main.c revision 7585
175374Sbp/* 275374Sbp * Copyright (c) 1980, 1986, 1993 375374Sbp * The Regents of the University of California. All rights reserved. 475374Sbp * 575374Sbp * Redistribution and use in source and binary forms, with or without 675374Sbp * modification, are permitted provided that the following conditions 775374Sbp * are met: 875374Sbp * 1. Redistributions of source code must retain the above copyright 975374Sbp * notice, this list of conditions and the following disclaimer. 1075374Sbp * 2. Redistributions in binary form must reproduce the above copyright 1175374Sbp * notice, this list of conditions and the following disclaimer in the 1275374Sbp * documentation and/or other materials provided with the distribution. 1375374Sbp * 3. All advertising materials mentioning features or use of this software 1475374Sbp * must display the following acknowledgement: 1575374Sbp * This product includes software developed by the University of 1675374Sbp * California, Berkeley and its contributors. 1775374Sbp * 4. Neither the name of the University nor the names of its contributors 1875374Sbp * may be used to endorse or promote products derived from this software 1975374Sbp * without specific prior written permission. 2075374Sbp * 2175374Sbp * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2275374Sbp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2375374Sbp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2475374Sbp * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2575374Sbp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2675374Sbp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2775374Sbp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2875374Sbp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2975374Sbp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3075374Sbp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3175374Sbp * SUCH DAMAGE. 3275374Sbp */ 3375374Sbp 3475374Sbp#ifndef lint 3575374Sbpstatic const char copyright[] = 3675374Sbp"@(#) Copyright (c) 1980, 1986, 1993\n\ 3775374Sbp The Regents of the University of California. All rights reserved.\n"; 3875374Sbp#endif /* not lint */ 3975374Sbp 4075374Sbp#ifndef lint 4175374Sbpstatic const char sccsid[] = "@(#)main.c 8.2 (Berkeley) 1/23/94"; 4275374Sbp#endif /* not lint */ 4375374Sbp 4475374Sbp#include <sys/param.h> 4575374Sbp#include <sys/time.h> 4675374Sbp#include <sys/proc.h> 4775374Sbp#include <sys/mount.h> 4875374Sbp#include <ufs/ufs/dinode.h> 4975374Sbp#include <ufs/ffs/fs.h> 5075374Sbp#include <fstab.h> 5175374Sbp#include <stdlib.h> 5275374Sbp#include <unistd.h> 5375374Sbp#include <string.h> 5475374Sbp#include <ctype.h> 5575374Sbp#include <stdio.h> 5675374Sbp#include "fsck.h" 5775374Sbpstatic int argtoi __P((int flag, char *req, char *str, int base)); 5875374Sbpstatic int docheck __P((struct fstab *fsp)); 5975374Sbpstatic int checkfilesys __P((char *filesys, char *mntpt, long auxdata, 6075374Sbp int child)); 6175374Sbp 6275374Sbpint 6375374Sbpmain(argc, argv) 6475374Sbp int argc; 6575374Sbp char *argv[]; 6675374Sbp{ 6775374Sbp int ch; 6875374Sbp int ret, maxrun = 0; 6975374Sbp extern char *optarg; 7075374Sbp extern int optind; 7175374Sbp 7275374Sbp sync(); 7375374Sbp while ((ch = getopt(argc, argv, "dfpnNyYb:c:l:m:")) != EOF) { 7475374Sbp switch (ch) { 7575374Sbp case 'p': 7675374Sbp preen++; 7775374Sbp break; 7875374Sbp 7975374Sbp case 'b': 8075374Sbp bflag = argtoi('b', "number", optarg, 10); 8188741Sbp printf("Alternate super block location: %d\n", bflag); 8288741Sbp break; 8375374Sbp 8491022Sbp case 'c': 8575374Sbp cvtlevel = argtoi('c', "conversion level", optarg, 10); 8675374Sbp break; 8775374Sbp 8875374Sbp case 'd': 8975374Sbp debug++; 9075374Sbp break; 9175374Sbp 9275374Sbp case 'f': 9375374Sbp fflag++; 9475374Sbp break; 9575374Sbp 9675374Sbp case 'l': 9775374Sbp maxrun = argtoi('l', "number", optarg, 10); 9875374Sbp break; 9975374Sbp 10075374Sbp case 'm': 10175374Sbp lfmode = argtoi('m', "mode", optarg, 8); 10275374Sbp if (lfmode &~ 07777) 10375374Sbp errexit("bad mode to -m: %o\n", lfmode); 10475374Sbp printf("** lost+found creation mode %o\n", lfmode); 10575374Sbp break; 10675374Sbp 10775374Sbp case 'n': 10875374Sbp case 'N': 10975374Sbp nflag++; 11075374Sbp yflag = 0; 11175374Sbp break; 11275374Sbp 11375374Sbp case 'y': 11475374Sbp case 'Y': 11575374Sbp yflag++; 11675374Sbp nflag = 0; 11775374Sbp break; 11888741Sbp 11975374Sbp default: 12075374Sbp errexit("%c option?\n", ch); 12175374Sbp } 12275374Sbp } 12375374Sbp argc -= optind; 12475374Sbp argv += optind; 12575374Sbp if (signal(SIGINT, SIG_IGN) != SIG_IGN) 12675374Sbp (void)signal(SIGINT, catch); 12775374Sbp if (preen) 12875374Sbp (void)signal(SIGQUIT, catchquit); 12975374Sbp if (argc) { 13075374Sbp while (argc-- > 0) 13175374Sbp (void)checkfilesys(blockcheck(*argv++), 0, 0L, 0); 13275374Sbp exit(0); 13375374Sbp } 13475374Sbp ret = checkfstab(preen, maxrun, docheck, checkfilesys); 13575374Sbp if (returntosingle) 13675374Sbp exit(2); 13775374Sbp exit(ret); 13875374Sbp} 13975374Sbp 14075374Sbpint 14175374Sbpargtoi(flag, req, str, base) 14275374Sbp int flag; 14375374Sbp char *req, *str; 14475374Sbp int base; 14575374Sbp{ 14675374Sbp char *cp; 14775374Sbp int ret; 14875374Sbp 14975374Sbp ret = (int)strtol(str, &cp, base); 15075374Sbp if (cp == str || *cp) 15175374Sbp errexit("-%c flag requires a %s\n", flag, req); 15275374Sbp return (ret); 15375374Sbp} 15475374Sbp 15575374Sbp/* 15675374Sbp * Determine whether a filesystem should be checked. 15775374Sbp */ 15875374Sbpint 15975374Sbpdocheck(fsp) 16075374Sbp register struct fstab *fsp; 16175374Sbp{ 16275374Sbp 16375374Sbp if (strcmp(fsp->fs_vfstype, "ufs") || 16475374Sbp (strcmp(fsp->fs_type, FSTAB_RW) && 16575374Sbp strcmp(fsp->fs_type, FSTAB_RO)) || 16675374Sbp fsp->fs_passno == 0) 167102479Sbde return (0); 16875374Sbp return (1); 16975374Sbp} 17075374Sbp 17175374Sbp/* 17275374Sbp * Check the specified filesystem. 17375374Sbp */ 17475374Sbp/* ARGSUSED */ 17575374Sbpint 17675374Sbpcheckfilesys(filesys, mntpt, auxdata, child) 17775374Sbp char *filesys, *mntpt; 17875374Sbp long auxdata; 17975374Sbp int child; 18075374Sbp{ 18175374Sbp daddr_t n_ffree, n_bfree; 18275374Sbp struct dups *dp; 18375374Sbp struct zlncnt *zlnp; 18475374Sbp int cylno; 18575374Sbp 18675374Sbp if (preen && child) 18775374Sbp (void)signal(SIGQUIT, voidquit); 18875374Sbp cdevname = filesys; 18975374Sbp if (debug && preen) 19075374Sbp pwarn("starting\n"); 19175374Sbp if (setup(filesys) == 0) { 19275374Sbp if (preen) 19375374Sbp pfatal("CAN'T CHECK FILE SYSTEM."); 19475374Sbp return (0); 19575374Sbp } 19675374Sbp 19775374Sbp if (preen && sblock.fs_clean && !fflag) { 19875374Sbp pwarn("clean, %ld free ", sblock.fs_cstotal.cs_nffree + 19975374Sbp sblock.fs_frag * sblock.fs_cstotal.cs_nbfree); 20075374Sbp printf("(%ld frags, %ld blocks, %.1f%% fragmentation)\n", 20175374Sbp sblock.fs_cstotal.cs_nffree, 20275374Sbp sblock.fs_cstotal.cs_nbfree, 20375374Sbp (float)(sblock.fs_cstotal.cs_nffree * 100) / 20475374Sbp sblock.fs_dsize); 20575374Sbp return(0); 20675374Sbp } 20775374Sbp 20875374Sbp /* 20975374Sbp * 1: scan inodes tallying blocks used 21075374Sbp */ 21175374Sbp if (preen == 0) { 21275374Sbp printf("** Last Mounted on %s\n", sblock.fs_fsmnt); 21375374Sbp if (hotroot) 21475374Sbp printf("** Root file system\n"); 21575374Sbp printf("** Phase 1 - Check Blocks and Sizes\n"); 21675374Sbp } 21775374Sbp pass1(); 21875374Sbp 21975374Sbp /* 22075374Sbp * 1b: locate first references to duplicates, if any 22175374Sbp */ 22275374Sbp if (duplist) { 22375374Sbp if (preen) 22475374Sbp pfatal("INTERNAL ERROR: dups with -p"); 22575374Sbp printf("** Phase 1b - Rescan For More DUPS\n"); 22675374Sbp pass1b(); 22775374Sbp } 22875374Sbp 22975374Sbp /* 23075374Sbp * 2: traverse directories from root to mark all connected directories 23175374Sbp */ 23275374Sbp if (preen == 0) 23375374Sbp printf("** Phase 2 - Check Pathnames\n"); 23475374Sbp pass2(); 23575374Sbp 23675374Sbp /* 23775374Sbp * 3: scan inodes looking for disconnected directories 23875374Sbp */ 23975374Sbp if (preen == 0) 24075374Sbp printf("** Phase 3 - Check Connectivity\n"); 24175374Sbp pass3(); 24275374Sbp 24375374Sbp /* 24475374Sbp * 4: scan inodes looking for disconnected files; check reference counts 24575374Sbp */ 24675374Sbp if (preen == 0) 24775374Sbp printf("** Phase 4 - Check Reference Counts\n"); 24875374Sbp pass4(); 24975374Sbp 25075374Sbp /* 25175374Sbp * 5: check and repair resource counts in cylinder groups 25275374Sbp */ 25375374Sbp if (preen == 0) 25475374Sbp printf("** Phase 5 - Check Cyl groups\n"); 25575374Sbp pass5(); 25675374Sbp 25775374Sbp /* 25875374Sbp * print out summary statistics 25975374Sbp */ 26075374Sbp n_ffree = sblock.fs_cstotal.cs_nffree; 26175374Sbp n_bfree = sblock.fs_cstotal.cs_nbfree; 26275374Sbp pwarn("%ld files, %ld used, %ld free ", 26375374Sbp n_files, n_blks, n_ffree + sblock.fs_frag * n_bfree); 26475374Sbp printf("(%ld frags, %ld blocks, %ld.%ld%% fragmentation)\n", 26575374Sbp n_ffree, n_bfree, (n_ffree * 100) / sblock.fs_dsize, 26675374Sbp ((n_ffree * 1000 + sblock.fs_dsize / 2) / sblock.fs_dsize) % 10); 26775374Sbp if (debug && 26875374Sbp (n_files -= maxino - ROOTINO - sblock.fs_cstotal.cs_nifree)) 26975374Sbp printf("%ld files missing\n", n_files); 27075374Sbp if (debug) { 27175374Sbp n_blks += sblock.fs_ncg * 27275374Sbp (cgdmin(&sblock, 0) - cgsblock(&sblock, 0)); 27375374Sbp n_blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0); 27475374Sbp n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize); 27575374Sbp if (n_blks -= maxfsblock - (n_ffree + sblock.fs_frag * n_bfree)) 27675374Sbp printf("%ld blocks missing\n", n_blks); 27775374Sbp if (duplist != NULL) { 27875374Sbp printf("The following duplicate blocks remain:"); 27975374Sbp for (dp = duplist; dp; dp = dp->next) 28075374Sbp printf(" %ld,", dp->dup); 28175374Sbp printf("\n"); 28275374Sbp } 28375374Sbp if (zlnhead != NULL) { 28475374Sbp printf("The following zero link count inodes remain:"); 28575374Sbp for (zlnp = zlnhead; zlnp; zlnp = zlnp->next) 28675374Sbp printf(" %lu,", zlnp->zlncnt); 28775374Sbp printf("\n"); 28875374Sbp } 28975374Sbp } 29075374Sbp zlnhead = (struct zlncnt *)0; 29175374Sbp duplist = (struct dups *)0; 29275374Sbp muldup = (struct dups *)0; 29375374Sbp inocleanup(); 29475374Sbp if (fsmodified) { 29575374Sbp (void)time(&sblock.fs_time); 29675374Sbp sbdirty(); 29775374Sbp } 29875374Sbp if (cvtlevel && sblk.b_dirty) { 29975374Sbp /* 30075374Sbp * Write out the duplicate super blocks 30175374Sbp */ 30275374Sbp for (cylno = 0; cylno < sblock.fs_ncg; cylno++) 30375374Sbp bwrite(fswritefd, (char *)&sblock, 30475374Sbp fsbtodb(&sblock, cgsblock(&sblock, cylno)), SBSIZE); 30575374Sbp } 30675374Sbp ckfini(); 30775374Sbp free(blockmap); 30875374Sbp free(statemap); 30975374Sbp free((char *)lncntp); 31075374Sbp if (!fsmodified) 31175374Sbp return (0); 31275374Sbp if (!preen) 31375374Sbp printf("\n***** FILE SYSTEM WAS MODIFIED *****\n"); 31475374Sbp if (hotroot) { 31575374Sbp struct statfs stfs_buf; 31675374Sbp /* 31775374Sbp * We modified the root. Do a mount update on 31875374Sbp * it, unless it is read-write, so we can continue. 31975374Sbp */ 32075374Sbp if (statfs("/", &stfs_buf) == 0) { 32175374Sbp long flags = stfs_buf.f_flags; 32275374Sbp struct ufs_args args; 32375374Sbp int ret; 32475374Sbp 32575374Sbp if (flags & MNT_RDONLY) { 32675374Sbp args.fspec = 0; 32775374Sbp args.export.ex_flags = 0; 32875374Sbp args.export.ex_root = 0; 32975374Sbp flags |= MNT_UPDATE | MNT_RELOAD; 33075374Sbp ret = mount(MOUNT_UFS, "/", flags, &args); 33175374Sbp if (ret == 0) 33275374Sbp return(0); 33375374Sbp } 33475374Sbp } 33575374Sbp if (!preen) 33675374Sbp printf("\n***** REBOOT NOW *****\n"); 33775374Sbp sync(); 33875374Sbp return (4); 33975374Sbp } 34075374Sbp return (0); 34175374Sbp} 34275374Sbp