blob: b9851c3308ac3935857ad4e7f57cbcdfa074a8fb [file] [log] [blame]
/*
* Copyright (c) 2000-2001 Silicon Graphics, Inc.
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it would be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <xfs/xfs.h>
#include <xfs/jdm.h>
#include <time.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/dir.h>
#include "types.h"
#include "mlog.h"
#include "inv_priv.h"
/*----------------------------------------------------------------------*/
/* init_idb */
/* */
/* Returns -1 if we are done with initialization, the fd if not. */
/* The idb_token indicates whether there was an error or not, if the */
/* return value is -1. */
/*----------------------------------------------------------------------*/
int
init_idb( void *pred, inv_predicate_t bywhat, inv_oflag_t forwhat,
inv_idbtoken_t *tok )
{
char fname[ INV_STRLEN ];
char uuname[ INV_STRLEN ];
int fd;
*tok = INV_TOKEN_NULL;
/* make sure INV_DIRPATH exists, and is writable */
if ( make_invdirectory( forwhat ) < 0 )
return I_DONE;
/* come up with the unique file suffix that refers to this
filesystem */
if ( fstab_get_fname( pred, uuname, bywhat, forwhat ) < 0 ) {
return I_DONE;
}
( void )strcpy( fname, uuname );
strcat ( fname, INV_INVINDEX_PREFIX );
/* first check if the inv_index file exists: if not create it */
if ( ( fd = open( fname, INV_OFLAG(forwhat) ) ) == -1 ) {
if (errno != ENOENT) {
INV_PERROR ( fname );
} else if (forwhat == INV_SEARCH_N_MOD) {
*tok = idx_create( fname, forwhat );
} else {
/* this happens when the inv is empty and the user
wants to do a search. this is legal - not an error */
return I_EMPTYINV;
}
return I_DONE; /* we are done whether token's NULL or not */
}
/* we've got to do more housekeeping stuff. so signal that */
return fd;
}
inv_idbtoken_t
get_token( int invfd, int stobjfd )
{
invt_desc_entry_t *desc;
desc = (invt_desc_entry_t *) malloc
( sizeof( invt_desc_entry_t ) );
desc->d_invindex_fd = invfd;
desc->d_stobj_fd = stobjfd;
desc->d_update_flag = 0;
desc->d_invindex_off = -1;
return (inv_idbtoken_t) desc; /* yukky, but ok for the time being */
}
void
destroy_token( inv_idbtoken_t tok )
{
free ( (invt_desc_entry_t *) tok );
}
inv_sestoken_t
get_sesstoken( inv_idbtoken_t tok )
{
inv_sestoken_t stok;
stok = (inv_sestoken_t) malloc( sizeof( invt_sesdesc_entry_t ) );
stok->sd_invtok = tok;
stok->sd_session_off = stok->sd_sesshdr_off = -1;
stok->sd_sesstime = (time32_t) 0;
return stok;
}
/*---------------------------------------------------------------------------*/
/* */
/* */
/* */
/*---------------------------------------------------------------------------*/
bool_t
invmgr_query_all_sessions (
void *inarg,
void **outarg,
search_callback_t func)
{
invt_counter_t *cnt;
invt_fstab_t *arr;
int numfs, i, fd, invfd;
char fname[INV_STRLEN];
int result;
inv_oflag_t forwhat = INV_SEARCH_ONLY;
void *objectfound;
/* if on return, this is still null, the search failed */
*outarg = NULL;
ASSERT(inarg);
fd = fstab_getall( &arr, &cnt, &numfs, forwhat );
/* special case missing file: ok, outarg says zero */
if ( fd < 0 && errno == ENOENT ) {
return BOOL_TRUE;
}
if ( fd < 0 || numfs <= 0 ) {
mlog( MLOG_NORMAL | MLOG_INV, _("INV: Error in fstab\n") );
return BOOL_FALSE;
}
close( fd );
for ( i = 0; i < numfs; i++) {
if ( fstab_get_fname( &arr[i].ft_uuid, fname,
(inv_predicate_t)INV_BY_UUID,
forwhat) < 0 ) {
mlog( MLOG_NORMAL | MLOG_INV, _(
"INV: Cant get inv-name for uuid\n")
);
return BOOL_FALSE;
}
strcat( fname, INV_INVINDEX_PREFIX );
invfd = open( fname, INV_OFLAG(forwhat) );
if ( invfd < 0 ) {
mlog( MLOG_NORMAL | MLOG_INV, _(
"INV: Open failed on %s\n"),
fname
);
return BOOL_FALSE;
}
result = search_invt( invfd, inarg, &objectfound, func );
close(invfd);
/* if error return BOOL_FALSE */
if (result < 0) {
return BOOL_FALSE;
} else if ((result == 1) && *outarg) {
/* multiple entries found, more info needed */
*outarg = NULL;
return BOOL_TRUE;
} else if (result == 1) {
*outarg = objectfound;
}
}
/* return val indicates if there was an error or not. *buf
says whether the search was successful */
return BOOL_TRUE;
}
/*----------------------------------------------------------------------*/
/* search_invt */
/* */
/* Used by the toplevel (inv layer ) to do common searches on the inven-*/
/* tory. Caller supplies a callback routine that performs the real */
/* comparison/check. */
/*----------------------------------------------------------------------*/
intgen_t
search_invt(
int invfd,
void *arg,
void **buf,
search_callback_t do_chkcriteria )
{
int fd, i;
invt_entry_t *iarr = NULL;
invt_counter_t *icnt = NULL;
int nindices;
if (invfd == I_EMPTYINV)
return -1;
/* set the caller's buffer pointer to NULL initially.
* if no session found, the caller will expect to see
* NULL.
*/
*( char ** )buf = NULL;
if ( ( nindices = GET_ALLHDRS_N_CNTS( invfd, (void **)&iarr,
(void **)&icnt,
sizeof( invt_entry_t ),
sizeof( invt_counter_t ))
) <= 0 ) {
return -1;
}
free( icnt );
/* we need to get all the invindex headers and seshdrs in reverse
order */
for (i = nindices - 1; i >= 0; i--) {
int nsess;
invt_sescounter_t *scnt = NULL;
invt_seshdr_t *harr = NULL;
bool_t found;
fd = open (iarr[i].ie_filename, O_RDONLY );
if (fd < 0) {
INV_PERROR( iarr[i].ie_filename );
continue;
}
INVLOCK( fd, LOCK_SH );
/* Now see if we can find the session we're looking for */
if (( nsess = GET_ALLHDRS_N_CNTS_NOLOCK( fd, (void **)&harr,
(void **)&scnt,
sizeof( invt_seshdr_t ),
sizeof( invt_sescounter_t ))
) < 0 ) {
INV_PERROR( iarr[i].ie_filename );
INVLOCK( fd, LOCK_UN );
close( fd );
continue;
}
free ( scnt );
while ( nsess ) {
/* fd is kept locked until we return from the
callback routine */
/* Check to see if this session has been pruned
* by xfsinvutil before checking it.
*/
if ( harr[nsess - 1].sh_pruned ) {
--nsess;
continue;
}
found = (* do_chkcriteria ) ( fd, &harr[ --nsess ],
arg, buf );
if (! found ) continue;
/* we found what we need; just return */
INVLOCK( fd, LOCK_UN );
close( fd );
free( harr );
return found; /* == -1 or 1 */
}
INVLOCK( fd, LOCK_UN );
close( fd );
}
return 0;
}
/*---------------------------------------------------------------------------*/
/* */
/* */
/* */
/*---------------------------------------------------------------------------*/
intgen_t
invmgr_inv_print(
int invfd,
invt_pr_ctx_t *prctx)
{
int fd, i;
invt_entry_t *iarr = NULL;
invt_counter_t *icnt = NULL;
int nindices;
u_int ref = 0;
if (invfd == I_EMPTYINV)
return 0;
if ( ( nindices = GET_ALLHDRS_N_CNTS( invfd, (void **)&iarr,
(void **)&icnt,
sizeof( invt_entry_t ),
sizeof( invt_counter_t ))
) <= 0 ) {
return -1;
}
free( icnt );
if (prctx->invidx) {
idx_DEBUG_printinvindices( iarr, (u_int) nindices );
free(iarr);
return (0);
}
for ( i = 0; i < nindices; i++ ) {
int nsess;
invt_sescounter_t *scnt = NULL;
invt_seshdr_t *harr = NULL;
int s;
fd = open (iarr[i].ie_filename, O_RDONLY );
if (fd < 0) {
INV_PERROR( iarr[i].ie_filename );
continue;
}
INVLOCK( fd, LOCK_SH );
/* Now see if we can find the session we're looking for */
if (( nsess = GET_ALLHDRS_N_CNTS_NOLOCK( fd, (void **)&harr,
(void **)&scnt,
sizeof( invt_seshdr_t ),
sizeof( invt_sescounter_t ))
) < 0 ) {
INV_PERROR( iarr[i].ie_filename );
INVLOCK( fd, LOCK_UN );
close( fd );
continue;
}
free ( scnt );
for( s = 0; s < nsess; s++ ) {
/* fd is kept locked until we return from the
callback routine */
/* Check to see if this session has been pruned
* by xfsinvutil before returning it.
*/
if ( harr[s].sh_pruned ) {
continue;
}
(void)DEBUG_displayallsessions( fd, &harr[ s ],
ref++, prctx);
}
INVLOCK( fd, LOCK_UN );
close( fd );
}
free (iarr);
return 0;
}
/*---------------------------------------------------------------------------*/
/* */
/* */
/* */
/*---------------------------------------------------------------------------*/
intgen_t
invmgr_inv_check(
int invfd)
{
int fd, i;
invt_entry_t *iarr = NULL;
invt_counter_t *icnt = NULL;
int nindices;
if (invfd == I_EMPTYINV)
return 0;
if ( ( nindices = GET_ALLHDRS_N_CNTS( invfd, (void **)&iarr,
(void **)&icnt,
sizeof( invt_entry_t ),
sizeof( invt_counter_t ))
) <= 0 ) {
return -1;
}
free( icnt );
for ( i = 0; i < nindices; i++ ) {
int nsess;
invt_sescounter_t *scnt = NULL;
invt_seshdr_t *harr = NULL;
int s;
fd = open (iarr[i].ie_filename, O_RDONLY );
if (fd < 0) {
INV_PERROR( iarr[i].ie_filename );
continue;
}
INVLOCK( fd, LOCK_SH );
/* Now see if we can find the session we're looking for */
if (( nsess = GET_ALLHDRS_N_CNTS_NOLOCK( fd, (void **)&harr,
(void **)&scnt,
sizeof( invt_seshdr_t ),
sizeof( invt_sescounter_t ))
) < 0 ) {
INV_PERROR( iarr[i].ie_filename );
INVLOCK( fd, LOCK_UN );
close( fd );
continue;
}
free ( scnt );
if ((iarr[i].ie_timeperiod.tp_start != harr[0].sh_time) ||
(iarr[i].ie_timeperiod.tp_end != harr[nsess-1].sh_time)) {
printf(_("INV: Check %d failed.\n"), i+1);
printf(_("invidx (%d)\t%d - %d\n"),
i+1,
iarr[i].ie_timeperiod.tp_start,
iarr[i].ie_timeperiod.tp_end);
for( s = 0; s < nsess; s++ ) {
printf(_("tm (%d)\t%d\n"), s, harr[s].sh_time);
}
}
else {
printf(_("INV: Check %d out of %d succeeded\n"),
i+1, nindices);
}
INVLOCK( fd, LOCK_UN );
close( fd );
}
return 0;
}
/*----------------------------------------------------------------------*/
/* */
/* */
/* */
/*----------------------------------------------------------------------*/
/* ARGSUSED */
bool_t
tm_level_lessthan( int fd, invt_seshdr_t *hdr, void *arg,
void **tm )
{
u_char level = *(u_char *)arg;
*tm = NULL;
if ( IS_PARTIAL_SESSION( hdr ) )
return 0;
if (hdr->sh_level < level ) {
#ifdef INVT_DEBUG
mlog( MLOG_DEBUG | MLOG_INV, "$ found level %d < %d\n", hdr->sh_level,
level );
#endif
*tm = calloc( 1, sizeof( time32_t ) );
memcpy( *tm, &hdr->sh_time, sizeof( time32_t ) );
return 1;
}
return 0;
}
/*----------------------------------------------------------------------*/
/* */
/* */
/* */
/*----------------------------------------------------------------------*/
bool_t
lastsess_level_lessthan( int fd, invt_seshdr_t *hdr, void *arg,
void **buf )
{
u_char level = *(u_char *)arg;
*buf = NULL;
if ( IS_PARTIAL_SESSION( hdr ) )
return 0;
if (hdr->sh_level < level ) {
#ifdef INVT_DEBUG
mlog( MLOG_DEBUG | MLOG_INV, "$ found (ses) level %d < %d \n",
hdr->sh_level, level );
#endif
return stobj_make_invsess( fd, (inv_session_t **) buf, hdr );
}
return 0;
}
/*----------------------------------------------------------------------*/
/* */
/* */
/* */
/*----------------------------------------------------------------------*/
bool_t
lastsess_level_equalto( int fd, invt_seshdr_t *hdr,
void *arg, void **buf )
{
u_char level = *(u_char *)arg;
*buf = NULL;
if ( IS_PARTIAL_SESSION( hdr ) )
return 0;
if (hdr->sh_level == level ) {
#ifdef INVT_DEBUG
mlog( MLOG_DEBUG | MLOG_INV, "$ found (ses) level %d == %d \n", hdr->sh_level,
level );
#endif
return stobj_make_invsess( fd, (inv_session_t **) buf, hdr );
}
return 0;
}
/*----------------------------------------------------------------------*/
/* insert_session */
/* */
/* insert a session that may or may not be already in the inventory. */
/* this is used in reconstructing the database. */
/*----------------------------------------------------------------------*/
bool_t
insert_session( invt_sessinfo_t *s)
{
inv_idbtoken_t tok = INV_TOKEN_NULL;
int invfd, stobjfd = -1;
invt_idxinfo_t idx;
bool_t ret = BOOL_FALSE;
inv_oflag_t forwhat = INV_SEARCH_N_MOD;
/* initialize the inventory */
if ( ( invfd = init_idb ( (void *) s->ses->s_fsid,
(inv_predicate_t) INV_BY_UUID,
forwhat,
&tok ) ) < 0 ) {
if ( tok == INV_TOKEN_NULL ) {
#ifdef INVT_DEBUG
mlog( MLOG_DEBUG | MLOG_INV, "INV: insert_session: init_db "
"failed\n" );
#endif
return BOOL_FALSE;
}
invfd = tok->d_invindex_fd;
close( tok->d_stobj_fd );
destroy_token( tok );
}
/* at this point we know that invindex has at least one entry
First we need to find out if this session is in the inventory
already. To find the storage object that can possibly
contain this session, it suffices to sequentially search the
inventory indices of this filesystem for the particular invt-entry
*/
INVLOCK( invfd, LOCK_EX );
idx.invfd = invfd;
stobjfd = idx_find_stobj( &idx, s->seshdr->sh_time );
if (stobjfd < 0) {
INVLOCK( invfd, LOCK_UN );
free( idx.icnt );
free( idx.iarr );
return BOOL_FALSE;
}
/* Now put the session in the storage-object */
INVLOCK( stobjfd, LOCK_EX );
if ( ( stobj_insert_session( &idx, stobjfd, s ) < 0 ) ||
( idx_recons_time ( s->seshdr->sh_time, &idx ) < 0 ) )
ret = BOOL_TRUE;
INVLOCK( stobjfd, LOCK_UN );
INVLOCK( invfd, LOCK_UN );
free( idx.icnt );
free( idx.iarr );
if (ret) return BOOL_FALSE;
/* make sure the fstab is uptodate too */
if ( fstab_put_entry( &s->ses->s_fsid, s->ses->s_mountpt, s->ses->s_devpath,
forwhat ) < 0 )
return BOOL_FALSE;
/* and we are done */
return BOOL_TRUE;
}
/*----------------------------------------------------------------------*/
/* */
/* */
/* */
/*----------------------------------------------------------------------*/
intgen_t
make_invdirectory( inv_oflag_t forwhat )
{
struct stat64 st;
char path[PATH_MAX];
char *p;
p = strcpy( path, INV_DIRPATH );
if ( stat64( path, &st ) == 0 )
return 1;
if ( forwhat == INV_SEARCH_ONLY || errno != ENOENT )
return -1;
do {
p++;
if ( *p == '/' ) {
*p = '\0';
if ( mkdir( path, (mode_t)0755 ) < 0 ) {
if ( errno != EEXIST ) {
INV_PERROR( path );
return -1;
}
}
*p = '/';
}
} while ( *p );
if ( mkdir( path, (mode_t)0755 ) < 0 ) {
if ( errno != EEXIST ) {
INV_PERROR( path );
return -1;
}
}
mlog( MLOG_VERBOSE | MLOG_INV, _("%s created\n"), path );
return 1;
}
#ifdef NOTDEF
bool_t
invmgr_lockinit( void )
{
if ( invlock_fd == -1 ) {
if (( invlock_fd = open( INV_LOCKFILE,
O_RDONLY | O_CREAT, S_IRUSR|S_IWUSR )) < 0 ) {
INV_PERROR( INV_LOCKFILE );
return BOOL_FALSE;
}
fchmod ( invlock_fd, INV_PERMS );
}
return BOOL_TRUE;
}
bool_t
invmgr_trylock( invt_mode_t mode )
{
int md;
ASSERT( invlock_fd >= 0 );
md = (mode == INVT_RECONSTRUCT) ? LOCK_EX: LOCK_SH;
if (INVLOCK( invlock_fd, md | LOCK_NB ) < 0)
return BOOL_FALSE;
return BOOL_TRUE;
}
void
invmgr_unlock( void )
{
ASSERT( invlock_fd >= 0 );
INVLOCK( invlock_fd, LOCK_UN );
}
#endif