1 /* 2 * Copyright 1999 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 7 /* All Rights Reserved */ 8 9 /* 10 * Copyright (c) 1980, 1986, 1990 The Regents of the University of California. 11 * All rights reserved. 12 * 13 * Redistribution and use in source and binary forms are permitted 14 * provided that: (1) source distributions retain this entire copyright 15 * notice and comment, and (2) distributions including binaries display 16 * the following acknowledgement: ``This product includes software 17 * developed by the University of California, Berkeley and its contributors'' 18 * in the documentation or other materials provided with the distribution 19 * and in all advertising materials mentioning features or use of this 20 * software. Neither the name of the University nor the names of its 21 * contributors may be used to endorse or promote products derived 22 * from this software without specific prior written permission. 23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 26 */ 27 28 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 #include <stdio.h> 31 #include <string.h> 32 #include <ctype.h> /* use isdigit macro rather than 4.1 libc routine */ 33 #include <unistd.h> 34 #include <stdlib.h> 35 #include <signal.h> 36 #include <malloc.h> 37 #include <ustat.h> 38 #include <sys/param.h> 39 #include <sys/types.h> 40 #include <sys/sysmacros.h> 41 #include <sys/mntent.h> 42 #include <sys/vnode.h> 43 #include <sys/stat.h> 44 #include <sys/wait.h> 45 #include <sys/mnttab.h> 46 #include <sys/signal.h> 47 #include <sys/vfstab.h> 48 #include <sys/fs/udf_volume.h> 49 #include "fsck.h" 50 #include <locale.h> 51 52 extern int32_t writable(char *); 53 extern void pfatal(char *, ...); 54 extern void printfree(); 55 extern void pwarn(char *, ...); 56 57 extern void pass1(); 58 extern void dofreemap(); 59 extern void dolvint(); 60 extern char *getfullblkname(); 61 extern char *getfullrawname(); 62 63 static int mflag = 0; /* sanity check only */ 64 65 char *mntopt(); 66 void catch(), catchquit(), voidquit(); 67 int returntosingle; 68 static void checkfilesys(); 69 static void check_sanity(); 70 static void usage(); 71 72 static char *subopts [] = { 73 #define PREEN 0 74 "p", 75 #define DEBUG 1 76 "d", 77 #define READ_ONLY 2 78 "r", 79 #define ONLY_WRITES 3 80 "w", 81 #define FORCE 4 /* force checking, even if clean */ 82 "f", 83 #define STATS 5 /* print time and busy stats */ 84 "s", 85 NULL 86 }; 87 88 uint32_t ecma_version = 2; 89 90 void 91 main(argc, argv) 92 int argc; 93 char *argv[]; 94 { 95 int c; 96 char *suboptions, *value; 97 int suboption; 98 99 (void) setlocale(LC_ALL, ""); 100 101 while ((c = getopt(argc, argv, "mnNo:VyYz")) != EOF) { 102 switch (c) { 103 104 case 'm': 105 mflag++; 106 break; 107 108 case 'n': /* default no answer flag */ 109 case 'N': 110 nflag++; 111 yflag = 0; 112 break; 113 114 case 'o': 115 /* 116 * udfs specific options. 117 */ 118 suboptions = optarg; 119 while (*suboptions != '\0') { 120 suboption = getsubopt(&suboptions, 121 subopts, &value); 122 switch (suboption) { 123 124 case PREEN: 125 preen++; 126 break; 127 128 case DEBUG: 129 debug++; 130 break; 131 132 case READ_ONLY: 133 break; 134 135 case ONLY_WRITES: 136 /* check only writable filesystems */ 137 wflag++; 138 break; 139 140 case FORCE: 141 fflag++; 142 break; 143 144 case STATS: 145 sflag++; 146 break; 147 148 default: 149 usage(); 150 } 151 } 152 break; 153 154 case 'V': 155 { 156 int opt_count; 157 char *opt_text; 158 159 (void) fprintf(stdout, "fsck -F udfs "); 160 for (opt_count = 1; opt_count < argc; 161 opt_count++) { 162 opt_text = argv[opt_count]; 163 if (opt_text) 164 (void) fprintf(stdout, " %s ", 165 opt_text); 166 } 167 (void) fprintf(stdout, "\n"); 168 } 169 break; 170 171 case 'y': /* default yes answer flag */ 172 case 'Y': 173 yflag++; 174 nflag = 0; 175 break; 176 177 case '?': 178 usage(); 179 } 180 } 181 argc -= optind; 182 argv = &argv[optind]; 183 rflag++; /* check raw devices */ 184 if (signal(SIGINT, SIG_IGN) != SIG_IGN) { 185 (void) signal(SIGINT, catch); 186 } 187 188 if (preen) { 189 (void) signal(SIGQUIT, catchquit); 190 } 191 192 if (argc) { 193 while (argc-- > 0) { 194 if (wflag && !writable(*argv)) { 195 (void) fprintf(stderr, 196 gettext("not writeable '%s'\n"), *argv); 197 argv++; 198 } else 199 checkfilesys(*argv++); 200 } 201 exit(exitstat); 202 } 203 } 204 205 206 static void 207 checkfilesys(filesys) 208 char *filesys; 209 { 210 char *devstr; 211 212 mountfd = -1; 213 mountedfs = 0; 214 iscorrupt = 1; 215 216 if ((devstr = setup(filesys)) == 0) { 217 if (iscorrupt == 0) 218 return; 219 if (preen) 220 pfatal(gettext("CAN'T CHECK FILE SYSTEM.")); 221 if ((exitstat == 0) && (mflag)) 222 exitstat = 32; 223 exit(exitstat); 224 } 225 else 226 devname = devstr; 227 if (mflag) 228 check_sanity(filesys); /* this never returns */ 229 iscorrupt = 0; 230 /* 231 * 1: scan inodes tallying blocks used 232 */ 233 if (preen == 0) { 234 if (mountedfs) 235 (void) printf(gettext("** Currently Mounted on %s\n"), 236 mountpoint); 237 if (mflag) { 238 (void) printf( 239 gettext("** Phase 1 - Sanity Check only\n")); 240 return; 241 } else 242 (void) printf( 243 gettext("** Phase 1 - Check Directories " 244 "and Blocks\n")); 245 } 246 pass1(); 247 if (sflag) { 248 if (preen) 249 (void) printf("%s: ", devname); 250 else 251 (void) printf("** "); 252 } 253 if (debug) 254 (void) printf("pass1 isdirty %d\n", isdirty); 255 if (debug) 256 printfree(); 257 dofreemap(); 258 dolvint(); 259 260 /* 261 * print out summary statistics 262 */ 263 pwarn(gettext("%d files, %d dirs, %d used, %d free\n"), n_files, n_dirs, 264 n_blks, part_len - n_blks); 265 if (iscorrupt) 266 exitstat = 36; 267 if (!fsmodified) 268 return; 269 if (!preen) 270 (void) printf( 271 gettext("\n***** FILE SYSTEM WAS MODIFIED *****\n")); 272 273 if (mountedfs) { 274 exitstat = 40; 275 } 276 } 277 278 279 /* 280 * exit 0 - file system is unmounted and okay 281 * exit 32 - file system is unmounted and needs checking 282 * exit 33 - file system is mounted 283 * for root file system 284 * exit 34 - cannot stat device 285 */ 286 287 static void 288 check_sanity(filename) 289 char *filename; 290 { 291 struct stat stbd, stbr; 292 struct ustat usb; 293 char *devname; 294 struct vfstab vfsbuf; 295 FILE *vfstab; 296 int is_root = 0; 297 int is_usr = 0; 298 int is_block = 0; 299 300 if (stat(filename, &stbd) < 0) { 301 (void) fprintf(stderr, 302 gettext("udfs fsck: sanity check failed : cannot stat " 303 "%s\n"), filename); 304 exit(34); 305 } 306 307 if ((stbd.st_mode & S_IFMT) == S_IFBLK) 308 is_block = 1; 309 else if ((stbd.st_mode & S_IFMT) == S_IFCHR) 310 is_block = 0; 311 else { 312 (void) fprintf(stderr, 313 gettext("udfs fsck: sanity check failed: %s not " 314 "block or character device\n"), filename); 315 exit(34); 316 } 317 318 /* 319 * Determine if this is the root file system via vfstab. Give up 320 * silently on failures. The whole point of this is not to care 321 * if the root file system is already mounted. 322 * 323 * XXX - similar for /usr. This should be fixed to simply return 324 * a new code indicating, mounted and needs to be checked. 325 */ 326 if ((vfstab = fopen(VFSTAB, "r")) != 0) { 327 if (getvfsfile(vfstab, &vfsbuf, "/") == 0) { 328 if (is_block) 329 devname = vfsbuf.vfs_special; 330 else 331 devname = vfsbuf.vfs_fsckdev; 332 if (stat(devname, &stbr) == 0) 333 if (stbr.st_rdev == stbd.st_rdev) 334 is_root = 1; 335 } 336 if (getvfsfile(vfstab, &vfsbuf, "/usr") == 0) { 337 if (is_block) 338 devname = vfsbuf.vfs_special; 339 else 340 devname = vfsbuf.vfs_fsckdev; 341 if (stat(devname, &stbr) == 0) 342 if (stbr.st_rdev == stbd.st_rdev) 343 is_usr = 1; 344 } 345 } 346 347 348 /* 349 * XXX - only works if filename is a block device or if 350 * character and block device has the same dev_t value 351 */ 352 if (is_root == 0 && is_usr == 0 && ustat(stbd.st_rdev, &usb) == 0) { 353 (void) fprintf(stderr, 354 gettext("udfs fsck: sanity check: %s " 355 "already mounted\n"), filename); 356 exit(33); 357 } 358 359 if (lvintp->lvid_int_type == LVI_CLOSE) { 360 (void) fprintf(stderr, 361 gettext("udfs fsck: sanity check: %s okay\n"), 362 filename); 363 } else { 364 (void) fprintf(stderr, 365 gettext("udfs fsck: sanity check: %s needs checking\n"), 366 filename); 367 exit(32); 368 } 369 exit(0); 370 } 371 372 char * 373 unrawname(name) 374 char *name; 375 { 376 char *dp; 377 378 379 if ((dp = getfullblkname(name)) == NULL) 380 return (""); 381 return (dp); 382 } 383 384 char * 385 rawname(name) 386 char *name; 387 { 388 char *dp; 389 390 if ((dp = getfullrawname(name)) == NULL) 391 return (""); 392 return (dp); 393 } 394 395 char * 396 hasvfsopt(vfs, opt) 397 register struct vfstab *vfs; 398 register char *opt; 399 { 400 char *f, *opts; 401 static char *tmpopts; 402 403 if (vfs->vfs_mntopts == NULL) 404 return (NULL); 405 if (tmpopts == 0) { 406 tmpopts = (char *)calloc(256, sizeof (char)); 407 if (tmpopts == 0) 408 return (0); 409 } 410 (void) strncpy(tmpopts, vfs->vfs_mntopts, (sizeof (tmpopts) - 1)); 411 opts = tmpopts; 412 f = mntopt(&opts); 413 for (; *f; f = mntopt(&opts)) { 414 if (strncmp(opt, f, strlen(opt)) == 0) 415 return (f - tmpopts + vfs->vfs_mntopts); 416 } 417 return (NULL); 418 } 419 420 static void 421 usage() 422 { 423 (void) fprintf(stderr, gettext("udfs usage: fsck [-F udfs] " 424 "[generic options] [-o p,w,s] [special ....]\n")); 425 exit(31+1); 426 } 427