#endif
#endif
#else /* AFS_VFSINCL_ENV */
-#ifdef AFS_OSF_ENV
-#include <ufs/inode.h>
-#else /* AFS_OSF_ENV */
#if !defined(AFS_LINUX20_ENV) && !defined(AFS_XBSD_ENV) && !defined(AFS_DARWIN_ENV)
#include <sys/inode.h>
#endif
-#endif
#endif /* AFS_VFSINCL_ENV */
#endif /* AFS_SGI_ENV */
#ifdef AFS_AIX_ENV
#include <pthread.h>
#endif
-#ifdef AFS_OSF_ENV
-extern void *calloc();
-#endif
-static char *TimeStamp(time_t clock, int precision);
+#define SALV_BUFFER_SIZE 1024
+
+static char *TimeStamp(char *buffer, size_t size, time_t clock, int precision);
int debug; /* -d flag */
int PartsPerDisk = 8; /* Salvage up to 8 partitions on same disk sequentially */
int forceR = 0; /* -b flag */
int ShowLog = 0; /* -showlog flag */
+char *ShowLogFilename = NULL; /* log file name for -showlog */
int ShowSuid = 0; /* -showsuid flag */
int ShowMounts = 0; /* -showmounts flag */
int orphans = ORPH_IGNORE; /* -orphans option */
int Showmode = 0;
-
-
-#ifndef AFS_NT40_ENV
-int useSyslog = 0; /* -syslog flag */
-int useSyslogFacility = LOG_DAEMON; /* -syslogfacility option */
-#endif
+int ClientMode = 0; /* running as salvager server client */
#ifdef AFS_NT40_ENV
int canfork = 0;
int ForceSalvage; /* If salvage should occur despite the DONT_SALVAGE flag
* in the volume header */
-FILE *logFile = 0; /* one of {/usr/afs/logs,/vice/file}/SalvageLog */
-
#define ROOTINODE 2 /* Root inode of a 4.2 Unix file system
* partition */
/**
/* Forward declarations */
+static void QuietExit(int) AFS_NORETURN;
+static void SalvageShowLog(void);
static int IsVnodeOrphaned(struct SalvInfo *salvinfo, VnodeId vnode);
static int AskVolumeSummary(struct SalvInfo *salvinfo,
VolumeId singleVolumeNumber);
struct job *thisjob = 0;
static int numjobs = 0;
static int jobcount = 0;
- char buf[1024];
int wstatus;
struct job *oldjob;
int startjob;
FILE *passLog;
- char logFileName[256];
int i, j, pid;
if (partP) {
numjobs++;
} else {
int fd;
+ char *filename;
+ struct logOptions logopts;
+
+ memset(&logopts, 0, sizeof(logopts));
+ logopts.lopt_dest = logDest_file;
- ShowLog = 0;
for (fd = 0; fd < 16; fd++)
close(fd);
open(OS_DIRSEP, 0);
dup2(0, 1);
dup2(0, 2);
-#ifndef AFS_NT40_ENV
- if (useSyslog) {
- openlog("salvager", LOG_PID, useSyslogFacility);
- } else
-#endif
- {
- snprintf(logFileName, sizeof logFileName, "%s.%d",
+
+ ShowLog = 0; /* Child processes do not display. */
+ if (asprintf(&filename, "%s.%d",
AFSDIR_SERVER_SLVGLOG_FILEPATH,
- jobs[startjob]->jobnumb);
- logFile = afs_fopen(logFileName, "w");
+ jobs[startjob]->jobnumb) >= 0) {
+ logopts.lopt_filename = filename;
+ OpenLog(&logopts);
+ free(filename);
}
- if (!logFile)
- logFile = stdout;
SalvageFileSys1(jobs[startjob]->partP, 0);
Exit(0);
}
} /* while ( thisjob || (!partP && numjobs > 0) ) */
- /* If waited for all jobs to complete, now collect log files and return */
-#ifndef AFS_NT40_ENV
- if (!useSyslog) /* if syslogging - no need to collect */
-#endif
+ /*
+ * If waited for all jobs to complete, now collect log files and return.
+ * No files can be collected when logging to the system log (syslog).
+ */
+ if (GetLogDest() == logDest_file) {
if (!partP) {
- for (i = 0; i < jobcount; i++) {
- snprintf(logFileName, sizeof logFileName, "%s.%d",
- AFSDIR_SERVER_SLVGLOG_FILEPATH, i);
- if ((passLog = afs_fopen(logFileName, "r"))) {
- while (fgets(buf, sizeof(buf), passLog)) {
- fputs(buf, logFile);
+ char *buf = calloc(1, SALV_BUFFER_SIZE);
+ char *logFileName;
+
+ if (buf == NULL) {
+ Log("out of memory");
+ } else {
+ for (i = 0; i < jobcount; i++) {
+ if (asprintf(&logFileName, "%s.%d",
+ AFSDIR_SERVER_SLVGLOG_FILEPATH, i) < 0) {
+ Log("out of memory");
+ break;
+ }
+ if ((passLog = afs_fopen(logFileName, "r"))) {
+ while (fgets(buf, SALV_BUFFER_SIZE, passLog)) {
+ WriteLogBuffer(buf, strlen(buf));
+ }
+ fclose(passLog);
}
- fclose(passLog);
+ (void)unlink(logFileName);
+ free(logFileName);
}
- (void)unlink(logFileName);
+ free(buf);
}
- fflush(logFile);
}
+ }
return;
}
if (!canfork || debug || Fork() == 0) {
SalvageFileSys1(partP, singleVolumeNumber);
if (canfork && !debug) {
- ShowLog = 0;
- Exit(0);
+ QuietExit(0);
}
} else
Wait("SalvageFileSys");
SalvageFileSys1(struct DiskPartition64 *partP, VolumeId singleVolumeNumber)
{
char *name, *tdir;
- char inodeListPath[256];
+ char *inodeListPath = NULL;
FD_t inodeFile = INVALID_FD;
static char tmpDevName[100];
static char wpath[100];
tdir = (tmpdir ? tmpdir : salvinfo->fileSysPath);
#ifdef AFS_NT40_ENV
(void)_putenv("TMP="); /* If "TMP" is set, then that overrides tdir. */
- (void)strncpy(inodeListPath, _tempnam(tdir, "salvage.inodes."), 255);
+ inodeListPath = strdup(_tempnam(tdir, "salvage.inodes."));
+ if (inodeListPath == NULL) {
+ Abort("Error allocating memory for inodeListPath\n");
+ }
#else
- snprintf(inodeListPath, 255, "%s" OS_DIRSEP "salvage.inodes.%s.%d", tdir, name,
+ code = asprintf(&inodeListPath, "%s" OS_DIRSEP "salvage.inodes.%s.%d", tdir, name,
getpid());
+ if (code == -1) {
+ Abort("Error allocating memory for inodeListPath\n");
+ }
#endif
inodeFile = OS_OPEN(inodeListPath, O_RDWR|O_TRUNC|O_CREAT, 0666);
if (GetInodeSummary(salvinfo, inodeFile, singleVolumeNumber) < 0) {
OS_CLOSE(inodeFile);
+ free(inodeListPath);
return;
}
salvinfo->inodeFd = inodeFile;
if (salvinfo->inodeFd == INVALID_FD)
Abort("Temporary file %s is missing...\n", inodeListPath);
+
+ free(inodeListPath);
+ inodeListPath = NULL;
+
OS_SEEK(salvinfo->inodeFd, 0L, SEEK_SET);
if (ListInodeOption) {
PrintInodeList(salvinfo);
void
DeleteExtraVolumeHeaderFile(struct SalvInfo *salvinfo, struct VolumeSummary *vsp)
{
- char path[64];
+ char path[VMAXPATHLEN + 10];
char filename[VMAXPATHLEN];
if (vsp->deleted) {
goto error;
}
if (canfork && !debug) {
- ShowLog = 0;
- Exit(0);
+ QuietExit(0);
}
} else {
if (Wait("Inode summary") == -1) {
return 0;
}
-/* Find the link table. This should be associated with the RW volume or, if
- * a RO only site, then the RO volume. For now, be cautious and hunt carefully.
+#ifdef AFS_NAMEI_ENV
+/* Find the link table. This should be associated with the RW volume, even
+ * if there is only an RO volume at this site.
*/
-Inode
+static Inode
FindLinkHandle(struct InodeSummary *isp, int nVols,
struct ViceInodeInfo *allInodes)
{
for (i = 0; i < nVols; i++) {
ip = allInodes + isp[i].index;
for (j = 0; j < isp[i].nSpecialInodes; j++) {
- if (ip[j].u.special.type == VI_LINKTABLE)
+ if (ip[j].u.special.volumeId == isp->RWvolumeId &&
+ ip[j].u.special.parentId == isp->RWvolumeId &&
+ ip[j].u.special.type == VI_LINKTABLE) {
return ip[j].inodeNumber;
+ }
}
}
return (Inode) - 1;
}
+static int
+CheckDupLinktable(struct SalvInfo *salvinfo, struct InodeSummary *isp, struct ViceInodeInfo *ip)
+{
+ afs_ino_str_t stmp;
+ if (ip->u.vnode.vnodeNumber != INODESPECIAL) {
+ /* not a linktable; process as a normal file */
+ return 0;
+ }
+ if (ip->u.special.type != VI_LINKTABLE) {
+ /* not a linktable; process as a normal file */
+ return 0;
+ }
+
+ /* make sure nothing inc/decs it */
+ ip->linkCount = 0;
+
+ if (ip->u.special.volumeId == ip->u.special.parentId) {
+ /* This is a little weird, but shouldn't break anything, and there is
+ * no known way that this can happen; just do nothing, in case deleting
+ * it would screw something up. */
+ Log("Inode %s appears to be a valid linktable for id (%u), but it's not\n",
+ PrintInode(stmp, ip->inodeNumber), ip->u.special.parentId);
+ Log("the linktable for our volume group (%u). This is unusual, since\n",
+ isp->RWvolumeId);
+ Log("there should only be one linktable per volume group. I'm leaving\n");
+ Log("it alone, just to be safe.\n");
+ return -1;
+ }
+
+ Log("Linktable %s appears to be invalid (parentid/volumeid mismatch: %u != %u)\n",
+ PrintInode(stmp, ip->inodeNumber), ip->u.special.parentId, ip->u.special.volumeId);
+ if (Testing) {
+ Log("Would have deleted linktable inode %s\n", PrintInode(stmp, ip->inodeNumber));
+ } else {
+ IHandle_t *tmpH;
+ namei_t ufs_name;
+
+ Log("Deleting linktable inode %s\n", PrintInode(stmp, ip->inodeNumber));
+ IH_INIT(tmpH, salvinfo->fileSysDevice, isp->RWvolumeId, ip->inodeNumber);
+ namei_HandleToName(&ufs_name, tmpH);
+ if (unlink(ufs_name.n_path) < 0) {
+ Log("Error %d unlinking path %s\n", errno, ufs_name.n_path);
+ }
+ }
+
+ return -1;
+}
+#endif
+
int
CreateLinkTable(struct SalvInfo *salvinfo, struct InodeSummary *isp, Inode ino)
{
for (i = 0; i < nVols; i++) {
ip = allInodes + isp[i].index;
for (j = isp[i].nSpecialInodes; j < isp[i].nInodes; j++) {
- namei_SetLinkCount(fdP, ip[j].inodeNumber, 1, 1);
+ namei_SetLinkCount(fdP, ip[j].inodeNumber, 1, 0);
ip[j].linkCount = 1;
}
}
int rw = (i == 0);
struct InodeSummary *lisp = &isp[i];
#ifdef AFS_NAMEI_ENV
- /* If only the RO is present on this partition, the link table
- * shows up as a RW volume special file. Need to make sure the
- * salvager doesn't try to salvage the non-existent RW.
- */
- if (rw && nVols > 1 && isp[i].nSpecialInodes == 1) {
- /* If this only special inode is the link table, continue */
- if (inodes->u.special.type == VI_LINKTABLE) {
- haveRWvolume = 0;
- continue;
+ if (rw && (nVols > 1 || isp[i].nSpecialInodes == isp[i].nInodes)) {
+ /* If nVols > 1, we have more than one vol in this volgroup, so
+ * the RW inodes we detected may just be for the linktable, and
+ * there is no actual RW volume.
+ *
+ * Additionally, if we only have linktable inodes (no other
+ * special inodes, no data inodes), there is also no actual RW
+ * volume to salvage; this is just cruft left behind by something
+ * else. In that case nVols will only be 1, though, so also
+ * perform this linktables-only check if we don't have any
+ * non-special inodes. */
+ int inode_i;
+ int all_linktables = 1;
+ for (inode_i = 0; inode_i < isp[i].nSpecialInodes; inode_i++) {
+ if (inodes[inode_i].u.special.type != VI_LINKTABLE) {
+ all_linktables = 0;
+ break;
+ }
+ }
+ if (all_linktables) {
+ /* All we have are linktable special inodes, so skip salvaging
+ * the RW; there was never an RW volume here. If we don't do
+ * this, we risk creating a new "phantom" RW that the VLDB
+ * doesn't know about, which is confusing and can cause
+ * problems. */
+ haveRWvolume = 0;
+ continue;
}
}
#endif
dec_VGLinkH = ip->linkCount - salvinfo->VGLinkH_cnt;
VGLinkH_p1 = ip->u.param[0];
continue; /* Deal with this last. */
+ } else if (CheckDupLinktable(salvinfo, isp, ip)) {
+ /* Don't touch this inode; CheckDupLinktable has handled it */
+ continue;
}
#endif
if (ip->linkCount != 0 && TraceBadLinkCounts) {
IH_RELEASE(salvinfo->VGLinkH);
if (canfork && !debug) {
- ShowLog = 0;
- Exit(0);
+ QuietExit(0);
}
}
}
if (isp->volSummary == NULL) {
- char path[64];
+ char path[VMAXPATHLEN];
char headerName[64];
snprintf(headerName, sizeof headerName, VFORMAT,
afs_printable_VolumeId_lu(isp->volumeId));
writefunc = VCreateVolumeDiskHeader;
} else {
- char path[64];
+ char path[VMAXPATHLEN];
char headerName[64];
/* hack: these two fields are obsolete... */
isp->volSummary->header.volumeAcl = 0;
if (sp->inodeType == VI_VOLINFO) {
salvinfo->VolInfo = header.volumeInfo;
if (check) {
- char update[25];
+ char update[64];
+ char buffer[64];
if (salvinfo->VolInfo.updateDate) {
- strcpy(update, TimeStamp(salvinfo->VolInfo.updateDate, 0));
+ strcpy(update, TimeStamp(buffer, sizeof(buffer), salvinfo->VolInfo.updateDate, 0));
if (!Showmode)
Log("%s (%" AFS_VOLID_FMT ") %supdated %s\n", salvinfo->VolInfo.name,
afs_printable_VolumeId_lu(salvinfo->VolInfo.id),
(Testing ? "it would have been " : ""), update);
} else {
- strcpy(update, TimeStamp(salvinfo->VolInfo.creationDate, 0));
+ strcpy(update, TimeStamp(buffer, sizeof(buffer), salvinfo->VolInfo.creationDate, 0));
if (!Showmode)
Log("%s (%" AFS_VOLID_FMT ") not updated (created %s)\n",
salvinfo->VolInfo.name, afs_printable_VolumeId_lu(salvinfo->VolInfo.id), update);
file = FDH_FDOPEN(fdP, "r+");
opr_Assert(file != NULL);
vcp = &VnodeClassInfo[class];
- size = OS_SIZE(fdP->fd_fd);
+ size = FDH_SIZE(fdP);
opr_Assert(size != -1);
nVnodes = (size / vcp->diskSize) - 1;
if (nVnodes > 0) {
opr_Assert(fdP != NULL);
file = FDH_FDOPEN(fdP, "r+");
opr_Assert(file != NULL);
- size = OS_SIZE(fdP->fd_fd);
+ size = FDH_SIZE(fdP);
opr_Assert(size != -1);
vip->nVnodes = (size / vcp->diskSize) - 1;
if (vip->nVnodes > 0) {
* link count was not incremented in JudgeEntry().
*/
if (class == vLarge) { /* directory vnode */
- pv = vnodeIdToBitNumber(vep->parent);
- if (salvinfo->vnodeInfo[vLarge].vnodes[pv].unique != 0) {
+ struct VnodeEssence *parent_vep;
+
+ parent_vep = CheckVnodeNumber(salvinfo, vep->parent);
+
+ if (!parent_vep)
+ Log("Vnode %d has invalid or out-of-range parent vnode %d;" \
+ " ignore parent count adjustment\n",
+ ThisVnode, vep->parent);
+ else if (parent_vep->unique != 0) {
if (vep->parent == 1 && newrootdir) {
/* this vnode's parent was the volume root, and
* we just created the volume root. So, the parent
/* noop */
} else {
- salvinfo->vnodeInfo[vLarge].vnodes[pv].count++;
+ parent_vep->count++;
}
}
}
volHeader.inUse = 0; /* clear flag indicating inUse@last crash */
volHeader.needsSalvaged = 0; /* clear 'damaged' flag */
volHeader.inService = 1; /* allow service again */
- volHeader.needsCallback = (salvinfo->VolumeChanged != 0);
+ if (salvinfo->VolumeChanged) {
+ volHeader.needsCallback = 1;
+ volHeader.updateDate = time(NULL);
+ } else {
+ volHeader.needsCallback = 0;
+ }
volHeader.dontSalvage = DONT_SALVAGE;
salvinfo->VolumeChanged = 0;
if (!Testing) {
}
if (!Testing) {
afs_int32 code;
- char path[64];
+ char path[VMAXPATHLEN + 10];
char filename[VMAXPATHLEN];
VolumeExternalName_r(isp->volumeId, filename, sizeof(filename));
sprintf(path, "%s" OS_DIRSEP "%s", salvinfo->fileSysPath, filename);
return f;
}
-void
-Exit(int code)
+static void
+QuietExit(int code)
{
- if (ShowLog)
- showlog();
-
#ifdef AFS_DEMAND_ATTACH_FS
if (programType == salvageServer) {
/* release all volume locks before closing down our SYNC channels.
#endif
}
+void
+Exit(int code)
+{
+ SalvageShowLog();
+ QuietExit(code);
+}
+
+
int
Wait(char *prog)
{
}
static char *
-TimeStamp(time_t clock, int precision)
+TimeStamp(char *buffer, size_t size, time_t clock, int precision)
{
struct tm *lt;
- static char timestamp[20];
+ size_t nbytes;
+
lt = localtime(&clock);
if (precision)
- (void)strftime(timestamp, 20, "%m/%d/%Y %H:%M:%S", lt);
+ nbytes = strftime(buffer, size, "%m/%d/%Y %H:%M:%S", lt);
else
- (void)strftime(timestamp, 20, "%m/%d/%Y %H:%M", lt);
- return timestamp;
+ nbytes = strftime(buffer, size, "%m/%d/%Y %H:%M", lt);
+ if (nbytes == 0)
+ memset(buffer, 0, size);
+ return buffer;
}
-void
-CheckLogFile(char * log_path)
-{
- char oldSlvgLog[AFSDIR_PATH_MAX];
-
-#ifndef AFS_NT40_ENV
- if (useSyslog) {
- ShowLog = 0;
- return;
- }
-#endif
-
- strcpy(oldSlvgLog, log_path);
- strcat(oldSlvgLog, ".old");
- if (!logFile) {
- rk_rename(log_path, oldSlvgLog);
- logFile = afs_fopen(log_path, "a");
-
- if (!logFile) { /* still nothing, use stdout */
- logFile = stdout;
- ShowLog = 0;
- }
-#ifndef AFS_NAMEI_ENV
- AFS_DEBUG_IOPS_LOG(logFile);
-#endif
- }
-}
-
-#ifndef AFS_NT40_ENV
-void
-TimeStampLogFile(char * log_path)
-{
- char stampSlvgLog[AFSDIR_PATH_MAX];
- struct tm *lt;
- time_t now;
-
- now = time(0);
- lt = localtime(&now);
- snprintf(stampSlvgLog, sizeof stampSlvgLog,
- "%s.%04d-%02d-%02d.%02d:%02d:%02d", log_path,
- lt->tm_year + 1900, lt->tm_mon + 1, lt->tm_mday, lt->tm_hour,
- lt->tm_min, lt->tm_sec);
-
- /* try to link the logfile to a timestamped filename */
- /* if it fails, oh well, nothing we can do */
- link(log_path, stampSlvgLog);
-}
-#endif
-
-void
-showlog(void)
+static void
+SalvageShowLog(void)
{
char line[256];
+ char *filename;
+ FILE *logFile;
-#ifndef AFS_NT40_ENV
- if (useSyslog) {
- printf("Can't show log since using syslog.\n");
- fflush(stdout);
- return;
+ if (ShowLog == 0 || ClientMode) {
+ return; /* nothing to do */
}
-#endif
-
- if (logFile) {
- rewind(logFile);
- fclose(logFile);
- }
-
- logFile = afs_fopen(AFSDIR_SERVER_SLVGLOG_FILEPATH, "r");
+ filename = strdup(GetLogFilename());
+ opr_Assert(filename != NULL);
+ CloseLog();
+ logFile = afs_fopen(filename, "r");
if (!logFile)
- printf("Can't read %s, exiting\n", AFSDIR_SERVER_SLVGLOG_FILEPATH);
+ printf("Can't read %s, exiting\n", ShowLogFilename);
else {
- rewind(logFile);
while (fgets(line, sizeof(line), logFile))
printf("%s", line);
fflush(stdout);
}
+ free(filename);
+}
+
+static void
+vLog(const char *format, va_list args)
+{
+ if (!ClientMode) {
+ vFSLog(format, args);
+ } else {
+ struct timeval now;
+ char buffer[64];
+
+ gettimeofday(&now, NULL);
+ fprintf(stderr, "%s ", TimeStamp(buffer, sizeof(buffer), now.tv_sec, 1));
+ vfprintf(stderr, format, args);
+ fflush(stderr);
+ }
}
void
Log(const char *format, ...)
{
- struct timeval now;
- char tmp[1024];
va_list args;
va_start(args, format);
- vsnprintf(tmp, sizeof tmp, format, args);
+ vLog(format, args);
va_end(args);
-#ifndef AFS_NT40_ENV
- if (useSyslog) {
- syslog(LOG_INFO, "%s", tmp);
- } else
-#endif
- if (logFile) {
- gettimeofday(&now, NULL);
- fprintf(logFile, "%s %s", TimeStamp(now.tv_sec, 1), tmp);
- fflush(logFile);
- }
}
void
Abort(const char *format, ...)
{
va_list args;
- char tmp[1024];
va_start(args, format);
- vsnprintf(tmp, sizeof tmp, format, args);
+ vLog(format, args);
va_end(args);
-#ifndef AFS_NT40_ENV
- if (useSyslog) {
- syslog(LOG_INFO, "%s", tmp);
- } else
-#endif
- if (logFile) {
- fprintf(logFile, "%s", tmp);
- fflush(logFile);
- if (ShowLog)
- showlog();
- }
-
+ SalvageShowLog();
if (debug)
abort();
- Exit(1);
+ QuietExit(1);
}
char *
nt_SetupPartitionSalvage(void *datap, int len)
{
childJob_t *jobp = (childJob_t *) datap;
- char logname[AFSDIR_PATH_MAX];
+ char *logname;
if (len != sizeof(childJob_t))
return -1;
myjob = *jobp;
/* Open logFile */
- (void)sprintf(logname, "%s.%d", AFSDIR_SERVER_SLVGLOG_FILEPATH,
- myjob.cj_number);
- logFile = afs_fopen(logname, "w");
- if (!logFile)
- logFile = stdout;
+ if (asprintf(&logname, "%s.%d", AFSDIR_SERVER_SLVGLOG_FILEPATH,
+ myjob.cj_number) < 0)
+ return -1;
+ OpenLog(logname);
+ free(logname);
return 0;
}