blob: b75db14d6a9a5c43e0c680b144c3e466cb99243c [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 <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <sys/mman.h>
#include "types.h"
#include "mlog.h"
#include "inv_priv.h"
#include "getopt.h"
#include "timeutil.h"
#include "invutil.h"
char *g_programName;
char *g_programVersion;
char *inventory_path;
bool_t debug = BOOL_FALSE;
bool_t force = BOOL_FALSE;
bool_t wait_for_locks = BOOL_FALSE;
bool_t resize_screen = BOOL_FALSE;
bool_t redraw_screen = BOOL_FALSE;
bool_t redraw_options = BOOL_FALSE;
#ifndef HAVE_CURSES
int
invutil_interactive(char *path, char *mountpt, uuid_t *uuidp, time32_t timeSecs)
{
fprintf(stderr, "%s: libcurses support not compiled in, "
"interactive mode is unavailable.\n", g_programName);
exit(1);
}
#endif
int
main(int argc, char *argv[])
{
int c = 0;
bool_t check_option = BOOL_FALSE;
bool_t mntpnt_option = BOOL_FALSE;
bool_t uuid_option = BOOL_FALSE;
bool_t interactive_option = BOOL_FALSE;
bool_t session_option = BOOL_FALSE;
static char version[32];
char *mntPoint = NULL;
char *r_mf_label = NULL;
uuid_t uuid;
uuid_t session;
snprintf(version, sizeof(version), "version %s", VERSION);
g_programName = basename(argv[0]);
g_programVersion = version;
uuid_clear(uuid);
uuid_clear(session);
while((c = getopt( argc, argv, GETOPT_CMDSTRING)) != EOF) {
switch(c) {
case GETOPT_DEBUG:
debug = BOOL_TRUE;
break;
case GETOPT_INTERACTIVE:
if (force) {
fprintf( stderr, "%s: may not specify both -%c and -%c\n",
g_programName,
GETOPT_FORCE,
c );
usage();
}
if (session_option) {
fprintf( stderr, "%s: may not specify both -%c and -%c\n",
g_programName,
GETOPT_PRUNESESSION,
c );
usage();
}
interactive_option = BOOL_TRUE;
break;
case GETOPT_NONINTERACTIVE: /* obsoleted by -F */
if (interactive_option) {
fprintf( stderr, "%s: may not specify both -%c and -%c\n",
g_programName,
GETOPT_INTERACTIVE,
c );
usage();
}
force = BOOL_TRUE;
break;
case GETOPT_UUID:
if (check_option) {
fprintf( stderr, "%s: may not specify both -%c and -%c\n",
g_programName,
GETOPT_CHECKPRUNEFSTAB,
c );
usage();
}
if (mntpnt_option || session_option) {
fprintf( stderr, "%s: may not specify both -%c and -%c\n",
g_programName,
mntpnt_option ? GETOPT_PRUNEMNT : GETOPT_PRUNESESSION,
c );
usage();
}
uuid_option = BOOL_TRUE;
uuid_parse(optarg, uuid);
break;
case GETOPT_WAITFORLOCKS:
wait_for_locks = BOOL_TRUE;
break;
case GETOPT_CHECKPRUNEFSTAB:
if (mntpnt_option) {
fprintf( stderr, "%s: may not specify both -%c and -%c\n",
g_programName,
GETOPT_PRUNEMNT,
c );
usage();
}
if (uuid_option) {
fprintf( stderr, "%s: may not specify both -%c and -%c\n",
g_programName,
GETOPT_UUID,
c );
usage();
}
if (session_option) {
fprintf( stderr, "%s: may not specify both -%c and -%c\n",
g_programName,
GETOPT_PRUNESESSION,
c );
usage();
}
check_option = BOOL_TRUE;
break;
case GETOPT_FORCE:
if (interactive_option) {
fprintf( stderr, "%s: may not specify both -%c and -%c\n",
g_programName,
GETOPT_INTERACTIVE,
c );
usage();
}
force = BOOL_TRUE;
break;
case GETOPT_PRUNEMNT:
if (check_option) {
fprintf( stderr, "%s: may not specify both -%c and -%c\n",
g_programName,
GETOPT_CHECKPRUNEFSTAB,
c );
usage();
}
if (uuid_option || session_option) {
fprintf( stderr, "%s: may not specify both -%c and -%c\n",
g_programName,
uuid_option ? GETOPT_UUID : GETOPT_PRUNESESSION,
c );
usage();
}
mntpnt_option = BOOL_TRUE;
mntPoint = optarg;
break;
case GETOPT_PRUNEMEDIALABEL:
r_mf_label = optarg;
break;
case GETOPT_PRUNESESSION:
if (check_option) {
fprintf( stderr, "%s: may not specify both -%c and -%c\n",
g_programName,
GETOPT_CHECKPRUNEFSTAB,
c );
usage();
}
if (interactive_option) {
fprintf( stderr, "%s: may not specify both -%c and -%c\n",
g_programName,
GETOPT_INTERACTIVE,
c );
usage();
}
if (mntpnt_option || uuid_option) {
fprintf( stderr, "%s: may not specify both -%c and -%c\n",
g_programName,
mntpnt_option ? GETOPT_PRUNEMNT : GETOPT_UUID,
c );
usage();
}
session_option = BOOL_TRUE;
uuid_parse(optarg, session);
break;
default:
usage();
break;
}
}
if (r_mf_label != NULL && !(mntpnt_option || uuid_option)) {
fprintf( stderr, "%s: -%c requires either -%c or -%c\n",
g_programName,
GETOPT_PRUNEMEDIALABEL,
GETOPT_PRUNEMNT,
GETOPT_UUID );
usage();
}
/* date string only passed for -u and -M */
if (uuid_option || mntpnt_option) {
if (optind != (argc - 1)) {
fprintf(stderr, "%s: Date missing for -%c option\n",
g_programName,
uuid_option ? GETOPT_UUID : GETOPT_PRUNEMNT);
usage();
}
} else {
if (optind != argc) {
fprintf(stderr, "%s: Extra arguments specified\n",
g_programName);
usage();
}
}
/* sanity check the inventory database directory, setup global paths
*/
if (!inv_setup_base()) {
fprintf( stderr,
"%s: both /var/lib/xfsdump and /var/xfsdump exist - fatal\n",
g_programName );
exit(1);
}
inventory_path = INV_DIRPATH;
if (check_option) {
char *tempstr = "test";
time32_t temptime = 0;
CheckAndPruneFstab(inventory_path, BOOL_TRUE, tempstr, &uuid,
&session, temptime, NULL);
}
else if (session_option) {
CheckAndPruneFstab(
inventory_path, BOOL_FALSE , mntPoint, &uuid,
&session, (time32_t)0, r_mf_label);
}
else if (uuid_option || mntpnt_option) {
time32_t timeSecs = ParseDate(argv[optind]);
if (interactive_option) {
invutil_interactive(inventory_path, mntPoint, &uuid, timeSecs);
printf("\n");
}
else {
CheckAndPruneFstab(
inventory_path, BOOL_FALSE , mntPoint, &uuid,
&session, timeSecs, r_mf_label);
}
}
else if ( interactive_option ) {
invutil_interactive(inventory_path, mntPoint, &uuid, 0);
printf("\n");
}
else {
usage();
}
return 0;
}
/* get_mntpnt & mntpnt_equal are used to allow matching of mountpoints if
* no hostname is supplied
*/
static char *
get_mntpnt(char *txt)
{
char *p;
p = strchr(txt, ':');
if(p == NULL)
return txt;
return p+1;
}
int
mntpnt_equal(char *s1, char *s2)
{
if(strchr(s1, ':') == NULL || strchr(s2, ':') == NULL) {
s1 = get_mntpnt(s1);
s2 = get_mntpnt(s2);
}
return STREQL(s1, s2);
}
time32_t
ParseDate(char *strDate)
{
struct tm tm;
time_t date = 0;
time32_t date32;
char **fmt;
char *templateStr[] = {
"%m/%d/%Y %I:%M:%S %p",
"%m/%d/%Y %H:%M:%S",
"%m/%d/%Y %I:%M %p",
"%m/%d/%Y %H:%M",
"%m/%d/%Y %I %p",
"%m/%d/%Y %H",
"%m/%d/%Y",
"%m/%d/%y %I:%M:%S %p",
"%m/%d/%y %H:%M:%S",
"%m/%d/%y %I:%M %p",
"%m/%d/%y %H:%M",
"%m/%d/%y %I %p",
"%m/%d/%y %H",
"%m/%d/%y",
"%m/%d",
"%b %d, %Y %H:%M:%S %p",
"%b %d, %Y %I:%M:%S",
"%B %d, %Y %H:%M:%S %p",
"%B %d, %Y %I:%M:%S",
"%b %d, %Y %H:%M %p",
"%b %d, %Y %I:%M",
"%B %d, %Y %H:%M %p",
"%B %d, %Y %I:%M",
"%b %d, %Y %H %p",
"%b %d, %Y %I",
"%B %d, %Y %H %p",
"%B %d, %Y %I",
"%b %d, %Y",
"%B %d, %Y",
"%b %d",
"%B %d",
"%m%d%H",
"%m%d",
0};
for (fmt = &templateStr[0]; *fmt != NULL; fmt++) {
memset (&tm, 0, sizeof (struct tm)); /* ensure fields init'ed */
if (strptime(strDate, *fmt, &tm) != NULL)
break;
}
#ifdef INV_DEBUG
printf("INV_DEBUG: the date entered is %s\n", strDate);
printf("INV_DEBUG: the hour parsed from string is %d\n", tm.tm_hour);
#endif
if (*fmt == NULL || (date = mktime(&tm)) < 0) {
fprintf(stderr, "%s: bad date, \"%s\"\n", g_programName, strDate );
usage();
}
/* HACK to ensure tm_isdst is set BEFORE calling mktime(3) */
if (tm.tm_isdst) {
int dst = tm.tm_isdst;
memset (&tm, 0, sizeof (struct tm));
tm.tm_isdst = dst;
(void)strptime(strDate, *fmt, &tm);
tm.tm_isdst = dst;
date = mktime(&tm);
}
/* xfsdump inventory uses time32_t for portability.
* make sure the given date did not overflow... */
date32 = date;
if (date32 != date) {
fprintf(stderr, "%s: date out of range: \"%s\"\n", g_programName, strDate);
usage();
}
#ifdef INV_DEBUG
printf("INV_DEBUG: the date entered is %s\n", strDate);
printf("INV_DEBUG: the hour parsed from string is %d\n", tm.tm_hour);
printf("INV_DEBUG: the date entered in secs is %d\n", date32);
#endif /* INV_DEBUG */
return date32;
}
char *
GetNameOfStobj (char *inv_path, char *filename)
{
char *str;
char *name;
str = basename(filename);
name = (char *) malloc( strlen( inv_path ) + 1 + strlen( str ) + 1);
strcpy( name, inv_path );
strcat( name, "/" );
strcat( name, str );
return(name);
}
char *
GetNameOfInvIndex (char *inv_path, uuid_t uuid)
{
char str[UUID_STR_LEN + 1];
char *name;
uuid_unparse( uuid, str );
name = (char *) malloc( strlen( inv_path ) + 1 + strlen( str )
+ strlen( INV_INVINDEX_PREFIX ) + 1);
strcpy( name, inv_path );
strcat( name, "/" );
strcat( name, str );
strcat( name, INV_INVINDEX_PREFIX );
return(name);
}
char *
GetFstabFullPath(char *inv_path)
{
char *fstabname;
fstabname = (char *) malloc( strlen(inv_path) + 1 /* one for the "/" */
+ strlen("fstab") + 1 );
strcpy( fstabname, inv_path );
strcat( fstabname, "/" );
strcat( fstabname, "fstab" );
return(fstabname);
}
void
CheckAndPruneFstab(char *inv_path, bool_t checkonly, char *mountPt,
uuid_t *uuidp, uuid_t *sessionp, time32_t prunetime, char *r_mf_label)
{
char *fstabname;
char *mapaddr;
char *invname;
int fstabEntries;
int nEntries;
int fd;
int i;
int j;
bool_t removeflag;
invt_fstab_t *fstabentry;
invt_counter_t *counter,cnt;
if (mountPt == NULL && uuid_is_null(*uuidp) && uuid_is_null(*sessionp)) {
fprintf( stderr, "%s: mountpoint, uuid or session "
"must be specified\n", g_programName );
fprintf( stderr, "%s: abnormal termination\n", g_programName );
exit(1);
}
fstabname = GetFstabFullPath(inv_path);
fd = open_and_lock( fstabname,
FILE_WRITE,
wait_for_locks );
if (fd < 0) {
fprintf( stderr, "%s: abnormal termination\n", g_programName );
exit(1);
}
read_n_bytes(fd, &cnt, sizeof(invt_counter_t), fstabname);
nEntries = cnt.ic_curnum;
mapaddr = mmap_n_bytes(fd,
nEntries*sizeof(invt_fstab_t) + sizeof(invt_counter_t),
BOOL_FALSE,
fstabname);
counter = (invt_counter_t *)mapaddr;
fstabentry = (invt_fstab_t *)(mapaddr + sizeof(invt_counter_t));
printf("Processing file %s\n", fstabname);
/* check each entry in fstab for mount pt or uuid match */
for (i = 0; i < counter->ic_curnum; )
{
removeflag = BOOL_FALSE;
printf(" Found entry for %s\n" , fstabentry[i].ft_mountpt);
for (j = i +1 ; j < counter->ic_curnum ; j++ ) {
if (uuid_compare(fstabentry[i].ft_uuid, fstabentry[j].ft_uuid) == 0)
{
printf(" duplicate fstab entry\n");
removeflag = BOOL_TRUE;
break;
}
}
if (!removeflag)
{
bool_t IdxCheckOnly = BOOL_TRUE;
invname = GetNameOfInvIndex(inv_path, fstabentry[i].ft_uuid);
#ifdef INV_DEBUG
printf("INV_DEBUG: ft_mountpt = %s, mountPt = %s, r_mf_label = %s\n",
fstabentry[i].ft_mountpt, mountPt,
(r_mf_label ? r_mf_label : "(NULL)"));
#endif
if ( checkonly == BOOL_FALSE ) {
if(mountPt != NULL && strcmp(mountPt, fstabentry[i].ft_mountpt) == 0) {
printf(" Match on hostname and path\n");
IdxCheckOnly = BOOL_FALSE;
}
else if((!uuid_is_null(*uuidp))
&& (uuid_compare(*uuidp, fstabentry[i].ft_uuid) == 0)) {
printf(" Match on UUID only\n");
IdxCheckOnly = BOOL_FALSE;
}
else if(mountPt != NULL && mntpnt_equal(mountPt, fstabentry[i].ft_mountpt)) {
printf(" Match on directory name only: %s\n", mountPt);
IdxCheckOnly = BOOL_FALSE;
}
else if (!uuid_is_null(*sessionp)) {
// no session id to match against yet, defer deciding if this is
// a check-only run until we have a session
IdxCheckOnly = BOOL_FALSE;
}
}
if (CheckAndPruneInvIndexFile(
IdxCheckOnly, invname, sessionp,
prunetime, r_mf_label) == -1 ) {
removeflag = BOOL_TRUE;
}
free( invname );
}
if (removeflag == BOOL_TRUE)
{
printf(" removing fstab entry %s\n", fstabentry[i].ft_mountpt);
if ( counter->ic_curnum > 1 ) {
bcopy((void *)&fstabentry[i + 1],
(void *)&fstabentry[i],
(sizeof(invt_fstab_t) * (counter->ic_curnum - i - 1)));
}
counter->ic_curnum--;
}
else
i++; /* next entry if this entry not removed */
}
fstabEntries = counter->ic_curnum;
munmap( mapaddr,
(nEntries*sizeof(invt_fstab_t)) + sizeof(invt_counter_t));
if ((fstabEntries != 0) && (fstabEntries != nEntries)) {
if(debug) {
printf("ftruncate fstab from %d to %d (%ld bytes)\n",
nEntries,
fstabEntries,
(long) sizeof(invt_counter_t) + (sizeof(invt_fstab_t) * fstabEntries));
printf("ftruncate %s\n", fstabname);
}
ftruncate(fd,
sizeof(invt_counter_t) + (sizeof(invt_fstab_t) * fstabEntries));
}
close(fd);
if (fstabEntries == 0)
{
if(debug) {
printf("unlink fstab file %s\n", fstabname);
}
unlink( fstabname );
}
free( fstabname );
}
int
CheckAndPruneInvIndexFile( bool_t checkonly,
char *idxFileName,
uuid_t *sessionp,
time32_t prunetime,
char *r_mf_label)
{
char *temp;
int fd;
int i;
int validEntries;
int nEntries;
bool_t removeflag;
invt_entry_t *invIndexEntry;
invt_counter_t *counter;
invt_counter_t header;
printf(" processing index file \n"
" %s\n",idxFileName);
fd = open_and_lock( idxFileName,
FILE_WRITE,
wait_for_locks );
if (fd < 0) {
return -1;
}
read_n_bytes( fd, &header, sizeof(invt_counter_t), idxFileName);
nEntries = header.ic_curnum;
temp = mmap_n_bytes(fd,
nEntries*sizeof(invt_entry_t) + sizeof(invt_counter_t),
BOOL_FALSE, idxFileName);
counter = (invt_counter_t *)temp;
invIndexEntry = (invt_entry_t *)( temp + sizeof(invt_counter_t));
for (i=0; i < counter->ic_curnum; )
{
removeflag = BOOL_FALSE;
printf(" Checking access for\n"
" %s\n", invIndexEntry[i].ie_filename);
if (debug) {
printf(" Time:\tbegin %s",
ctime32(&(invIndexEntry[i].ie_timeperiod.tp_start)));
printf("\t\tend %s",
ctime32(&(invIndexEntry[i].ie_timeperiod.tp_end)));
}
if (( access( invIndexEntry[i].ie_filename, R_OK | W_OK ) == -1) &&
(errno == ENOENT))
{
printf(" Unable to access %s referred in %s\n",
invIndexEntry[i].ie_filename, idxFileName);
printf(" removing index entry \n");
removeflag = BOOL_TRUE;
}
if (CheckAndPruneStObjFile(checkonly, invIndexEntry[i].ie_filename,
sessionp, prunetime, r_mf_label) == -1) {
removeflag = BOOL_TRUE; /* The StObj is gone */
}
if (removeflag == BOOL_TRUE)
{
if ( counter->ic_curnum > 1 ) {
bcopy((void *)&invIndexEntry[i + 1],
(void *)&invIndexEntry[i],
(sizeof(invt_entry_t) * (counter->ic_curnum - i - 1)));
}
counter->ic_curnum--;
}
else
i++; /* next entry if this entry not removed */
}
validEntries = counter->ic_curnum;
munmap( temp, (nEntries*sizeof(invt_entry_t)) + sizeof(invt_counter_t) );
if ((validEntries != 0) && (validEntries != nEntries)) {
if(debug) {
printf("ftruncate idx from %d to %d (%ld bytes)\n",
nEntries,
validEntries,
(long) sizeof(invt_counter_t) + (validEntries * sizeof(invt_entry_t)) );
printf("- truncate %s\n", idxFileName);
}
ftruncate( fd,
sizeof(invt_counter_t) + (validEntries * sizeof(invt_entry_t)) );
}
if (debug) {
printf(" pruned %d entries from this index file, %d remaining\n",
(nEntries - validEntries),
validEntries);
}
close( fd );
if (validEntries == 0)
{
if(debug) {
printf("unlink idx file %s\n", idxFileName);
}
unlink( idxFileName );
return(-1);
}
return(0);
}
int
CheckAndPruneStObjFile( bool_t checkonly,
char *StObjFileName,
uuid_t *sessionp,
time32_t prunetime,
char *r_mf_label)
{
char response[GEN_STRLEN];
char *temp;
int fd;
int i;
int validEntries;
bool_t removeflag;
int prunedcount = 0;
int removedcount = 0;
bool_t session_match;
struct stat sb;
char str[UUID_STR_LEN + 1];
int sescount;
invt_seshdr_t *StObjhdr;
invt_session_t *StObjses;
invt_sescounter_t *counter;
invt_sescounter_t header;
fd = open_and_lock( StObjFileName,
FILE_WRITE,
wait_for_locks );
if (fd < 0) {
return -1;
}
read_n_bytes(fd, &header, sizeof(invt_sescounter_t), StObjFileName);
if (fstat(fd, &sb) < 0) {
fprintf(stderr, "Could not get stat info on %s\n", StObjFileName);
perror("fstat");
exit(1);
}
temp = mmap_n_bytes(fd, sb.st_size, BOOL_FALSE, StObjFileName);
counter = (invt_sescounter_t *)temp;
StObjhdr = (invt_seshdr_t *)( temp + sizeof(invt_sescounter_t));
StObjses = (invt_session_t *)(temp + StObjhdr->sh_sess_off);
sescount = 0;
for (i=0; i < counter->ic_curnum; ) {
removeflag = BOOL_FALSE;
if (StObjhdr->sh_pruned)
prunedcount++;
if (! StObjhdr->sh_pruned) {
printf(" Session %d: %s %s",
sescount++,
StObjses->s_mountpt,
ctime32(&StObjhdr->sh_time));
}
if (debug) {
/* Note that the DMF people use some of this debug
* output for their interface to the inventory.
* They care about the following fields:
* media label:
* interrupted:
* session label:
* level:
* Do not change these fields w/out talking to
* them first.
*/
int i;
int j;
invt_stream_t *StObjstrm;
invt_mediafile_t *StObjmed;
if (StObjhdr->sh_pruned)
printf(" Pruned Session: %s %s",
StObjses->s_mountpt,
ctime32(&StObjhdr->sh_time));
printf("\t\tdevice:\t\t%s\n", StObjses->s_devpath);
printf("\t\tsession label:\t\"%s\"\n", StObjses->s_label);
uuid_unparse( StObjses->s_sesid, str );
printf("\t\tsession id:\t%s\n", str);
printf("\t\tlevel:\t\t%d\n", StObjhdr->sh_level);
printf("\t\tstreams:\t%d\n", StObjses->s_cur_nstreams );
for ( i = 0; i < (int) StObjses->s_cur_nstreams; i++ ) {
printf( "\t\tstream %d:\n", i);
StObjstrm = (invt_stream_t *)(temp +
StObjhdr->sh_streams_off +
(i * sizeof(invt_stream_t)));
printf( "\t\t\tpathname:\t%s\n",
StObjstrm->st_cmdarg);
printf( "\t\t\tinode start:\t%llu\n",
(unsigned long long) StObjstrm->st_startino.ino);
printf( "\t\t\tinode end:\t%llu\n",
(unsigned long long) StObjstrm->st_endino.ino);
printf( "\t\t\tinterrupted:\t%s\n",
StObjstrm->st_interrupted ? "YES" : "NO" );
printf( "\t\t\tmedia files:\t%d\n",
StObjstrm->st_nmediafiles);
for ( j = 0; j < StObjstrm->st_nmediafiles; j++) {
StObjmed = (invt_mediafile_t *)(temp +
StObjstrm->st_firstmfile +
(j * sizeof(invt_mediafile_t)));
printf( "\t\t\tmfile file %d:\n", j);
printf( "\t\t\t\tmfile size:\t%lld\n",
(long long) StObjmed->mf_size);
printf( "\t\t\t\tmfile start:\t%llu\n",
(unsigned long long) StObjmed->mf_startino.ino);
printf( "\t\t\t\tmfile end:\t%llu\n",
(unsigned long long) StObjmed->mf_endino.ino);
printf( "\t\t\t\tmedia label:\t\"%s\"\n",
StObjmed->mf_label);
}
}
}
#ifdef INV_DEBUG
printf("INV_DEBUG: sh_time = %d, prunetime = %d\n",
StObjhdr->sh_time, prunetime);
printf("INV_DEBUG: checkonly = %d, sh_pruned = %d\n",
checkonly, StObjhdr->sh_pruned);
#endif
session_match = !uuid_compare(*sessionp, StObjses->s_sesid);
if (session_match) {
printf("\t\tMatch on session id\n");
}
if ((checkonly == BOOL_FALSE)
&& (! StObjhdr->sh_pruned)
&& ((StObjhdr->sh_time < prunetime) || session_match)
&& (uses_specified_mf_label(StObjhdr, StObjses, temp, r_mf_label))){
bool_t GotResponse = BOOL_FALSE;
uuid_unparse( StObjses->s_sesid, str );
if(force) {
printf("-------------------------------------------------\n");
printf("Pruning this matching entry:\n");
printf( "UUID\t\t:\t%s\nMOUNT POINT\t:\t%s\n"
"DEV PATH\t:\t%s\n"
"LABEL\t\t:\t%s\n"
"TIME OF DUMP\t:\t%s",
str, StObjses->s_mountpt, StObjses->s_devpath,
StObjses->s_label, ctime32(&StObjhdr->sh_time));
removeflag = BOOL_TRUE;
}
else {
printf("-------------------------------------------------\n");
printf("An entry matching the mount point/time is :\n");
printf("UUID\t\t:\t%s\nMOUNT POINT\t:\t%s\n"
"DEV PATH\t:\t%s\nTIME OF DUMP\t:\t%s",
str, StObjses->s_mountpt, StObjses->s_devpath,
ctime32(&StObjhdr->sh_time));
while ( GotResponse == BOOL_FALSE )
{
char *chp;
printf("\nDo you want to prune this entry: [y/n] ");
fgets( response, GEN_STRLEN, stdin );
chp = strchr( response, '\n');
if (chp)
*chp = '\0';
if (strcasecmp( response, "Y" ) == 0) {
removeflag = BOOL_TRUE;
GotResponse = BOOL_TRUE;
}
else if (strcasecmp( response, "N" ) == 0) {
GotResponse = BOOL_TRUE;
}
}
}
printf("-------------------------------------------------\n\n");
}
if (removeflag == BOOL_TRUE) {
/* Mark this entry as pruned */
StObjhdr->sh_pruned = 1;
removedcount++;
}
i++;
StObjhdr = (invt_seshdr_t *)( temp + sizeof(invt_sescounter_t) +
(i * sizeof(invt_seshdr_t)) );
StObjses = (invt_session_t *)(temp + StObjhdr->sh_sess_off);
}
validEntries = counter->ic_curnum - prunedcount - removedcount;
munmap( temp, sb.st_size);
if (debug && removedcount)
printf(" pruned %d entries from this StObj file,"
" %d remaining\n", removedcount, validEntries);
close( fd );
if (validEntries == 0)
{
if (debug)
printf("Removing: %s\n", StObjFileName);
unlink( StObjFileName );
return(-1);
}
return(0);
}
/* If any of the media objects have a label which matches the one supplied
* by the user, or if none is supplied, or if the session has no media
* objects, say the session is prunable.
* Otherwise, say it should be bypassed.
*/
int
uses_specified_mf_label(
invt_seshdr_t *StObjhdr,
invt_session_t *StObjses,
char *temp,
char *r_mf_label)
{
int s, m;
int num_media_objects = 0;
invt_stream_t *StObjstrm;
invt_mediafile_t *StObjmed;
if (!r_mf_label) {
return 1; /* prune */
}
for ( s = 0; s < (int) StObjses->s_cur_nstreams; s++ ) {
StObjstrm = (invt_stream_t *)
(temp + StObjhdr->sh_streams_off + (s * sizeof(invt_stream_t)));
for ( m = 0; m < StObjstrm->st_nmediafiles; m++, num_media_objects++) {
StObjmed = (invt_mediafile_t *)
(temp + StObjstrm->st_firstmfile + (m * sizeof(invt_mediafile_t)));
if (!strncmp(StObjmed->mf_label, r_mf_label,
sizeof(StObjmed->mf_label))) {
printf("\t\tSpecified media label \"%s\" found - "
"pruning session \"%s\"\n",
r_mf_label, StObjses->s_label);
return 1; /* prune */
}
}
}
if (!num_media_objects)
return 1; /* prune */
return 0; /* don't prune */
}
/* copied from inv_api.c */
char *
inv_DEBUG_lock_str( int c )
{
#ifdef USE_LOCKF
static char *lockstr[] = {
"F_ULOCK",
"F_LOCK",
"F_TLOCK",
"F_TEST",
};
if (c < 0 || c >= (sizeof(lockstr) / sizeof(char *))) {
return "unknown lockf";
}
return lockstr[c];
#else
#ifdef USE_FLOCK
int i;
static struct {
int cmd;
char *str;
} lockinfo[] = {
{ LOCK_UN, "LOCK_UN" },
{ LOCK_SH, "LOCK_SH" },
{ LOCK_EX, "LOCK_EX" },
{ LOCK_NB, "LOCK_NB" },
{ NULL, NULL }
};
for (i = 0; lockinfo[i].str; i++) {
if(lockinfo[i].cmd == c) {
return lockinfo[i].str;
}
}
return "unknown flock";
#else
return "unknown lock mechanism";
#endif /* USE_FLOCK */
#endif /* USE_LOCKF */
}
/*
* returns file descriptor >= 0 if open and lock successful.
*
* returns LOCK_BUSY if lock busy.
* returns SYSCALL_FAILED for other failures.
*/
int
open_and_lock(char * path, Open_t open_type, uint lock_wait_flag)
{
int fd;
int rc;
int open_mode, lock_mode;
switch (open_type) {
case FILE_READ:
open_mode = O_RDONLY;
lock_mode = 0;
break;
case FILE_WRITE:
open_mode = O_RDWR;
lock_mode = LOCK_EX;
break;
case FILE_UNSAFE:
open_mode = O_RDWR;
lock_mode = 0;
break;
case DIRECTORY_READ:
open_mode = O_RDONLY;
lock_mode = 0;
break;
case DIRECTORY_WRITE:
open_mode = O_RDWR;
lock_mode = LOCK_EX;
break;
case DIRECTORY_UNSAFE:
open_mode = O_RDONLY;
lock_mode = 0;
break;
default:
abort();
}
fd = open(path, open_mode);
if (fd < 0) {
fprintf( stderr, "%s: open of %s failed.\n",
g_programName, path);
perror( "open" );
return SYSCALL_FAILED;
}
if (lock_mode != 0) {
int local_mode = lock_mode;
if (lock_wait_flag == 0)
local_mode &= ~LOCK_NB;
rc = INVLOCK(fd, local_mode);
if (rc < 0) {
if (errno == EACCES || errno == EWOULDBLOCK) {
fprintf(stderr,"%s: Unable to get lock on "
"file %s\n",
g_programName,
path);
fprintf(stderr,"Conflict with other instances of"
" xfsinvutil, xfsdump or xfsrestore.\n");
rc = LOCK_BUSY;
} else {
fprintf(stderr,"%s: lock on %s (fd == %d) failed.\n",
g_programName,
path,
fd);
perror("file lock");
rc = SYSCALL_FAILED;
}
close(fd);
return rc;
}
}
if (debug) {
char *lstr;
switch(lock_mode) {
case LOCK_EX: lstr = inv_DEBUG_lock_str(lock_mode); break;
default: lstr = "NO_LOCK";
}
fprintf(stderr, "open_and_lock: DEBUG open_mode %s"
" lock_mode %s file %s\n",
open_mode == O_RDONLY ? "O_RDONLY" : "O_RDWR", lstr, path);
}
return fd;
}
void
read_n_bytes(int fd, void * buf, size_t count, char *path)
{
int rc;
rc = read(fd, buf, count);
if (rc < 0) {
fprintf(stderr, "%s: read of %ld bytes on %s failed.\n",
g_programName, (long) count, path);
perror(path);
exit (2);
} else if (rc != count) {
fprintf(stderr, "%s: read of %ld bytes on %s failed.\n",
g_programName, (long) count, path);
fprintf(stderr, "Tried to read %ld bytes, got %d.\n",
(long) count, rc);
exit (2);
}
}
void
write_n_bytes(int fd, void * buf, size_t count, char *path)
{
int rc;
rc = write(fd, buf, count);
if (rc < 0) {
fprintf(stderr, "%s: write of %ld bytes on %s failed.\n",
g_programName, (long) count, path);
perror(path);
exit (2);
} else if (rc != count) {
fprintf(stderr, "%s: write of %ld bytes on %s failed.\n",
g_programName, (long) count, path);
fprintf(stderr, "Tried to write %ld bytes, wrote %d.\n",
(long) count, rc);
exit (2);
}
}
void *
mmap_n_bytes(int fd, size_t count, bool_t checkonly, char *path)
{
void * temp;
lseek( fd, 0, SEEK_SET );
temp = mmap( NULL, count,
(checkonly == BOOL_TRUE) ? PROT_READ : PROT_READ|PROT_WRITE,
MAP_SHARED, fd, 0 );
if (temp == (void *)-1) {
fprintf( stderr, "%s: error in mmap of %ld bytes for file %s\n",
g_programName, (long) count, path);
perror("mmap");
fprintf( stderr, "%s: abnormal termination\n", g_programName );
exit(1);
}
return temp;
}
void
usage (void)
{
int pfxsz;
fprintf(stderr, "%s: %s\n", g_programName, g_programVersion);
pfxsz = fprintf(stderr, "Usage: \n");
fprintf(stderr, "%*s%s [-F|-i] [-m media_label] -M mount_point mm/dd/yyyy\n",
pfxsz, "", g_programName);
fprintf(stderr, "%*s%s [-F|-i] [-m media_label] -u UUID mm/dd/yyyy\n",
pfxsz, "", g_programName);
fprintf(stderr, "%*s%s [-F] -s SESSION_ID\n",
pfxsz, "", g_programName);
fprintf(stderr, "%*s%s -i\n", pfxsz, "", g_programName);
fprintf(stderr, "%*s%s -C\n", pfxsz, "", g_programName);
exit(1);
}