/* * Copyright 1999 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1980, 1986, 1990 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that: (1) source distributions retain this entire copyright * notice and comment, and (2) distributions including binaries display * the following acknowledgement: ``This product includes software * developed by the University of California, Berkeley and its contributors'' * in the documentation or other materials provided with the distribution * and in all advertising materials mentioning features or use of this * software. Neither the name of the University nor the names of its * contributors may 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. */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include #include /* use isdigit macro rather than 4.1 libc routine */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fsck.h" #include extern int32_t writable(char *); extern void pfatal(char *, ...); extern void printfree(); extern void pwarn(char *, ...); extern void pass1(); extern void dofreemap(); extern void dolvint(); extern char *getfullblkname(); extern char *getfullrawname(); static int mflag = 0; /* sanity check only */ char *mntopt(); void catch(), catchquit(), voidquit(); int returntosingle; static void checkfilesys(); static void check_sanity(); static void usage(); static char *subopts [] = { #define PREEN 0 "p", #define DEBUG 1 "d", #define READ_ONLY 2 "r", #define ONLY_WRITES 3 "w", #define FORCE 4 /* force checking, even if clean */ "f", #define STATS 5 /* print time and busy stats */ "s", NULL }; uint32_t ecma_version = 2; void main(argc, argv) int argc; char *argv[]; { int c; char *suboptions, *value; int suboption; (void) setlocale(LC_ALL, ""); while ((c = getopt(argc, argv, "mnNo:VyYz")) != EOF) { switch (c) { case 'm': mflag++; break; case 'n': /* default no answer flag */ case 'N': nflag++; yflag = 0; break; case 'o': /* * udfs specific options. */ suboptions = optarg; while (*suboptions != '\0') { suboption = getsubopt(&suboptions, subopts, &value); switch (suboption) { case PREEN: preen++; break; case DEBUG: debug++; break; case READ_ONLY: break; case ONLY_WRITES: /* check only writable filesystems */ wflag++; break; case FORCE: fflag++; break; case STATS: sflag++; break; default: usage(); } } break; case 'V': { int opt_count; char *opt_text; (void) fprintf(stdout, "fsck -F udfs "); 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 'y': /* default yes answer flag */ case 'Y': yflag++; nflag = 0; break; case '?': usage(); } } argc -= optind; argv = &argv[optind]; rflag++; /* check raw devices */ if (signal(SIGINT, SIG_IGN) != SIG_IGN) { (void) signal(SIGINT, catch); } if (preen) { (void) signal(SIGQUIT, catchquit); } if (argc) { while (argc-- > 0) { if (wflag && !writable(*argv)) { (void) fprintf(stderr, gettext("not writeable '%s'\n"), *argv); argv++; } else checkfilesys(*argv++); } exit(exitstat); } } static void checkfilesys(filesys) char *filesys; { char *devstr; mountfd = -1; mountedfs = 0; iscorrupt = 1; if ((devstr = setup(filesys)) == 0) { if (iscorrupt == 0) return; if (preen) pfatal(gettext("CAN'T CHECK FILE SYSTEM.")); if ((exitstat == 0) && (mflag)) exitstat = 32; exit(exitstat); } else devname = devstr; if (mflag) check_sanity(filesys); /* this never returns */ iscorrupt = 0; /* * 1: scan inodes tallying blocks used */ if (preen == 0) { if (mountedfs) (void) printf(gettext("** Currently Mounted on %s\n"), mountpoint); if (mflag) { (void) printf( gettext("** Phase 1 - Sanity Check only\n")); return; } else (void) printf( gettext("** Phase 1 - Check Directories " "and Blocks\n")); } pass1(); if (sflag) { if (preen) (void) printf("%s: ", devname); else (void) printf("** "); } if (debug) (void) printf("pass1 isdirty %d\n", isdirty); if (debug) printfree(); dofreemap(); dolvint(); /* * print out summary statistics */ pwarn(gettext("%d files, %d dirs, %d used, %d free\n"), n_files, n_dirs, n_blks, part_len - n_blks); if (iscorrupt) exitstat = 36; if (!fsmodified) return; if (!preen) (void) printf( gettext("\n***** FILE SYSTEM WAS MODIFIED *****\n")); if (mountedfs) { exitstat = 40; } } /* * 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 */ static void 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) { (void) fprintf(stderr, gettext("udfs 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 { (void) fprintf(stderr, gettext("udfs 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) { (void) fprintf(stderr, gettext("udfs fsck: sanity check: %s " "already mounted\n"), filename); exit(33); } if (lvintp->lvid_int_type == LVI_CLOSE) { (void) fprintf(stderr, gettext("udfs fsck: sanity check: %s okay\n"), filename); } else { (void) fprintf(stderr, gettext("udfs fsck: sanity check: %s needs checking\n"), filename); exit(32); } exit(0); } char * unrawname(name) char *name; { char *dp; if ((dp = getfullblkname(name)) == NULL) return (""); return (dp); } char * rawname(name) char *name; { char *dp; if ((dp = getfullrawname(name)) == NULL) return (""); return (dp); } char * hasvfsopt(vfs, opt) register struct vfstab *vfs; register char *opt; { char *f, *opts; static char *tmpopts; if (vfs->vfs_mntopts == NULL) return (NULL); if (tmpopts == 0) { tmpopts = (char *)calloc(256, sizeof (char)); if (tmpopts == 0) return (0); } (void) strncpy(tmpopts, vfs->vfs_mntopts, (sizeof (tmpopts) - 1)); opts = tmpopts; f = mntopt(&opts); for (; *f; f = mntopt(&opts)) { if (strncmp(opt, f, strlen(opt)) == 0) return (f - tmpopts + vfs->vfs_mntopts); } return (NULL); } static void usage() { (void) fprintf(stderr, gettext("udfs usage: fsck [-F udfs] " "[generic options] [-o p,w,s] [special ....]\n")); exit(31+1); }