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