1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 3*0Sstevel@tonic-gate * Use is subject to license terms. 4*0Sstevel@tonic-gate */ 5*0Sstevel@tonic-gate 6*0Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 7*0Sstevel@tonic-gate /* All Rights Reserved */ 8*0Sstevel@tonic-gate 9*0Sstevel@tonic-gate 10*0Sstevel@tonic-gate /* 11*0Sstevel@tonic-gate * Copyright (c) 1980, 1986, 1990 The Regents of the University of California. 12*0Sstevel@tonic-gate * All rights reserved. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted 15*0Sstevel@tonic-gate * provided that: (1) source distributions retain this entire copyright 16*0Sstevel@tonic-gate * notice and comment, and (2) distributions including binaries display 17*0Sstevel@tonic-gate * the following acknowledgement: ``This product includes software 18*0Sstevel@tonic-gate * developed by the University of California, Berkeley and its contributors'' 19*0Sstevel@tonic-gate * in the documentation or other materials provided with the distribution 20*0Sstevel@tonic-gate * and in all advertising materials mentioning features or use of this 21*0Sstevel@tonic-gate * software. Neither the name of the University nor the names of its 22*0Sstevel@tonic-gate * contributors may be used to endorse or promote products derived 23*0Sstevel@tonic-gate * from this software without specific prior written permission. 24*0Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 25*0Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 26*0Sstevel@tonic-gate * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 27*0Sstevel@tonic-gate */ 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate #include <stdio.h> 32*0Sstevel@tonic-gate #include <sys/param.h> 33*0Sstevel@tonic-gate #include <sys/types.h> 34*0Sstevel@tonic-gate #include <sys/int_types.h> 35*0Sstevel@tonic-gate #include <sys/sysmacros.h> 36*0Sstevel@tonic-gate #include <sys/mntent.h> 37*0Sstevel@tonic-gate 38*0Sstevel@tonic-gate #define bcopy(f, t, n) memcpy(t, f, n) 39*0Sstevel@tonic-gate #define bzero(s, n) memset(s, 0, n) 40*0Sstevel@tonic-gate #define bcmp(s, d, n) memcmp(s, d, n) 41*0Sstevel@tonic-gate 42*0Sstevel@tonic-gate #define index(s, r) strchr(s, r) 43*0Sstevel@tonic-gate #define rindex(s, r) strrchr(s, r) 44*0Sstevel@tonic-gate 45*0Sstevel@tonic-gate #include <sys/fs/ufs_fs.h> 46*0Sstevel@tonic-gate #include <sys/vnode.h> 47*0Sstevel@tonic-gate #include <sys/fs/ufs_inode.h> 48*0Sstevel@tonic-gate #include <sys/stat.h> 49*0Sstevel@tonic-gate #include <sys/wait.h> 50*0Sstevel@tonic-gate #include <sys/mnttab.h> 51*0Sstevel@tonic-gate #include <sys/signal.h> 52*0Sstevel@tonic-gate #include <string.h> 53*0Sstevel@tonic-gate #include <ctype.h> /* use isdigit macro rather than 4.1 libc routine */ 54*0Sstevel@tonic-gate #include "fsck.h" 55*0Sstevel@tonic-gate #include <sys/vfstab.h> 56*0Sstevel@tonic-gate #include <sys/ustat.h> 57*0Sstevel@tonic-gate #include <sys/statvfs.h> 58*0Sstevel@tonic-gate #include <errno.h> 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gate int mflag = 0; /* sanity check only */ 61*0Sstevel@tonic-gate char hotroot; 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate uint_t largefile_count = 0; /* global largefile counter */ 64*0Sstevel@tonic-gate 65*0Sstevel@tonic-gate extern int optind; 66*0Sstevel@tonic-gate extern char *optarg; 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate char *mntopt(); 69*0Sstevel@tonic-gate char *malloc(); 70*0Sstevel@tonic-gate void catch(), catchquit(), voidquit(); 71*0Sstevel@tonic-gate int returntosingle; 72*0Sstevel@tonic-gate void checkfilesys(); 73*0Sstevel@tonic-gate void update_lf(); 74*0Sstevel@tonic-gate void main(); 75*0Sstevel@tonic-gate void check_sanity(); 76*0Sstevel@tonic-gate void usage(); 77*0Sstevel@tonic-gate struct dinode *getnextinode(); 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gate char *subopts [] = { 80*0Sstevel@tonic-gate #define PREEN 0 81*0Sstevel@tonic-gate "p", 82*0Sstevel@tonic-gate #define BLOCK 1 83*0Sstevel@tonic-gate "b", 84*0Sstevel@tonic-gate #define DEBUG 2 85*0Sstevel@tonic-gate "d", 86*0Sstevel@tonic-gate #define READ_ONLY 3 87*0Sstevel@tonic-gate "r", 88*0Sstevel@tonic-gate #define ONLY_WRITES 4 89*0Sstevel@tonic-gate "w", 90*0Sstevel@tonic-gate #define CONVERT 5 /* setup.c convert between fffs and ffs */ 91*0Sstevel@tonic-gate "c", 92*0Sstevel@tonic-gate #define FORCE 6 /* force checking, even if clean */ 93*0Sstevel@tonic-gate "f", 94*0Sstevel@tonic-gate NULL 95*0Sstevel@tonic-gate }; 96*0Sstevel@tonic-gate 97*0Sstevel@tonic-gate char **sargv; 98*0Sstevel@tonic-gate void 99*0Sstevel@tonic-gate main(argc, argv) 100*0Sstevel@tonic-gate int argc; 101*0Sstevel@tonic-gate char *argv[]; 102*0Sstevel@tonic-gate { 103*0Sstevel@tonic-gate int c; 104*0Sstevel@tonic-gate char *suboptions, *value; 105*0Sstevel@tonic-gate int suboption; 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate /* 108*0Sstevel@tonic-gate * Save argv pointer to be used if a hole in a directory's block list 109*0Sstevel@tonic-gate * is found. 110*0Sstevel@tonic-gate */ 111*0Sstevel@tonic-gate sargv = argv; 112*0Sstevel@tonic-gate while ((c = getopt(argc, argv, "mnNo:VyYz")) != EOF) { 113*0Sstevel@tonic-gate switch (c) { 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate case 'm': 116*0Sstevel@tonic-gate mflag++; 117*0Sstevel@tonic-gate break; 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate case 'n': /* default no answer flag */ 120*0Sstevel@tonic-gate case 'N': 121*0Sstevel@tonic-gate nflag++; 122*0Sstevel@tonic-gate yflag = 0; 123*0Sstevel@tonic-gate break; 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate case 'o': 126*0Sstevel@tonic-gate /* 127*0Sstevel@tonic-gate * ufs specific options. 128*0Sstevel@tonic-gate */ 129*0Sstevel@tonic-gate suboptions = optarg; 130*0Sstevel@tonic-gate while (*suboptions != '\0') { 131*0Sstevel@tonic-gate switch ((suboption = getsubopt(&suboptions, 132*0Sstevel@tonic-gate subopts, &value))) { 133*0Sstevel@tonic-gate 134*0Sstevel@tonic-gate case PREEN: 135*0Sstevel@tonic-gate preen++; 136*0Sstevel@tonic-gate break; 137*0Sstevel@tonic-gate 138*0Sstevel@tonic-gate case BLOCK: 139*0Sstevel@tonic-gate if (value == NULL) { 140*0Sstevel@tonic-gate usage(); 141*0Sstevel@tonic-gate } else { 142*0Sstevel@tonic-gate bflag = atoi(value); 143*0Sstevel@tonic-gate } 144*0Sstevel@tonic-gate printf("Alternate super block location: %d.\n", 145*0Sstevel@tonic-gate bflag); 146*0Sstevel@tonic-gate break; 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate case CONVERT: 149*0Sstevel@tonic-gate cvtflag++; 150*0Sstevel@tonic-gate break; 151*0Sstevel@tonic-gate 152*0Sstevel@tonic-gate case DEBUG: 153*0Sstevel@tonic-gate debug++; 154*0Sstevel@tonic-gate break; 155*0Sstevel@tonic-gate 156*0Sstevel@tonic-gate case READ_ONLY: 157*0Sstevel@tonic-gate break; 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate case ONLY_WRITES: 160*0Sstevel@tonic-gate /* check only writable filesystems */ 161*0Sstevel@tonic-gate wflag++; 162*0Sstevel@tonic-gate break; 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate case FORCE: 165*0Sstevel@tonic-gate fflag++; 166*0Sstevel@tonic-gate break; 167*0Sstevel@tonic-gate 168*0Sstevel@tonic-gate default: 169*0Sstevel@tonic-gate usage(); 170*0Sstevel@tonic-gate } 171*0Sstevel@tonic-gate } 172*0Sstevel@tonic-gate break; 173*0Sstevel@tonic-gate 174*0Sstevel@tonic-gate case 'V': 175*0Sstevel@tonic-gate { 176*0Sstevel@tonic-gate int opt_count; 177*0Sstevel@tonic-gate char *opt_text; 178*0Sstevel@tonic-gate 179*0Sstevel@tonic-gate (void) fprintf(stdout, "fsck -F ufs "); 180*0Sstevel@tonic-gate for (opt_count = 1; opt_count < argc; 181*0Sstevel@tonic-gate opt_count++) { 182*0Sstevel@tonic-gate opt_text = argv[opt_count]; 183*0Sstevel@tonic-gate if (opt_text) 184*0Sstevel@tonic-gate (void) fprintf(stdout, " %s ", 185*0Sstevel@tonic-gate opt_text); 186*0Sstevel@tonic-gate } 187*0Sstevel@tonic-gate (void) fprintf(stdout, "\n"); 188*0Sstevel@tonic-gate } 189*0Sstevel@tonic-gate break; 190*0Sstevel@tonic-gate 191*0Sstevel@tonic-gate case 'y': /* default yes answer flag */ 192*0Sstevel@tonic-gate case 'Y': 193*0Sstevel@tonic-gate yflag++; 194*0Sstevel@tonic-gate nflag = 0; 195*0Sstevel@tonic-gate break; 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate case '?': 198*0Sstevel@tonic-gate usage(); 199*0Sstevel@tonic-gate } 200*0Sstevel@tonic-gate } 201*0Sstevel@tonic-gate argc -= optind; 202*0Sstevel@tonic-gate argv = &argv[optind]; 203*0Sstevel@tonic-gate rflag++; /* check raw devices */ 204*0Sstevel@tonic-gate if (signal(SIGINT, SIG_IGN) != (int)SIG_IGN) 205*0Sstevel@tonic-gate (void) signal(SIGINT, catch); 206*0Sstevel@tonic-gate if (preen) 207*0Sstevel@tonic-gate (void) signal(SIGQUIT, catchquit); 208*0Sstevel@tonic-gate 209*0Sstevel@tonic-gate if (argc) { 210*0Sstevel@tonic-gate while (argc-- > 0) { 211*0Sstevel@tonic-gate if (wflag && !writable(*argv)) { 212*0Sstevel@tonic-gate (void) fprintf(stderr, "not writeable '%s'\n", 213*0Sstevel@tonic-gate *argv); 214*0Sstevel@tonic-gate argv++; 215*0Sstevel@tonic-gate } else 216*0Sstevel@tonic-gate checkfilesys(*argv++); 217*0Sstevel@tonic-gate } 218*0Sstevel@tonic-gate exit(exitstat); 219*0Sstevel@tonic-gate } 220*0Sstevel@tonic-gate } 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gate 223*0Sstevel@tonic-gate void 224*0Sstevel@tonic-gate checkfilesys(filesys) 225*0Sstevel@tonic-gate char *filesys; 226*0Sstevel@tonic-gate { 227*0Sstevel@tonic-gate daddr32_t n_ffree, n_bfree; 228*0Sstevel@tonic-gate struct dups *dp; 229*0Sstevel@tonic-gate struct zlncnt *zlnp; 230*0Sstevel@tonic-gate char *devstr; 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate mountfd = -1; 233*0Sstevel@tonic-gate hotroot = 0; 234*0Sstevel@tonic-gate mountedfs = 0; 235*0Sstevel@tonic-gate iscorrupt = 1; 236*0Sstevel@tonic-gate isconvert = 0; 237*0Sstevel@tonic-gate ismdd = 0; 238*0Sstevel@tonic-gate islog = 0; 239*0Sstevel@tonic-gate islogok = 0; 240*0Sstevel@tonic-gate dirholes = 0; 241*0Sstevel@tonic-gate needs_reclaim = 0; 242*0Sstevel@tonic-gate errorlocked = is_errorlocked(filesys); 243*0Sstevel@tonic-gate 244*0Sstevel@tonic-gate if ((devstr = setup(filesys)) == 0) { 245*0Sstevel@tonic-gate if (iscorrupt == 0) 246*0Sstevel@tonic-gate return; 247*0Sstevel@tonic-gate if (preen) 248*0Sstevel@tonic-gate pfatal("CAN'T CHECK FILE SYSTEM."); 249*0Sstevel@tonic-gate if ((exitstat == 0) && (mflag)) 250*0Sstevel@tonic-gate exitstat = 32; 251*0Sstevel@tonic-gate exit(exitstat); 252*0Sstevel@tonic-gate } 253*0Sstevel@tonic-gate else 254*0Sstevel@tonic-gate devname = devstr; 255*0Sstevel@tonic-gate if (mflag) 256*0Sstevel@tonic-gate check_sanity(filesys); /* this never returns */ 257*0Sstevel@tonic-gate if (debug) 258*0Sstevel@tonic-gate printclean(); 259*0Sstevel@tonic-gate iscorrupt = 0; 260*0Sstevel@tonic-gate /* 261*0Sstevel@tonic-gate * 1: scan inodes tallying blocks used 262*0Sstevel@tonic-gate */ 263*0Sstevel@tonic-gate if (preen == 0) { 264*0Sstevel@tonic-gate if (mountedfs) 265*0Sstevel@tonic-gate printf("** Currently Mounted on %s\n", sblock.fs_fsmnt); 266*0Sstevel@tonic-gate else 267*0Sstevel@tonic-gate printf("** Last Mounted on %s\n", sblock.fs_fsmnt); 268*0Sstevel@tonic-gate if (mflag) { 269*0Sstevel@tonic-gate printf("** Phase 1 - Sanity Check only\n"); 270*0Sstevel@tonic-gate return; 271*0Sstevel@tonic-gate } else { 272*0Sstevel@tonic-gate printf("** Phase 1 - Check Blocks and Sizes\n"); 273*0Sstevel@tonic-gate } 274*0Sstevel@tonic-gate } 275*0Sstevel@tonic-gate pass1(); 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate /* 278*0Sstevel@tonic-gate * 1b: locate first references to duplicates, if any 279*0Sstevel@tonic-gate */ 280*0Sstevel@tonic-gate if (duplist) { 281*0Sstevel@tonic-gate if (preen) 282*0Sstevel@tonic-gate pfatal("INTERNAL ERROR: dups with -p"); 283*0Sstevel@tonic-gate printf("** Phase 1b - Rescan For More DUPS\n"); 284*0Sstevel@tonic-gate pass1b(); 285*0Sstevel@tonic-gate } 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate /* 288*0Sstevel@tonic-gate * 2: traverse directories from root to mark all connected directories 289*0Sstevel@tonic-gate */ 290*0Sstevel@tonic-gate if (preen == 0) { 291*0Sstevel@tonic-gate printf("** Phase 2 - Check Pathnames\n"); 292*0Sstevel@tonic-gate } 293*0Sstevel@tonic-gate pass2(); 294*0Sstevel@tonic-gate 295*0Sstevel@tonic-gate /* 296*0Sstevel@tonic-gate * 3: scan inodes looking for disconnected directories 297*0Sstevel@tonic-gate */ 298*0Sstevel@tonic-gate if (preen == 0) { 299*0Sstevel@tonic-gate printf("** Phase 3 - Check Connectivity\n"); 300*0Sstevel@tonic-gate } 301*0Sstevel@tonic-gate pass3(); 302*0Sstevel@tonic-gate 303*0Sstevel@tonic-gate /* 304*0Sstevel@tonic-gate * 3b: check acls 305*0Sstevel@tonic-gate */ 306*0Sstevel@tonic-gate pass3b(); 307*0Sstevel@tonic-gate 308*0Sstevel@tonic-gate /* 309*0Sstevel@tonic-gate * 4: scan inodes looking for disconnected files; check reference counts 310*0Sstevel@tonic-gate */ 311*0Sstevel@tonic-gate if (preen == 0) { 312*0Sstevel@tonic-gate printf("** Phase 4 - Check Reference Counts\n"); 313*0Sstevel@tonic-gate } 314*0Sstevel@tonic-gate pass4(); 315*0Sstevel@tonic-gate 316*0Sstevel@tonic-gate /* 317*0Sstevel@tonic-gate * 5: check and repair resource counts in cylinder groups 318*0Sstevel@tonic-gate */ 319*0Sstevel@tonic-gate if (preen == 0) { 320*0Sstevel@tonic-gate printf("** Phase 5 - Check Cyl groups\n"); 321*0Sstevel@tonic-gate } 322*0Sstevel@tonic-gate pass5(); 323*0Sstevel@tonic-gate 324*0Sstevel@tonic-gate updateclean(); 325*0Sstevel@tonic-gate if (debug) 326*0Sstevel@tonic-gate printclean(); 327*0Sstevel@tonic-gate 328*0Sstevel@tonic-gate /* 329*0Sstevel@tonic-gate * print out summary statistics 330*0Sstevel@tonic-gate */ 331*0Sstevel@tonic-gate n_ffree = sblock.fs_cstotal.cs_nffree; 332*0Sstevel@tonic-gate n_bfree = sblock.fs_cstotal.cs_nbfree; 333*0Sstevel@tonic-gate pwarn("%d files, %d used, %d free ", 334*0Sstevel@tonic-gate n_files, n_blks, n_ffree + sblock.fs_frag * n_bfree); 335*0Sstevel@tonic-gate if (preen) 336*0Sstevel@tonic-gate printf("\n"); 337*0Sstevel@tonic-gate pwarn("(%d frags, %d blocks, %.1f%% fragmentation)\n", 338*0Sstevel@tonic-gate n_ffree, n_bfree, (float)(n_ffree * 100) / sblock.fs_dsize); 339*0Sstevel@tonic-gate if (debug && 340*0Sstevel@tonic-gate (n_files -= maxino - UFSROOTINO - sblock.fs_cstotal.cs_nifree)) 341*0Sstevel@tonic-gate printf("%d files missing\n", n_files); 342*0Sstevel@tonic-gate if (debug) { 343*0Sstevel@tonic-gate n_blks += sblock.fs_ncg * 344*0Sstevel@tonic-gate (cgdmin(&sblock, 0) - cgsblock(&sblock, 0)); 345*0Sstevel@tonic-gate n_blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0); 346*0Sstevel@tonic-gate n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize); 347*0Sstevel@tonic-gate if (n_blks -= maxfsblock - (n_ffree + sblock.fs_frag * n_bfree)) 348*0Sstevel@tonic-gate printf("%d blocks missing\n", n_blks); 349*0Sstevel@tonic-gate if (duplist != NULL) { 350*0Sstevel@tonic-gate printf("The following duplicate blocks remain:"); 351*0Sstevel@tonic-gate for (dp = duplist; dp; dp = dp->next) 352*0Sstevel@tonic-gate printf(" %d,", dp->dup); 353*0Sstevel@tonic-gate printf("\n"); 354*0Sstevel@tonic-gate } 355*0Sstevel@tonic-gate if (zlnhead != NULL) { 356*0Sstevel@tonic-gate printf("The following zero link count inodes remain:"); 357*0Sstevel@tonic-gate for (zlnp = zlnhead; zlnp; zlnp = zlnp->next) 358*0Sstevel@tonic-gate printf(" %d,", zlnp->zlncnt); 359*0Sstevel@tonic-gate printf("\n"); 360*0Sstevel@tonic-gate } 361*0Sstevel@tonic-gate } 362*0Sstevel@tonic-gate zlnhead = (struct zlncnt *)0; 363*0Sstevel@tonic-gate duplist = muldup = (struct dups *)0; 364*0Sstevel@tonic-gate inocleanup(); 365*0Sstevel@tonic-gate ckfini(); 366*0Sstevel@tonic-gate free(blockmap); 367*0Sstevel@tonic-gate free(statemap); 368*0Sstevel@tonic-gate free((char *)lncntp); 369*0Sstevel@tonic-gate lncntp = NULL; 370*0Sstevel@tonic-gate blockmap = statemap = NULL; 371*0Sstevel@tonic-gate if (iscorrupt) 372*0Sstevel@tonic-gate exitstat = 36; 373*0Sstevel@tonic-gate if (!fsmodified) 374*0Sstevel@tonic-gate return; 375*0Sstevel@tonic-gate if (!preen) 376*0Sstevel@tonic-gate printf("\n***** FILE SYSTEM WAS MODIFIED *****\n"); 377*0Sstevel@tonic-gate 378*0Sstevel@tonic-gate if (dirholes) { 379*0Sstevel@tonic-gate 380*0Sstevel@tonic-gate if (preen) { 381*0Sstevel@tonic-gate printf("\nFixed directory holes, Re-checking %s\n", 382*0Sstevel@tonic-gate devname); 383*0Sstevel@tonic-gate execv("/usr/sbin/fsck", sargv); 384*0Sstevel@tonic-gate printf("Exec failed %s\n", strerror(errno)); 385*0Sstevel@tonic-gate } 386*0Sstevel@tonic-gate 387*0Sstevel@tonic-gate printf("\nFixed directories with holes, Run fsck once again\n"); 388*0Sstevel@tonic-gate exitstat = 36; 389*0Sstevel@tonic-gate } else { 390*0Sstevel@tonic-gate if ((mountedfs && !errorlocked) || hotroot) { 391*0Sstevel@tonic-gate exitstat = 40; 392*0Sstevel@tonic-gate } 393*0Sstevel@tonic-gate } 394*0Sstevel@tonic-gate } 395*0Sstevel@tonic-gate 396*0Sstevel@tonic-gate 397*0Sstevel@tonic-gate /* 398*0Sstevel@tonic-gate * exit 0 - file system is unmounted and okay 399*0Sstevel@tonic-gate * exit 32 - file system is unmounted and needs checking 400*0Sstevel@tonic-gate * exit 33 - file system is mounted 401*0Sstevel@tonic-gate * for root file system 402*0Sstevel@tonic-gate * exit 34 - cannot stat device 403*0Sstevel@tonic-gate */ 404*0Sstevel@tonic-gate 405*0Sstevel@tonic-gate void 406*0Sstevel@tonic-gate check_sanity(filename) 407*0Sstevel@tonic-gate char *filename; 408*0Sstevel@tonic-gate { 409*0Sstevel@tonic-gate struct stat64 stbd, stbr; 410*0Sstevel@tonic-gate struct ustat usb; 411*0Sstevel@tonic-gate char *devname; 412*0Sstevel@tonic-gate char vfsfilename[MAXPATHLEN]; 413*0Sstevel@tonic-gate struct vfstab vfsbuf; 414*0Sstevel@tonic-gate FILE *vfstab; 415*0Sstevel@tonic-gate struct statvfs vfs_stat; 416*0Sstevel@tonic-gate int is_root = 0; 417*0Sstevel@tonic-gate int is_usr = 0; 418*0Sstevel@tonic-gate int is_block = 0; 419*0Sstevel@tonic-gate 420*0Sstevel@tonic-gate if (stat64(filename, &stbd) < 0) { 421*0Sstevel@tonic-gate fprintf(stderr, 422*0Sstevel@tonic-gate "ufs fsck: sanity check failed : cannot stat %s\n", filename); 423*0Sstevel@tonic-gate exit(34); 424*0Sstevel@tonic-gate } 425*0Sstevel@tonic-gate 426*0Sstevel@tonic-gate if ((stbd.st_mode & S_IFMT) == S_IFBLK) 427*0Sstevel@tonic-gate is_block = 1; 428*0Sstevel@tonic-gate else if ((stbd.st_mode & S_IFMT) == S_IFCHR) 429*0Sstevel@tonic-gate is_block = 0; 430*0Sstevel@tonic-gate else { 431*0Sstevel@tonic-gate fprintf(stderr, 432*0Sstevel@tonic-gate "ufs fsck: sanity check failed: %s not block or character device\n", 433*0Sstevel@tonic-gate filename); 434*0Sstevel@tonic-gate exit(34); 435*0Sstevel@tonic-gate } 436*0Sstevel@tonic-gate 437*0Sstevel@tonic-gate /* 438*0Sstevel@tonic-gate * Determine if this is the root file system via vfstab. Give up 439*0Sstevel@tonic-gate * silently on failures. The whole point of this is not to care 440*0Sstevel@tonic-gate * if the root file system is already mounted. 441*0Sstevel@tonic-gate * 442*0Sstevel@tonic-gate * XXX - similar for /usr. This should be fixed to simply return 443*0Sstevel@tonic-gate * a new code indicating, mounted and needs to be checked. 444*0Sstevel@tonic-gate */ 445*0Sstevel@tonic-gate if ((vfstab = fopen(VFSTAB, "r")) != 0) { 446*0Sstevel@tonic-gate if (getvfsfile(vfstab, &vfsbuf, "/") == 0) { 447*0Sstevel@tonic-gate if (is_block) 448*0Sstevel@tonic-gate devname = vfsbuf.vfs_special; 449*0Sstevel@tonic-gate else 450*0Sstevel@tonic-gate devname = vfsbuf.vfs_fsckdev; 451*0Sstevel@tonic-gate if (stat64(devname, &stbr) == 0) 452*0Sstevel@tonic-gate if (stbr.st_rdev == stbd.st_rdev) 453*0Sstevel@tonic-gate is_root = 1; 454*0Sstevel@tonic-gate } 455*0Sstevel@tonic-gate if (getvfsfile(vfstab, &vfsbuf, "/usr") == 0) { 456*0Sstevel@tonic-gate if (is_block) 457*0Sstevel@tonic-gate devname = vfsbuf.vfs_special; 458*0Sstevel@tonic-gate else 459*0Sstevel@tonic-gate devname = vfsbuf.vfs_fsckdev; 460*0Sstevel@tonic-gate if (stat64(devname, &stbr) == 0) 461*0Sstevel@tonic-gate if (stbr.st_rdev == stbd.st_rdev) 462*0Sstevel@tonic-gate is_usr = 1; 463*0Sstevel@tonic-gate } 464*0Sstevel@tonic-gate } 465*0Sstevel@tonic-gate 466*0Sstevel@tonic-gate 467*0Sstevel@tonic-gate /* 468*0Sstevel@tonic-gate * XXX - only works if filename is a block device or if 469*0Sstevel@tonic-gate * character and block device has the same dev_t value 470*0Sstevel@tonic-gate */ 471*0Sstevel@tonic-gate if (is_root == 0 && is_usr == 0 && ustat(stbd.st_rdev, &usb) == 0) { 472*0Sstevel@tonic-gate fprintf(stderr, "ufs fsck: sanity check: %s already mounted\n", 473*0Sstevel@tonic-gate filename); 474*0Sstevel@tonic-gate exit(33); 475*0Sstevel@tonic-gate } 476*0Sstevel@tonic-gate 477*0Sstevel@tonic-gate if (is_root || is_usr) { 478*0Sstevel@tonic-gate if (is_root) 479*0Sstevel@tonic-gate strcpy(vfsfilename, "/"); 480*0Sstevel@tonic-gate else 481*0Sstevel@tonic-gate strcpy(vfsfilename, "/usr"); 482*0Sstevel@tonic-gate if (statvfs(vfsfilename, &vfs_stat) != 0) { 483*0Sstevel@tonic-gate fprintf(stderr, 484*0Sstevel@tonic-gate "ufs fsck: Cannot stat %s\n", 485*0Sstevel@tonic-gate vfsfilename); 486*0Sstevel@tonic-gate exit(34); 487*0Sstevel@tonic-gate } 488*0Sstevel@tonic-gate 489*0Sstevel@tonic-gate if (!(vfs_stat.f_flag & ST_RDONLY)) { 490*0Sstevel@tonic-gate /* 491*0Sstevel@tonic-gate * The file system is mounted read/write 492*0Sstevel@tonic-gate * We need to exit saying that / or /usr is 493*0Sstevel@tonic-gate * already mounted read/write. If it's only 494*0Sstevel@tonic-gate * mounted readonly, we can continue. 495*0Sstevel@tonic-gate */ 496*0Sstevel@tonic-gate 497*0Sstevel@tonic-gate fprintf(stderr, 498*0Sstevel@tonic-gate "ufs fsck: sanity check:" 499*0Sstevel@tonic-gate "%s already mounted read/write\n", 500*0Sstevel@tonic-gate filename); 501*0Sstevel@tonic-gate exit(33); 502*0Sstevel@tonic-gate } 503*0Sstevel@tonic-gate } 504*0Sstevel@tonic-gate 505*0Sstevel@tonic-gate /* 506*0Sstevel@tonic-gate * We mount the ufs root file system read-only first. After fsck 507*0Sstevel@tonic-gate * runs, we remount the root as read-write. Therefore, we no longer 508*0Sstevel@tonic-gate * check for different values for fs_state between the root file 509*0Sstevel@tonic-gate * system and the rest of file systems. 510*0Sstevel@tonic-gate */ 511*0Sstevel@tonic-gate if (islog && !islogok) { 512*0Sstevel@tonic-gate fprintf(stderr, "ufs fsck: sanity check: %s needs checking\n", 513*0Sstevel@tonic-gate filename); 514*0Sstevel@tonic-gate exit(32); 515*0Sstevel@tonic-gate } 516*0Sstevel@tonic-gate if ((sblock.fs_state + (long)sblock.fs_time == FSOKAY) && 517*0Sstevel@tonic-gate (sblock.fs_clean == FSCLEAN || sblock.fs_clean == FSSTABLE || 518*0Sstevel@tonic-gate (sblock.fs_clean == FSLOG && islog))) { 519*0Sstevel@tonic-gate fprintf(stderr, "ufs fsck: sanity check: %s okay\n", filename); 520*0Sstevel@tonic-gate } else { 521*0Sstevel@tonic-gate fprintf(stderr, "ufs fsck: sanity check: %s needs checking\n", 522*0Sstevel@tonic-gate filename); 523*0Sstevel@tonic-gate exit(32); 524*0Sstevel@tonic-gate } 525*0Sstevel@tonic-gate exit(0); 526*0Sstevel@tonic-gate } 527*0Sstevel@tonic-gate 528*0Sstevel@tonic-gate char * 529*0Sstevel@tonic-gate unrawname(name) 530*0Sstevel@tonic-gate char *name; 531*0Sstevel@tonic-gate { 532*0Sstevel@tonic-gate char *dp; 533*0Sstevel@tonic-gate 534*0Sstevel@tonic-gate extern char *getfullblkname(); 535*0Sstevel@tonic-gate 536*0Sstevel@tonic-gate if ((dp = getfullblkname(name)) == NULL) 537*0Sstevel@tonic-gate return (""); 538*0Sstevel@tonic-gate return (dp); 539*0Sstevel@tonic-gate } 540*0Sstevel@tonic-gate 541*0Sstevel@tonic-gate char * 542*0Sstevel@tonic-gate rawname(name) 543*0Sstevel@tonic-gate char *name; 544*0Sstevel@tonic-gate { 545*0Sstevel@tonic-gate char *dp; 546*0Sstevel@tonic-gate 547*0Sstevel@tonic-gate extern char *getfullrawname(); 548*0Sstevel@tonic-gate 549*0Sstevel@tonic-gate if ((dp = getfullrawname(name)) == NULL) 550*0Sstevel@tonic-gate return (""); 551*0Sstevel@tonic-gate return (dp); 552*0Sstevel@tonic-gate } 553*0Sstevel@tonic-gate 554*0Sstevel@tonic-gate char * 555*0Sstevel@tonic-gate hasvfsopt(vfs, opt) 556*0Sstevel@tonic-gate struct vfstab *vfs; 557*0Sstevel@tonic-gate char *opt; 558*0Sstevel@tonic-gate { 559*0Sstevel@tonic-gate char *f, *opts; 560*0Sstevel@tonic-gate static char *tmpopts; 561*0Sstevel@tonic-gate 562*0Sstevel@tonic-gate if (vfs->vfs_mntopts == NULL) 563*0Sstevel@tonic-gate return (NULL); 564*0Sstevel@tonic-gate if (tmpopts == 0) { 565*0Sstevel@tonic-gate tmpopts = (char *)calloc(256, sizeof (char)); 566*0Sstevel@tonic-gate if (tmpopts == 0) 567*0Sstevel@tonic-gate return (0); 568*0Sstevel@tonic-gate } 569*0Sstevel@tonic-gate strncpy(tmpopts, vfs->vfs_mntopts, (sizeof (tmpopts) - 1)); 570*0Sstevel@tonic-gate opts = tmpopts; 571*0Sstevel@tonic-gate f = mntopt(&opts); 572*0Sstevel@tonic-gate for (; *f; f = mntopt(&opts)) { 573*0Sstevel@tonic-gate if (strncmp(opt, f, strlen(opt)) == 0) 574*0Sstevel@tonic-gate return (f - tmpopts + vfs->vfs_mntopts); 575*0Sstevel@tonic-gate } 576*0Sstevel@tonic-gate return (NULL); 577*0Sstevel@tonic-gate } 578*0Sstevel@tonic-gate 579*0Sstevel@tonic-gate 580*0Sstevel@tonic-gate void 581*0Sstevel@tonic-gate usage() 582*0Sstevel@tonic-gate { 583*0Sstevel@tonic-gate (void) fprintf(stderr, 584*0Sstevel@tonic-gate "ufs usage: fsck [-F ufs] [generic options] [-o p,b=#,c,w] [special ....]\n"); 585*0Sstevel@tonic-gate exit(31+1); 586*0Sstevel@tonic-gate } 587