1 /* 2 * Copyright 2005 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 int 91 main(int argc, char *argv[]) 92 { 93 int c; 94 char *suboptions, *value; 95 int suboption; 96 97 (void) setlocale(LC_ALL, ""); 98 99 while ((c = getopt(argc, argv, "mnNo:VyYz")) != EOF) { 100 switch (c) { 101 102 case 'm': 103 mflag++; 104 break; 105 106 case 'n': /* default no answer flag */ 107 case 'N': 108 nflag++; 109 yflag = 0; 110 break; 111 112 case 'o': 113 /* 114 * udfs specific options. 115 */ 116 suboptions = optarg; 117 while (*suboptions != '\0') { 118 suboption = getsubopt(&suboptions, 119 subopts, &value); 120 switch (suboption) { 121 122 case PREEN: 123 preen++; 124 break; 125 126 case DEBUG: 127 debug++; 128 break; 129 130 case READ_ONLY: 131 break; 132 133 case ONLY_WRITES: 134 /* check only writable filesystems */ 135 wflag++; 136 break; 137 138 case FORCE: 139 fflag++; 140 break; 141 142 case STATS: 143 sflag++; 144 break; 145 146 default: 147 usage(); 148 } 149 } 150 break; 151 152 case 'V': 153 { 154 int opt_count; 155 char *opt_text; 156 157 (void) fprintf(stdout, "fsck -F udfs "); 158 for (opt_count = 1; opt_count < argc; 159 opt_count++) { 160 opt_text = argv[opt_count]; 161 if (opt_text) 162 (void) fprintf(stdout, " %s ", 163 opt_text); 164 } 165 (void) fprintf(stdout, "\n"); 166 } 167 break; 168 169 case 'y': /* default yes answer flag */ 170 case 'Y': 171 yflag++; 172 nflag = 0; 173 break; 174 175 case '?': 176 usage(); 177 } 178 } 179 argc -= optind; 180 argv = &argv[optind]; 181 rflag++; /* check raw devices */ 182 if (signal(SIGINT, SIG_IGN) != SIG_IGN) { 183 (void) signal(SIGINT, catch); 184 } 185 186 if (preen) { 187 (void) signal(SIGQUIT, catchquit); 188 } 189 190 if (argc) { 191 while (argc-- > 0) { 192 if (wflag && !writable(*argv)) { 193 (void) fprintf(stderr, 194 gettext("not writeable '%s'\n"), *argv); 195 argv++; 196 } else 197 checkfilesys(*argv++); 198 } 199 exit(exitstat); 200 } 201 return (0); 202 } 203 204 205 static void 206 checkfilesys(char *filesys) 207 { 208 char *devstr; 209 210 mountfd = -1; 211 mountedfs = 0; 212 iscorrupt = 1; 213 214 if ((devstr = setup(filesys)) == 0) { 215 if (iscorrupt == 0) 216 return; 217 if (preen) 218 pfatal(gettext("CAN'T CHECK FILE SYSTEM.")); 219 if ((exitstat == 0) && (mflag)) 220 exitstat = 32; 221 exit(exitstat); 222 } 223 else 224 devname = devstr; 225 if (mflag) 226 check_sanity(filesys); /* this never returns */ 227 iscorrupt = 0; 228 /* 229 * 1: scan inodes tallying blocks used 230 */ 231 if (preen == 0) { 232 if (mountedfs) 233 (void) printf(gettext("** Currently Mounted on %s\n"), 234 mountpoint); 235 if (mflag) { 236 (void) printf( 237 gettext("** Phase 1 - Sanity Check only\n")); 238 return; 239 } else 240 (void) printf( 241 gettext("** Phase 1 - Check Directories " 242 "and Blocks\n")); 243 } 244 pass1(); 245 if (sflag) { 246 if (preen) 247 (void) printf("%s: ", devname); 248 else 249 (void) printf("** "); 250 } 251 if (debug) 252 (void) printf("pass1 isdirty %d\n", isdirty); 253 if (debug) 254 printfree(); 255 dofreemap(); 256 dolvint(); 257 258 /* 259 * print out summary statistics 260 */ 261 pwarn(gettext("%d files, %d dirs, %d used, %d free\n"), n_files, n_dirs, 262 n_blks, part_len - n_blks); 263 if (iscorrupt) 264 exitstat = 36; 265 if (!fsmodified) 266 return; 267 if (!preen) 268 (void) printf( 269 gettext("\n***** FILE SYSTEM WAS MODIFIED *****\n")); 270 271 if (mountedfs) { 272 exitstat = 40; 273 } 274 } 275 276 277 /* 278 * exit 0 - file system is unmounted and okay 279 * exit 32 - file system is unmounted and needs checking 280 * exit 33 - file system is mounted 281 * for root file system 282 * exit 34 - cannot stat device 283 */ 284 285 static void 286 check_sanity(char *filename) 287 { 288 struct stat stbd, stbr; 289 struct ustat usb; 290 char *devname; 291 struct vfstab vfsbuf; 292 FILE *vfstab; 293 int is_root = 0; 294 int is_usr = 0; 295 int is_block = 0; 296 297 if (stat(filename, &stbd) < 0) { 298 (void) fprintf(stderr, 299 gettext("udfs fsck: sanity check failed : cannot stat " 300 "%s\n"), filename); 301 exit(34); 302 } 303 304 if ((stbd.st_mode & S_IFMT) == S_IFBLK) 305 is_block = 1; 306 else if ((stbd.st_mode & S_IFMT) == S_IFCHR) 307 is_block = 0; 308 else { 309 (void) fprintf(stderr, 310 gettext("udfs fsck: sanity check failed: %s not " 311 "block or character device\n"), filename); 312 exit(34); 313 } 314 315 /* 316 * Determine if this is the root file system via vfstab. Give up 317 * silently on failures. The whole point of this is not to care 318 * if the root file system is already mounted. 319 * 320 * XXX - similar for /usr. This should be fixed to simply return 321 * a new code indicating, mounted and needs to be checked. 322 */ 323 if ((vfstab = fopen(VFSTAB, "r")) != 0) { 324 if (getvfsfile(vfstab, &vfsbuf, "/") == 0) { 325 if (is_block) 326 devname = vfsbuf.vfs_special; 327 else 328 devname = vfsbuf.vfs_fsckdev; 329 if (stat(devname, &stbr) == 0) 330 if (stbr.st_rdev == stbd.st_rdev) 331 is_root = 1; 332 } 333 if (getvfsfile(vfstab, &vfsbuf, "/usr") == 0) { 334 if (is_block) 335 devname = vfsbuf.vfs_special; 336 else 337 devname = vfsbuf.vfs_fsckdev; 338 if (stat(devname, &stbr) == 0) 339 if (stbr.st_rdev == stbd.st_rdev) 340 is_usr = 1; 341 } 342 } 343 344 345 /* 346 * XXX - only works if filename is a block device or if 347 * character and block device has the same dev_t value 348 */ 349 if (is_root == 0 && is_usr == 0 && ustat(stbd.st_rdev, &usb) == 0) { 350 (void) fprintf(stderr, 351 gettext("udfs fsck: sanity check: %s " 352 "already mounted\n"), filename); 353 exit(33); 354 } 355 356 if (lvintp->lvid_int_type == LVI_CLOSE) { 357 (void) fprintf(stderr, 358 gettext("udfs fsck: sanity check: %s okay\n"), 359 filename); 360 } else { 361 (void) fprintf(stderr, 362 gettext("udfs fsck: sanity check: %s needs checking\n"), 363 filename); 364 exit(32); 365 } 366 exit(0); 367 } 368 369 char * 370 unrawname(char *name) 371 { 372 char *dp; 373 374 375 if ((dp = getfullblkname(name)) == NULL) 376 return (""); 377 return (dp); 378 } 379 380 char * 381 rawname(char *name) 382 { 383 char *dp; 384 385 if ((dp = getfullrawname(name)) == NULL) 386 return (""); 387 return (dp); 388 } 389 390 char * 391 hasvfsopt(struct vfstab *vfs, char *opt) 392 { 393 char *f, *opts; 394 static char *tmpopts; 395 396 if (vfs->vfs_mntopts == NULL) 397 return (NULL); 398 if (tmpopts == 0) { 399 tmpopts = (char *)calloc(256, sizeof (char)); 400 if (tmpopts == 0) 401 return (0); 402 } 403 (void) strncpy(tmpopts, vfs->vfs_mntopts, (sizeof (tmpopts) - 1)); 404 opts = tmpopts; 405 f = mntopt(&opts); 406 for (; *f; f = mntopt(&opts)) { 407 if (strncmp(opt, f, strlen(opt)) == 0) 408 return (f - tmpopts + vfs->vfs_mntopts); 409 } 410 return (NULL); 411 } 412 413 static void 414 usage() 415 { 416 (void) fprintf(stderr, gettext("udfs usage: fsck [-F udfs] " 417 "[generic options] [-o p,w,s] [special ....]\n")); 418 exit(31+1); 419 } 420