/* * Copyright (c) 1980, 1986 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #include #include RCSID("$Header$"); #define VICE /* allow us to put our changes in at will */ #include #include #include #ifdef AFS_SUN_ENV #define KERNEL #endif /* AFS_SUN_ENV */ #include #ifdef AFS_SUN_ENV #undef KERNEL #endif #include #ifdef AFS_OSF_ENV #include #include #include #include #else /* AFS_OSF_ENV */ #ifdef AFS_VFSINCL_ENV #define VFS #include #ifdef AFS_SUN5_ENV #include #include #include #define _KERNEL #include #undef _KERNEL #include #else #include #include #define KERNEL #include #undef KERNEL #endif #else /* AFS_VFSINCL_ENV */ #include #ifdef AFS_HPUX_ENV #include #define LONGFILENAMES 1 #include #include #define DIRSIZ_MACRO #include #else #define KERNEL #include #undef KERNEL #endif #include #endif /* AFS_VFSINCL_ENV */ #endif /* AFS_OSF_ENV */ #ifdef AFS_DEC_ENV #include #endif #include #include #ifdef AFS_SUN5_ENV #include #else #include #endif #include #ifdef XAFS_SUN_ENV #include #else #ifdef AFS_SUN5_ENV #include #include #include #include #else #include #endif #endif #include "fsck.h" #include #include char *rawname(), *unrawname(), *blockcheck(), *malloc(); void catch(), catchquit(), voidquit(); static int tryForce; int returntosingle; extern int errno; struct part { char *name; /* device name */ char *fsname; /* mounted filesystem name */ struct part *next; /* forward link of partitions on disk */ } *badlist, **badnext = &badlist; struct disk { char *name; /* disk base name */ struct disk *next; /* forward link for list of disks */ struct part *part; /* head of list of partitions on disk */ int pid; /* If != 0, pid of proc working on */ } *disks; int nrun, ndisks, maxrun, wflag=0; #ifdef AFS_HPUX_ENV int fixed; #endif #if defined(AFS_HPUX100_ENV) #include #include #endif #ifdef VICE #define msgprintf vfscklogprintf #else /* VICE */ #define msgprintf printf #endif /* VICE */ #ifdef AFS_SUN5_ENV int mnt_passno = 0; #endif #include "AFS_component_version_number.c" #ifdef AFS_HPUX_ENV int ge_danger = 0; /* on when fsck is not able to fix the dirty file system within single run. Problems like dup table overflow, maxdup is exceeding MAXDUP.. etc. could potentailly prevent fsck from doing a complete repair. This is found in a GE hotsite. */ #endif main(argc, argv) int argc; char *argv[]; { struct fstab *fsp; int pid, passno, sumstatus; char *name; register struct disk *dk, *nextdisk; register struct part *pt; extern char* AFSVersion; /* generated version */ #ifdef AFS_SUN5_ENV int other_than_ufs=0; char *subopt; struct vfstab vt; FILE *vfile; int ret; struct vfstab vget; FILE *fd; #endif sync(); tryForce = 0; #if defined(AFS_HPUX_ENV) pclean = 0; #endif #if defined(AFS_HPUX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) fflag = 0; #endif #ifdef AFS_SUN5_ENV fsflag = oflag = mflag = exitstat = 0; #endif #if defined(AFS_HPUX100_ENV) mflag = 0; #endif printf("----Open AFS (R) %s fsck----\n", AFSVersion); /* generated version */ if (access("/TRYFORCE", 0) == 0) tryForce = 1; while (--argc > 0 && **++argv == '-') { switch (*++*argv) { #if defined(AFS_HPUX_ENV) #if defined(AFS_HPUX100_ENV) case 'f': /* default yes to answer force to check */ fflag++; break; #else /* AFS_HPUX100_ENV */ #ifdef AFS_HPUX_ENV case 'F': /* default yes to answer force to check */ fflag++; break; #endif /* AFS_HPUX_ENV */ #endif /* AFS_HPUX100_ENV */ case 'P': pclean++; preen++; break; #endif #if defined(AFS_DEC_ENV) /* On the late versions of Ultrix they changed the defn of '-p' a bit. Particularly, * -p is used to check a file system that was not unmounted cleanly, and they added, * -P to check a file system regardless of how it was unmounted; this, unfortunately, * is identical to '-p' on the rest of the systems but we have to maintain vendor's * semantics so we leave it the way Dec likes it. */ case 'p': only_when_needed++; /* P is for Ultrix compatibility */ case 'P': #else case 'p': #endif preen++; break; #if defined(AFS_HPUX100_ENV) case 'V': { int opt_count; char *opt_text; (void) fprintf (stdout, "fsck -F hfs "); for (opt_count = 1; opt_count < argc ; opt_count++) { opt_text = argv[opt_count]; if (opt_text) (void) fprintf (stdout, " %s ", opt_text); } (void) fprintf (stdout, "\n"); exit(0); } break; case 'm': mflag++; break; #endif #ifdef AFS_SUN5_ENV case 'V': { int opt_count; char *opt_text; (void) fprintf (stdout, "fsck -F ufs "); for (opt_count = 1; opt_count < argc ; opt_count++) { opt_text = argv[opt_count]; if (opt_text) (void) fprintf (stdout, " %s ", opt_text); } (void) fprintf (stdout, "\n"); } break; case 'o': subopt = *++argv; argc--; while (*subopt != '\0') { if (*subopt == 'p') { preen++; break; } else if (*subopt == 'b') { if (argv[0][1] != '\0') { bflag = atoi(argv[0]+1); } else { bflag = atoi(*++argv); argc--; } msgprintf("Alternate super block location: %d\n", bflag); break; } else if (*subopt == 'd') { debug++; break; } else if (*subopt == 'r') { break; } else if (*subopt == 'w') { wflag++; break; } else if (*subopt == 'c') { cvtflag++; break; } else if (*subopt == 'f') { fflag++; break; } else { errexit("-o %c option?\n", *subopt); } subopt++; ++argv; argc--; } oflag++; break; case 'm': mflag++; break; #else case 'b': if (argv[0][1] != '\0') { bflag = atoi(argv[0]+1); } else { bflag = atoi(*++argv); argc--; } msgprintf("Alternate super block location: %d\n", bflag); break; case 'c': cvtflag++; break; /* who knows? defined, but doesn't do much */ case 'r': break; case 'w': /* check writable only */ wflag++; break; case 'd': debug++; break; case 'l': if (!isdigit(argv[1][0])) errexit("-l flag requires a number\n"); maxrun = atoi(*++argv); argc--; break; #if !defined(AFS_HPUX100_ENV) case 'm': if (!isdigit(argv[1][0])) errexit("-m flag requires a mode\n"); sscanf(*++argv, "%o", &lfmode); if (lfmode &~ 07777) errexit("bad mode to -m: %o\n", lfmode); argc--; printf("** lost+found creation mode %o\n", lfmode); break; #endif /* AFS_HPUX100_ENV */ #endif /* AFS_SUN5_ENV */ #ifdef AFS_OSF_ENV case 'o': fflag++; break; #endif /* AFS_OSF_ENV */ case 'n': case 'N': nflag++; yflag = 0; break; /* * NOTE: -q flag is used only by HPux fsck versions but we add it for all systems since * it's general/useful flag to use. */ case 'q': qflag++; break; case 'y': case 'Y': yflag++; nflag = 0; break; default: errexit("%c option?\n", **argv); } } /* * The following checks were only available on hpux but are useful to all systems. */ if (nflag && preen) errexit("Incompatible options: -n and -p\n"); if (nflag && qflag) errexit("Incompatible options: -n and -q\n"); #ifdef AFS_SUN5_ENV rflag++; /* check raw devices */ #endif if (signal(SIGINT, SIG_IGN) != SIG_IGN) (void)signal(SIGINT, catch); if (preen) (void)signal(SIGQUIT, catchquit); if (argc) { while (argc-- > 0) { hotroot = 0; #ifdef AFS_SUN5_ENV if (wflag && !writable(*argv)) { (void) fprintf (stderr, "not writeable '%s'\n", *argv); argv++; } else #endif checkfilesys(*argv++, (char *)0); } #ifdef AFS_HPUX_ENV if (ge_danger) exit(-1); #endif #ifdef AFS_SUN5_ENV exit(exitstat); #else exit(0); #endif } #ifndef AFS_SUN5_ENV sumstatus = 0; #ifdef AFS_SUN5_ENV if (fstype == NULL || strcmp(fstype, MNTTYPE_UFS) == 0) { int status; if ((fd = fopen(VFSTAB, "r")) == NULL) { errexit("vfsck: cannot open vfstab\n"); } while ((ret = getvfsent(fd, &vget)) == 0) { if (strcmp(vget.vfs_fstype, MNTTYPE_UFS) && numbers(vget.vfs_fsckpass)) { other_than_ufs++; continue; } if (numbers(vget.vfs_fsckpass)) passno = atoi(vget.vfs_fsckpass); else continue; if (passno < 1) continue; if (preen == 0 || passno == 1) { checkfilesys(vget.vfs_fsckdev, get.vfs_mountp); } else if (passno > 1) { addpart(vget.vfs_fsckdev, vget.vfs_special); } } #else for (passno = 1; passno <= 2; passno++) { if (setfsent() == 0) errexit("Can't open checklist file: %s\n", FSTAB); while ((fsp = getfsent()) != 0) { if (strcmp(fsp->fs_type, FSTAB_RW) && strcmp(fsp->fs_type, FSTAB_RO) && strcmp(fsp->fs_type, FSTAB_RQ)) continue; #ifdef AFS_DEC_ENV /* Only check local (i.e. ufs) file systems */ if (strcmp(fsp->fs_name, "4.2") && strcmp(fsp->fs_name, "ufs")) continue; #endif #ifdef AFS_OSF_ENV if (strcmp(fsp->fs_vfstype, "ufs") || fsp->fs_passno == 0) { continue; } #endif /* AFS_OSF_ENV */ if (preen == 0 || passno == 1 && fsp->fs_passno == 1) { if (passno == 1) { name = blockcheck(fsp->fs_spec); if (name != NULL) { checkfilesys(name, fsp->fs_file); } else if (preen) { printf("pid %d exiting 8/1\n", getpid()); exit(8); } } } else if (passno == 2 && fsp->fs_passno > 1) { name = blockcheck(fsp->fs_spec); if (name == NULL) { pwarn("BAD DISK NAME %s\n", fsp->fs_spec); sumstatus |= 8; printf("pid %d saw bad disk name 8/3\n", getpid()); continue; } addpart(name, fsp->fs_file); } } #endif AFS_SUN5_ENV } if (preen) { int status, rc; if (maxrun == 0) maxrun = ndisks; if (maxrun > ndisks) maxrun = ndisks; nextdisk = disks; for (passno = 0; passno < maxrun; ++passno) { startdisk(nextdisk); nextdisk = nextdisk->next; } while ((pid = wait(&status)) != -1) { for (dk = disks; dk; dk = dk->next) if (dk->pid == pid) break; if (dk == 0) { printf("Unknown pid %d\n", pid); continue; } rc = WEXITSTATUS(status); if (WIFSIGNALED(status)) { printf("%s (%s): EXITED WITH SIGNAL %d\n", dk->part->name, dk->part->fsname, WTERMSIG(status)); rc = 8; } if (rc != 0) { sumstatus |= rc; *badnext = dk->part; badnext = &dk->part->next; dk->part = dk->part->next; *badnext = NULL; } else dk->part = dk->part->next; dk->pid = 0; nrun--; if (dk->part == NULL) ndisks--; if (nextdisk == NULL) { if (dk->part) startdisk(dk); } else if (nrun < maxrun && nrun < ndisks) { for ( ;; ) { if ((nextdisk = nextdisk->next) == NULL) nextdisk = disks; if (nextdisk->part != NULL && nextdisk->pid == 0) break; } startdisk(nextdisk); } } } if (sumstatus) { if (badlist == 0) { printf("pid %d exiting 8/2\n", getpid()); exit(8); } printf("THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t", badlist->next ? "S" : "", "UNEXPECTED INCONSISTENCY:"); for (pt = badlist; pt; pt = pt->next) printf("%s (%s)%s", pt->name, pt->fsname, pt->next ? ", " : "\n"); exit(8); } #ifdef AFS_SUN5_ENV fclose(fd); #else (void)endfsent(); #endif if (returntosingle) exit(2); #endif /* !AFS_SUN5_ENV */ exit(0); } struct disk * finddisk(name) char *name; { register struct disk *dk, **dkp; register char *p; int len; for (p = name + strlen(name) - 1; p >= name; --p) if (isdigit(*p)) { len = p - name + 1; break; } if (p < name) len = strlen(name); for (dk = disks, dkp = &disks; dk; dkp = &dk->next, dk = dk->next) { if (strncmp(dk->name, name, len) == 0 && dk->name[len] == 0) return (dk); } if ((*dkp = (struct disk *)malloc(sizeof(struct disk))) == NULL) errexit("out of memory"); dk = *dkp; if ((dk->name = malloc((unsigned int)len + 1)) == NULL) errexit("out of memory"); strncpy(dk->name, name, len); dk->name[len] = '\0'; dk->part = NULL; dk->next = NULL; dk->pid = 0; ndisks++; return (dk); } addpart(name, fsname) char *name, *fsname; { struct disk *dk = finddisk(name); register struct part *pt, **ppt = &dk->part; for (pt = dk->part; pt; ppt = &pt->next, pt = pt->next) if (strcmp(pt->name, name) == 0) { printf("%s in fstab more than once!\n", name); return; } if ((*ppt = (struct part *)malloc(sizeof(struct part))) == NULL) errexit("out of memory"); pt = *ppt; if ((pt->name = malloc((unsigned int)strlen(name) + 1)) == NULL) errexit("out of memory"); strcpy(pt->name, name); if ((pt->fsname = malloc((unsigned int)strlen(fsname) + 1)) == NULL) errexit("out of memory"); strcpy(pt->fsname, fsname); pt->next = NULL; } startdisk(dk) register struct disk *dk; { nrun++; dk->pid = fork(); if (dk->pid < 0) { perror("fork"); exit(8); } if (dk->pid == 0) { (void)signal(SIGQUIT, voidquit); checkfilesys(dk->part->name, dk->part->fsname); exit(0); } } checkfilesys(filesys, parname) char *filesys; { daddr_t n_ffree, n_bfree; struct dups *dp; struct stat tstat; /* for ultrix 3 unmount */ struct zlncnt *zlnp; char devbuffer[128]; int ret_val; #ifdef AFS_DEC_ENV int retries = 3; /* # of retries fora clean fsck pass */ int fsdirty = 0; /* file system was or is dirty */ int rootdirty = 0; /* Root was or is dirty */ #endif #ifdef AFS_OSF_ENV int temp; #endif /* AFS_OSF_ENV */ #ifdef AFS_SUN_ENV iscorrupt = 1; #endif #ifdef AFS_SUN5_ENV mountedfs = 0; isconvert = 0; #endif #ifdef AFS_HPUX_ENV ge_danger = 0; /* set to 1 by any table overflow or more dup/bad blocks than expected */ fixed = 1; /* set to 0 by any 'no' reply */ #endif strcpy(devbuffer, filesys); /* copy the file system name to the device buffer */ devname = devbuffer; /* remember generic ptr for later */ EnsureDevice(devname); /* canonicalize name */ if (debug && preen) pinfo("starting\n"); #ifdef AFS_DEC_ENV for (; retries > 0; retries--) { /* 003 - Loop for NUMRETRIES or until clean */ #endif ret_val = setup(devname); if (ret_val == 0) { #ifdef AFS_SUN_ENV if (iscorrupt == 0) return; #endif if (preen) pfatal("CAN'T CHECK FILE SYSTEM."); #ifdef AFS_SUN5_ENV if ((exitstat == 0) && (mflag)) exitstat = 32; exit(exitstat); #endif return (0); #ifdef AFS_HPUX_ENV } else if (ret_val == -1 ) { /* pclean && FS_CLEAN */ return(1); #endif #if defined(AFS_DEC_ENV) || defined(AFS_OSF_ENV) } else if (ret_val == FS_CLEAN) { /* pclean && FS_CLEAN */ return(1); #endif } #if defined(AFS_HPUX100_ENV) if (mflag) check_sanity(filesys); #endif #ifdef AFS_SUN5_ENV if (mflag) check_sanity(filesys); if (debug) printclean(); #endif #ifdef AFS_SUN_ENV iscorrupt = 0; #endif /* * 1: scan inodes tallying blocks used */ if (preen == 0) { #if defined(AFS_SUN5_ENV) if (mountedfs) msgprintf("** Currently Mounted on %s\n", sblock.fs_fsmnt); else #endif msgprintf("** Last Mounted on %s\n", sblock.fs_fsmnt); if (hotroot) msgprintf("** Root file system\n"); #ifdef AFS_SUN5_ENV if (mflag) { printf("** Phase 1 - Sanity Check only\n"); return; } else #endif msgprintf("** Phase 1 - Check Blocks and Sizes\n"); } pass1(); /* * 1b: locate first references to duplicates, if any */ if (duplist) { if (preen) pfatal("INTERNAL ERROR: dups with -p"); msgprintf("** Phase 1b - Rescan For More DUPS\n"); pass1b(); } /* * 2: traverse directories from root to mark all connected directories */ if (preen == 0) msgprintf("** Phase 2 - Check Pathnames\n"); pass2(); /* * 3: scan inodes looking for disconnected directories */ if (preen == 0) msgprintf("** Phase 3 - Check Connectivity\n"); pass3(); /* * 4: scan inodes looking for disconnected files; check reference counts */ if (preen == 0) msgprintf("** Phase 4 - Check Reference Counts\n"); pass4(); /* * 5: check and repair resource counts in cylinder groups */ if (preen == 0) msgprintf("** Phase 5 - Check Cyl groups\n"); pass5(); #ifdef AFS_DEC_ENV if (fsmodified || (sblk.b_dirty) || (cgblk.b_dirty)) { fsdirty = 1; if (hotroot) rootdirty = 1; if (retries <= 1) { /* * 003 - Number of retry attempts have been * exhausted. Mark super block as dirty. */ (void)time(&sblock.fs_time); sbdirty(); } } else { /* * 003 - If checking root file system, and it was * modified during any pass, don't assume it is ok. Must reboot. */ if (rootdirty) { sbdirty(); retries = 0; } else { if ((!hotroot) && (!bflag) && (!nflag) && (!iscorrupt)) { sblock.fs_fmod = 0; sblock.fs_clean = FS_CLEAN; (void)time(&sblock.fs_time); (void)time(&sblock.fs_lastfsck); if ((sblock.fs_deftimer) && (sblock.fs_deftimer > 0) && (sblock.fs_deftimer < 255)) sblock.fs_cleantimer = sblock.fs_deftimer; else sblock.fs_cleantimer = sblock.fs_deftimer = FSCLEAN_TIMEOUTFACTOR; sbdirty(); } /* * 006 - If an alternate super block was used, * we want to re fsck the partition after * updating the primary super block. */ if (!bflag) retries = 0; } } /* Unless no updates are to be done, write out maps. */ if (nflag) retries = 0; else ckfini(); if (debug) { daddr_t nn_files = n_files; daddr_t nn_blks = n_blks; n_ffree = sblock.fs_cstotal.cs_nffree; n_bfree = sblock.fs_cstotal.cs_nbfree; if (nn_files -= maxino - ROOTINO - sblock.fs_cstotal.cs_nifree) printf("%d files missing\n", nn_files); nn_blks += sblock.fs_ncg * (cgdmin(&sblock, 0) - cgsblock(&sblock, 0)); nn_blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0); nn_blks += howmany(sblock.fs_cssize, sblock.fs_fsize); if (nn_blks -= maxfsblock - (n_ffree + sblock.fs_frag * n_bfree)) printf("%d blocks missing\n", nn_blks); } if (duplist != NULL) { if (debug) printf("The following duplicate blocks remain:"); for (dp = duplist; dp; dp = dp->next) { if (debug) printf(" %d,", dp->dup); free(dp); } if (debug) printf("\n"); } if (zlnhead != NULL) { if (debug) printf("The following zero link count inodes remain:"); for (zlnp = zlnhead; zlnp; zlnp = zlnp->next) { if (debug) printf(" %d,", zlnp->zlncnt); free(zlnp); } if (debug) printf("\n"); } zlnhead = (struct zlncnt *)0; duplist = (struct dups *)0; free(blockmap); free(statemap); free((char *)lncntp); /* Print out retry message, and fsck file system again. */ if (retries > 1) if (preen) printf("%s: FILE SYSTEM MODIFIED, VERIFYING\n",filesys); else printf("**** FILE SYSTEM MODIFIED, VERIFYING\n"); } /* for retries */ #endif #if defined(AFS_SUN_ENV) && !defined(AFS_SUN3_ENV) updateclean(); if (debug) printclean(); #endif /* * print out summary statistics */ n_ffree = sblock.fs_cstotal.cs_nffree; n_bfree = sblock.fs_cstotal.cs_nbfree; #ifdef VICE #if defined(ACLS) && defined(AFS_HPUX_ENV) pinfo("%d files, %d icont, %d used, %d free", n_files, n_cont, n_blks, n_ffree + sblock.fs_frag * n_bfree); #else pinfo("%d files, %d used, %d free", n_files, n_blks, n_ffree + sblock.fs_frag * n_bfree); #endif if (nViceFiles) msgprintf(", %d AFS files", nViceFiles); msgprintf(" (%d frags, %d blocks, %.1f%% fragmentation)\n", n_ffree, n_bfree, (float)(n_ffree * 100) / sblock.fs_dsize); #else /* VICE */ #if defined(ACLS) && defined(AFS_HPUX_ENV) pinfo("%d files, %d icont, %d used, %d free ", n_files, n_cont, n_blks, n_ffree + sblock.fs_frag * n_bfree); #else pinfo("%d files, %d used, %d free ", n_files, n_blks, n_ffree + sblock.fs_frag * n_bfree); #endif n printf("(%d frags, %d blocks, %.1f%% fragmentation)\n", n_ffree, n_bfree, (float)(n_ffree * 100) / sblock.fs_dsize); #endif /* VICE */ #ifdef AFS_DEC_ENV if ((!fsdirty) && (!rootdirty)) return; if (!preen) { printf("\n***** FILE SYSTEM WAS MODIFIED *****\n"); if (hotroot) printf("\n***** HALT PROCESSOR WITHOUT SYNCING DISK *****\n"); } if (hotroot) { sync(); exit(4); } #else if (debug && (n_files -= maxino - ROOTINO - sblock.fs_cstotal.cs_nifree)) msgprintf("%d files missing\n", n_files); if (debug) { n_blks += sblock.fs_ncg * (cgdmin(&sblock, 0) - cgsblock(&sblock, 0)); n_blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0); n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize); if (n_blks -= maxfsblock - (n_ffree + sblock.fs_frag * n_bfree)) printf("%d blocks missing\n", n_blks); if (duplist != NULL) { msgprintf("The following duplicate blocks remain:"); for (dp = duplist; dp; dp = dp->next) msgprintf(" %d,", dp->dup); msgprintf("\n"); } if (zlnhead != NULL) { msgprintf("The following zero link count inodes remain:"); for (zlnp = zlnhead; zlnp; zlnp = zlnp->next) msgprintf(" %d,", zlnp->zlncnt); msgprintf("\n"); } } #endif #ifdef AFS_HPUX_ENV /* if user's specification denotes that the file system block * is going to be modified (nflag == 0) then fsck store the * correct magic number in the super block if it is not already * there */ if (!nflag && !(fswritefd < 0)) { if (ge_danger) { printf("***** FILE SYSTEM IS NOT CLEAN, FSCK AGAIN *****\n"); fsmodified++; } else { if (!hotroot) { if (fixed && (sblock.fs_clean != FS_CLEAN)) { if (!preen && !qflag) printf("***** MARKING FILE SYSTEM CLEAN *****\n"); sblock.fs_clean = FS_CLEAN; fsmodified++; } } else { /* fix FS_CLEAN if changes made and no 'no' replies */ if (fsmodified && fixed) sblock.fs_clean = FS_CLEAN; /* * Fix fs_clean if there were no 'no' replies. * This is done for both the s300 and s800. The s800 root will be * guaranteed clean as of 7.0. */ if (fixed && (sblock.fs_clean != FS_OK)) { if (!preen && !qflag) printf("***** MARKING FILE SYSTEM CLEAN *****\n"); sblock.fs_clean = FS_CLEAN; fsmodified++; } } } } #endif zlnhead = (struct zlncnt *)0; duplist = (struct dups *)0; #if defined(AFS_SUN_ENV) && !defined(AFS_SUN3_ENV) /* WAS AFS_SUN5_ENV */ #ifdef notdef inocleanup(); #endif if (fsmodified) fixstate = 1; else fixstate = 0; if (hotroot && sblock.fs_clean == FSACTIVE) rebflg = 1; #ifdef AFS_SUN5_ENV else if (!((sblock.fs_state + (afs_int32)sblock.fs_time == FSOKAY) && #else else if (!((fs_get_state(&sblock) + (afs_int32)sblock.fs_time == FSOKAY) && #endif (sblock.fs_clean ==FSCLEAN || sblock.fs_clean ==FSSTABLE))) { if (yflag || !iscorrupt) { printf("%s FILE SYSTEM STATE SET TO OKAY\n", devname); fixstate = 1; } else { printf("%s FILE SYSTEM STATE NOT SET TO OKAY\n", devname); fixstate = 0; } } if (fixstate) { (void)time(&sblock.fs_time); if (!iscorrupt) { if (hotroot && rebflg) sblock.fs_clean = FSACTIVE; else sblock.fs_clean = FSSTABLE; #ifdef AFS_SUN5_ENV sblock.fs_state = FSOKAY - (afs_int32)sblock.fs_time; #else fs_set_state(&sblock, FSOKAY - (afs_int32)sblock.fs_time); #endif } sbdirty(); } #else #ifdef AFS_OSF_ENV if (!nflag && !bflag && !hotroot) { temp = fsmodified; sblock.fs_clean = FS_CLEAN; (void)time(&sblock.fs_time); sbdirty(); flush(fswritefd, &sblk); fsmodified = temp; } #else /* AFS_OSF_ENV */ if (fsmodified) { (void)time(&sblock.fs_time); sbdirty(); } #endif #endif #ifndef AFS_DEC_ENV ckfini(); free(blockmap); free(statemap); free((char *)lncntp); lncntp = NULL; blockmap = statemap = NULL; #ifdef AFS_SUN5_ENV if (iscorrupt) exitstat = 36; #endif if (!fsmodified) return; if (!preen) { msgprintf("\n***** FILE SYSTEM WAS MODIFIED *****\n"); if (hotroot) msgprintf("\n***** REBOOT UNIX *****\n"); } #ifdef AFS_SUN5_ENV if (mountedfs || hotroot) { exitstat = 40; } #endif if (hotroot) { sync(); #ifdef AFS_HPUX_ENV if (ge_danger) exit(-1); else #endif exit(4); } #endif #ifdef VICE (void)close(fsreadfd); (void)close(fswritefd); if (nViceFiles || tryForce) { /* Modified file system with vice files: force full salvage */ /* Salvager recognizes the file FORCESALVAGE in the root of each partition */ #if !defined(AFS_DEC_ENV) struct ufs_args ufsargs; #endif char pname[100], fname[100], *special; int fd, code, failed=0; msgprintf("%s: AFS file system partition was modified; forcing full salvage\n", devname); devname = unrawname(devname); special = (char *) strrchr(devname, '/'); if (!special++) special = devname; strcpy(pname, "/etc/vfsck."); /* Using /etc, rather than /tmp, since /tmp is a link to /usr/tmp on some systems, and isn't mounted now */ strcat(pname, special); #ifdef AFS_SUN_ENV /* if system mounted / as read-only, we'll try to fix now */ if (access("/", W_OK) < 0 && errno == EROFS) { code = system("mount -o remount /"); if (code) { printf("Couldn't remount / R/W; continuing anyway (%d).\n", errno); failed = 1; } } #endif #ifdef AFS_OSF_ENV /* if system mounted / as read-only, we'll try to fix now */ if (access("/", W_OK) < 0 && errno == EROFS) { printf("Can't RW acceess /; %d\n", errno); code = system("/sbin/mount -u /"); if (code) { printf("Couldn't remount / R/W; continuing anyway (%d).\n", errno); failed = 1; } } #endif rmdir(pname); unlink(pname); if (mkdir(pname, 0777) < 0) { if (errno != EEXIST) { perror("fsck mkdir"); failed = 1; } } if (failed && parname) { strcpy(pname, parname); } #if !defined(AFS_DEC_ENV) && !defined(AFS_HPUX_ENV) #ifdef AFS_SUN5_ENV ufsargs.flags = UFSMNT_NOINTR; #else ufsargs.fspec = devname; #endif #ifdef AFS_SUN_ENV #ifdef AFS_SUN5_ENV if (mount(devname, pname, MS_DATA, "ufs", (char *)&ufsargs, sizeof(ufsargs)) < 0) { #else if (mount("4.2", pname, M_NEWTYPE, &ufsargs) < 0) { #endif #else if (mount(MOUNT_UFS, pname, 0, &ufsargs) < 0) { #endif #else #ifdef AFS_DEC_ENV if (mount(devname, pname, 0, GT_ULTRIX, (char *) 0)) { #else if (mount(devname, pname, 0) < 0) { #endif #endif printf("Couldn't mount %s on %s to force FULL SALVAGE; continuing anyway (%d)!\n", devname, pname, errno); } else { strcpy(fname, pname); strcat(fname, "/FORCESALVAGE"); fd = open(fname, O_CREAT, 0); if (fd == -1) { errexit("Couldn't create %s to force full salvage!\n", fname); #if defined(AFS_DEC_ENV) stat(".", &tstat); #endif } else { fstat(fd, &tstat); close(fd); } #if /*defined(AFS_VFS_ENV) &&*/ !defined(AFS_DEC_ENV) && !defined(AFS_HPUX_ENV) && !defined(AFS_SUN5_ENV) && !defined(AFS_OSF_ENV) unmount(pname); #else #if defined(AFS_DEC_ENV) umount(tstat.st_dev); #else #if defined(AFS_OSF_ENV) umount(pname, MNT_NOFORCE); #else /* AFS_OSF_ENV */ umount(devname); #endif #endif #endif } rmdir(pname); } if (logfile) { fsync(fileno(logfile)); /* Since update isn't running */ fclose(logfile); logfile = 0; } #endif /* VICE */ } char * blockcheck(name) char *name; { struct stat stslash, stblock, stchar; char *raw; int retried = 0; hotroot = 0; if (stat("/", &stslash) < 0) { perror("/"); printf("Can't stat root\n"); return (0); } retry: if (stat(name, &stblock) < 0) { perror(name); printf("Can't stat %s\n", name); return (0); } if ((stblock.st_mode & S_IFMT) == S_IFBLK) { if (stslash.st_dev == stblock.st_rdev) { hotroot++; #if !defined(AFS_OSF_ENV) /* OSF/1 always uses the raw device, even for / */ return (name); #endif /* AFS_OSF_ENV */ } raw = rawname(name); if (raw) { return (raw); } else { printf("Cannot find character device for %s\n", name); return (name); } } else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) { name = unrawname(name); retried++; goto retry; } printf("Can't make sense out of name %s\n", name); return (0); } #if defined(AFS_HPUX_ENV) || defined(AFS_SUN5_ENV) #ifdef AFS_SUN5_ENV /* * exit 0 - file system is unmounted and okay * exit 32 - file system is unmounted and needs checking * exit 33 - file system is mounted for root file system * exit 34 - cannot stat device */ check_sanity(filename) char *filename; { struct stat stbd, stbr; struct ustat usb; char *devname; struct vfstab vfsbuf; FILE *vfstab; int is_root = 0; int is_usr = 0; int is_block = 0; if (stat(filename, &stbd) < 0) { fprintf(stderr, "ufs fsck: sanity check failed : cannot stat %s\n", filename); exit(34); } if ((stbd.st_mode & S_IFMT) == S_IFBLK) is_block = 1; else if ((stbd.st_mode & S_IFMT) == S_IFCHR) is_block = 0; else { fprintf(stderr, "ufs fsck: sanity check failed: %s not block or character device\n", filename); exit(34); } /* * Determine if this is the root file system via vfstab. Give up * silently on failures. The whole point of this is not to care * if the root file system is already mounted. * * XXX - similar for /usr. This should be fixed to simply return * a new code indicating, mounted and needs to be checked. */ if ((vfstab = fopen(VFSTAB, "r")) != 0) { if (getvfsfile(vfstab, &vfsbuf, "/") == 0) { if (is_block) devname = vfsbuf.vfs_special; else devname = vfsbuf.vfs_fsckdev; if (stat(devname, &stbr) == 0) if (stbr.st_rdev == stbd.st_rdev) is_root = 1; } if (getvfsfile(vfstab, &vfsbuf, "/usr") == 0) { if (is_block) devname = vfsbuf.vfs_special; else devname = vfsbuf.vfs_fsckdev; if (stat(devname, &stbr) == 0) if (stbr.st_rdev == stbd.st_rdev) is_usr = 1; } } /* XXX - only works if filename is a block device or if character and block device has the same dev_t value */ if (is_root == 0 && is_usr == 0 && ustat(stbd.st_rdev, &usb) == 0) { fprintf(stderr, "ufs fsck: sanity check: %s already mounted\n", filename); exit(33); } /* * We mount the ufs root file system read-only first. After fsck * runs, we remount the root as read-write. Therefore, we no longer * check for different values for fs_state between the root file * system and the rest of file systems. */ if (!((sblock.fs_state + (time_t)sblock.fs_time == FSOKAY) && (sblock.fs_clean ==FSCLEAN || sblock.fs_clean ==FSSTABLE))) { fprintf(stderr, "ufs fsck: sanity check: %s needs checking\n", filename); exit(32); } fprintf(stderr, "ufs fsck: sanity check: %s okay\n", filename); exit(0); } #endif #if defined(AFS_HPUX100_ENV) check_sanity(filename) char *filename; { struct stat stbd, stbr; struct ustat usb; char *devname; FILE *vfstab; struct mntent *mnt; int is_root = 0; int is_usr = 0; int is_block = 0; if (stat(filename, &stbd) < 0) { fprintf(stderr, "hfs fsck: sanity check failed : cannot stat %s\n", filename); exit(34); } if ((stbd.st_mode & S_IFMT) == S_IFBLK) is_block = 1; else if ((stbd.st_mode & S_IFMT) == S_IFCHR) is_block = 0; else { fprintf(stderr, "hfs fsck: sanity check failed: %s not block or character device\n", filename); exit(34); } /* * Determine if this is the root file system via vfstab. Give up * silently on failures. The whole point of this is not to care * if the root file system is already mounted. * * XXX - similar for /usr. This should be fixed to simply return * a new code indicating, mounted and needs to be checked. */ if ((vfstab = setmntent(FSTAB, "r")) != 0) { while ( mnt = getmntent(vfstab)) { if ( !strcmp(mnt->mnt_dir,"/") ) if (stat(mnt->mnt_fsname, &stbr) == 0) if (stbr.st_rdev == stbd.st_rdev) is_root = 1; if ( !strcmp(mnt->mnt_dir,"/usr") ) if (stat(mnt->mnt_fsname, &stbr) == 0) if (stbr.st_rdev == stbd.st_rdev) is_usr = 1; } endmntent(vfstab); } /* XXX - only works if filename is a block device or if character and block device has the same dev_t value */ if (is_root == 0 && is_usr == 0 && ustat(stbd.st_rdev, &usb) == 0) { fprintf(stderr, "hfs fsck: sanity check: %s already mounted\n", filename); exit(33); } /* * We mount the ufs root file system read-only first. After fsck * runs, we remount the root as read-write. Therefore, we no longer * check for different values for fs_state between the root file * system and the rest of file systems. */ if (! ((sblock.fs_clean ==FS_CLEAN || sblock.fs_clean ==FS_OK))) { fprintf(stderr, "hfs fsck: sanity check: %s needs checking\n", filename); exit(32); } fprintf(stderr, "hfs fsck: sanity check: %s okay\n", filename); exit(0); } #endif /* see if all numbers */ numbers(yp) char *yp; { if (yp == NULL) return (0); while ('0' <= *yp && *yp <= '9') yp++; if (*yp) return (0); return (1); } #endif /* Convert a raw device name into a block device name. * If the block device is not found, return the raw device name. * For HP and SUN, the returned value is not changed. For other * platforms it is changed (I see no rhyme or reason -jpm). */ char * unrawname(rawdev) char *rawdev; { static char bldev[256]; struct stat statbuf; int code, i; code = stat(rawdev, &statbuf); if ((code < 0) || !S_ISCHR(statbuf.st_mode)) return(rawdev); /* Not a char device */ for (i=strlen(rawdev)-2; i>=0; i--) { if ((rawdev[i] == '/') && (rawdev[i+1] == 'r')) { strcpy(bldev, rawdev); bldev[i+1] = 0; strcat(bldev, &rawdev[i+2]); code = stat(bldev, &statbuf); /* test for block device */ if (!code && S_ISBLK(statbuf.st_mode)) { #if defined(AFS_HPUX_ENV) || defined(AFS_SUN5_ENV) return(bldev); #else strcpy(rawdev, bldev); /* Replace */ return(rawdev); #endif } } } return(rawdev); } /* Convert a block device name into a raw device name. * If the block device is not found, return null */ char * rawname(bldev) char *bldev; { static char rawdev[256]; struct stat statbuf; int code, i; for (i=strlen(bldev)-1; i>=0; i--) { if (bldev[i] == '/') { strcpy(rawdev, bldev); rawdev[i+1] = 'r'; rawdev[i+2] = 0; strcat(rawdev, &bldev[i+1]); code = stat(rawdev, &statbuf); if (!code && S_ISCHR(statbuf.st_mode)) return(rawdev); } } return (char *)0; }