Print this page
PSARC 2008/290 lofi mount
6384817 Need persistent lofi based mounts and direct mount(1m) support for lofi
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/fs.d/ufs/fsck/main.c
+++ new/usr/src/cmd/fs.d/ufs/fsck/main.c
1 1 /*
2 2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 3 * Use is subject to license terms.
4 4 */
5 5
6 6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
7 7 /* All Rights Reserved */
8 8
9 9
10 10 /*
11 11 * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
12 12 * All rights reserved.
13 13 *
14 14 * Redistribution and use in source and binary forms are permitted
15 15 * provided that: (1) source distributions retain this entire copyright
16 16 * notice and comment, and (2) distributions including binaries display
17 17 * the following acknowledgement: ``This product includes software
18 18 * developed by the University of California, Berkeley and its contributors''
|
↓ open down ↓ |
18 lines elided |
↑ open up ↑ |
19 19 * in the documentation or other materials provided with the distribution
20 20 * and in all advertising materials mentioning features or use of this
21 21 * software. Neither the name of the University nor the names of its
22 22 * contributors may be used to endorse or promote products derived
23 23 * from this software without specific prior written permission.
24 24 * THIS SOFTWARE IS PROVIDED '`AS IS'' AND WITHOUT ANY EXPRESS OR
25 25 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
26 26 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27 27 */
28 28
29 -#pragma ident "@(#)main.c 1.54 08/02/06 SMI"
29 +#pragma ident "@(#)main.c 1.55 08/05/07 SMI"
30 30
31 31 /*
32 32 * In-core structures:
33 33 * blockmap[]
34 34 * A bitmap of block usage very similar to what's on disk, but
35 35 * for the entire filesystem rather than just a cylinder group.
36 36 * Zero indicates free, one indicates allocated. Note that this
37 37 * is opposite the interpretation of a cylinder group's free block
38 38 * bitmap.
39 39 *
40 40 * statemap[]
41 41 * Tracks what is known about each inode in the filesystem.
42 42 * The fundamental state value is one of USTATE, FSTATE, DSTATE,
43 43 * or SSTATE (unallocated, file, directory, shadow/acl).
44 44 *
45 45 * There are optional modifying attributes as well: INZLINK,
46 46 * INFOUND, INCLEAR, INORPHAN, and INDELAYD. The IN prefix
47 47 * stands for inode. INZLINK declares that no links (di_nlink ==
48 48 * 0) to the inode have been found. It is used instead of
49 49 * examining di_nlink because we've always got the statemap[] in
50 50 * memory, and on average the odds are against having any given
51 51 * inode in the cache. INFOUND flags that an inode was
52 52 * encountered during the descent of the filesystem. In other
53 53 * words, it's reachable, either by name or by being an acl or
54 54 * attribute. INCLEAR declares an intent to call clri() on an
55 55 * inode. The INCLEAR and INZLINK attributes are treated in a
56 56 * mutually exclusive manner with INCLEAR taking higher precedence
57 57 * as the intent is to clear the inode.
58 58 *
59 59 * INORPHAN indicates that the inode has already been seen once
60 60 * in pass3 and determined to be an orphan, so any additional
61 61 * encounters don't need to waste cycles redetermining that status.
62 62 * It also means we don't ask the user about doing something to the
63 63 * inode N times.
64 64 *
65 65 * INDELAYD marks inodes that pass1 determined needed to be truncated.
66 66 * They can't be truncated during that pass, because it depends on
67 67 * having a stable world for building the block and inode tables from.
68 68 *
69 69 * The IN flags rarely used directly, but instead are
70 70 * pre-combined through the {D,F,S}ZLINK, DFOUND, and
71 71 * {D,F,S}CLEAR convenience macros. This mainly matters when
72 72 * trying to use grep on the source.
73 73 *
74 74 * Three state-test macros are provided: S_IS_DUNFOUND(),
75 75 * S_IS_DVALID(), and S_IS_ZLINK(). The first is true when an
76 76 * inode's state indicates that it is either a simple directory
77 77 * (DSTATE without the INFOUND or INCLEAR modifiers) or a
78 78 * directory with the INZLINK modifier set. By definition, if a
79 79 * directory has zero links, then it can't be found. As for
80 80 * S_IS_DVALID(), it decides if a directory inode is alive.
81 81 * Effectively, this translates to whether or not it's been
82 82 * flagged for clearing. If not, then it's valid for current
83 83 * purposes. This is true even if INZLINK is set, as we may find
84 84 * a reference to it later. Finally, S_IS_ZLINK() just picks out
85 85 * the INZLINK flag from the state.
86 86 *
87 87 * The S_*() macros all work on a state value. To simplify a
88 88 * bit, the INO_IS_{DUNFOUND,DVALID}() macros take an inode
89 89 * number argument. The inode is looked up in the statemap[] and
90 90 * the result handed off to the corresponding S_*() macro. This
91 91 * is partly a holdover from working with different data
92 92 * structures (with the same net intent) in the BSD fsck.
93 93 *
94 94 * lncntp
95 95 * Each entry is initialized to the di_link from the on-disk
96 96 * inode. Each time we find one of those links, we decrement it.
97 97 * Once all the traversing is done, we should have a zero. If we
98 98 * have a positive value, then some reference disappeared
99 99 * (probably from a directory that got nuked); deal with it by
100 100 * fixing the count. If we have a negative value, then we found
101 101 * an extra reference. This is a can't-happen, except in the
102 102 * special case of when we reconnect a directory to its parent or
103 103 * to lost+found. An exact match between lncntp[] and the on-disk
104 104 * inode means it's completely unreferenced.
105 105 *
106 106 * aclphead
107 107 * This is a hash table of the acl inodes in the filesystem.
108 108 *
109 109 * aclpsort
110 110 * The same acls as in aclphead, but as a simple linear array.
111 111 * It is used to hold the acl pointers for sorting and scanning
112 112 * in pass3b.
113 113 */
114 114
115 115 #include <stdio.h>
116 116 #include <stdlib.h>
117 117 #include <unistd.h>
118 118 #include <sys/types.h>
119 119 #include <sys/param.h>
120 120 #include <sys/int_types.h>
121 121 #include <sys/mntent.h>
122 122 #include <sys/fs/ufs_fs.h>
123 123 #include <sys/vnode.h>
124 124 #include <sys/fs/ufs_inode.h>
125 125 #include <sys/stat.h>
126 126 #include <fcntl.h>
127 127 #include <sys/wait.h>
128 128 #include <sys/mnttab.h>
129 129 #include <signal.h>
130 130 #include <string.h>
131 131 #include <sys/vfstab.h>
132 132 #include <sys/statvfs.h>
133 133 #include <sys/filio.h>
134 134 #include <ustat.h>
135 135 #include <errno.h>
136 136 #include "fsck.h"
137 137
138 138 static void usage(void);
139 139 static long argtol(int, char *, char *, int);
140 140 static void checkfilesys(char *);
141 141 static void check_sanity(char *);
142 142 static void report_limbo(const void *, VISIT, int);
143 143
144 144 #define QUICK_CHECK 'm' /* are things ok according to superblock? */
145 145 #define ALL_no 'n' /* auto-answer interactive questions `no' */
146 146 #define ALL_NO 'N' /* auto-answer interactive questions `no' */
147 147 #define UFS_OPTS 'o' /* ufs-specific options, see subopts[] */
148 148 #define ECHO_CMD 'V' /* echo the command line */
149 149 #define ALL_yes 'y' /* auto-answer interactive questions `yes' */
150 150 #define ALL_YES 'Y' /* auto-answer interactive questions `yes' */
151 151 #define VERBOSE 'v' /* be chatty */
152 152
153 153 static char *subopts[] = {
154 154 #define PREEN 0 /* non-interactive mode (parent is parallel) */
155 155 "p",
156 156 #define BLOCK 1 /* alternate superblock */
157 157 "b",
158 158 #define DEBUG 2 /* yammer */
159 159 "d",
160 160 #define ONLY_WRITES 3 /* check all writable filesystems */
161 161 "w",
162 162 #define FORCE 4 /* force checking, even if clean */
163 163 "f",
164 164 NULL
165 165 };
166 166
167 167 /*
168 168 * Filesystems that are `magical' - if they exist in vfstab,
169 169 * then they have to be mounted for the system to have gotten
170 170 * far enough to be able to run fsck. Thus, don't get all
171 171 * bent out of shape if we're asked to check it and it is mounted.
172 172 */
173 173 char *magic_fs[] = {
174 174 "", /* MAGIC_NONE, for normal filesystems */
175 175 "/", /* MAGIC_ROOT */
176 176 "/usr", /* MAGIC_USR */
177 177 NULL /* MAGIC_LIMIT */
178 178 };
179 179
180 180 int
181 181 main(int argc, char *argv[])
182 182 {
183 183 int c;
184 184 int wflag = 0;
185 185 char *suboptions, *value;
186 186 struct rlimit rlimit;
187 187 extern int optind;
188 188 extern char *optarg;
189 189
190 190 while ((c = getopt(argc, argv, "mnNo:VvyY")) != EOF) {
191 191 switch (c) {
192 192
193 193 case QUICK_CHECK:
194 194 mflag++;
195 195 break;
196 196
197 197 case ALL_no:
198 198 case ALL_NO:
199 199 nflag++;
200 200 yflag = 0;
201 201 break;
202 202
203 203 case VERBOSE:
204 204 verbose++;
205 205 break;
206 206
207 207 case UFS_OPTS:
208 208 /*
209 209 * ufs specific options.
210 210 */
211 211 if (optarg == NULL) {
212 212 usage();
213 213 /*
214 214 * lint does not believe this, nor does it
215 215 * believe #pragma does_not_return(usage)
216 216 */
217 217 /* NOTREACHED */
218 218 }
219 219 suboptions = optarg;
220 220 while (*suboptions != '\0') {
221 221 switch (getsubopt(&suboptions, subopts,
222 222 &value)) {
223 223
224 224 case PREEN:
225 225 preen++;
226 226 break;
227 227
228 228 case BLOCK:
229 229 bflag = argtol(BLOCK, "block",
230 230 value, 10);
231 231 (void) printf("Alternate super block "
232 232 "location: %ld.\n",
233 233 (long)bflag);
234 234 break;
235 235
236 236 case DEBUG:
237 237 debug++;
238 238 verbose++;
239 239 break;
240 240
241 241 case ONLY_WRITES:
242 242 /* check only writable filesystems */
243 243 wflag++;
244 244 break;
245 245
246 246 case FORCE:
247 247 fflag++;
248 248 break;
249 249
250 250 default:
251 251 usage();
252 252 }
253 253 }
254 254 break;
255 255
256 256 case ECHO_CMD:
257 257 {
258 258 int opt_count;
259 259 char *opt_text;
260 260
261 261 (void) printf("fsck -F ufs ");
262 262 for (opt_count = 1; opt_count < argc;
263 263 opt_count++) {
264 264 opt_text = argv[opt_count];
265 265 if (opt_text)
266 266 (void) printf("%s ", opt_text);
267 267 }
268 268 (void) printf("\n");
269 269 }
270 270 break;
271 271
272 272 case ALL_yes:
273 273 case ALL_YES:
274 274 yflag++;
275 275 nflag = 0;
276 276 break;
277 277
278 278 default:
279 279 usage();
280 280 }
281 281 }
282 282 argc -= optind;
283 283 argv += optind;
284 284
285 285 if (argc == 0)
286 286 usage();
287 287
288 288 rflag++; /* check raw devices where we can */
289 289 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
290 290 (void) signal(SIGINT, catch);
291 291 if (preen)
292 292 (void) signal(SIGQUIT, catchquit);
293 293
294 294 /*
295 295 * Push up our allowed memory limit so we can cope
296 296 * with huge file systems.
297 297 */
298 298 if (getrlimit(RLIMIT_DATA, &rlimit) == 0) {
299 299 rlimit.rlim_cur = rlimit.rlim_max;
300 300 (void) setrlimit(RLIMIT_DATA, &rlimit);
301 301 }
302 302
303 303 /*
304 304 * There are a lot of places where we just exit if a problem is
305 305 * found. This means that we won't necessarily check everything
306 306 * we were asked to. It would be nice to do everything, and
307 307 * then provide a summary when we're done. However, the
308 308 * interface doesn't really allow us to do that in any useful
309 309 * way. So, we'll just bail on the first unrecoverable
310 310 * problem encountered. If we've been run by the generic
311 311 * wrapper, we were only given one filesystem to check, so the
312 312 * multi-fs case implies being run manually; that means the
313 313 * user can rerun us on the remaining filesystems when it's
314 314 * convenient for them.
315 315 */
316 316 while (argc-- > 0) {
317 317 if (wflag && !writable(*argv)) {
318 318 (void) fprintf(stderr, "not writeable '%s'\n", *argv);
319 319 argv++;
320 320 if (exitstat == 0)
321 321 exitstat = EXBADPARM;
322 322 } else {
323 323 checkfilesys(*argv++);
324 324 }
325 325 }
326 326 if (interrupted)
327 327 exitstat = EXSIGNAL;
328 328 exit(exitstat);
329 329 }
330 330
331 331 /*
332 332 * A relatively intelligent strtol(). Note that if str is NULL, we'll
333 333 * exit, so ret does not actually need to be pre-initialized. Lint
334 334 * doesn't believe this, and it's harmless enough to make lint happy here.
335 335 */
336 336 static long
337 337 argtol(int flag, char *req, char *str, int base)
338 338 {
339 339 char *cp = str;
340 340 long ret = -1;
341 341
342 342 errno = 0;
343 343 if (str != NULL)
344 344 ret = strtol(str, &cp, base);
345 345 if (cp == str || *cp) {
346 346 (void) fprintf(stderr, "-%c flag requires a %s\n", flag, req);
347 347 exit(EXBADPARM);
348 348 }
349 349 if (errno != 0) {
350 350 (void) fprintf(stderr, "-%c %s value out of range\n",
351 351 flag, req);
352 352 }
353 353
354 354 return (ret);
355 355 }
356 356
357 357 /*
358 358 * Check the specified file system.
359 359 */
360 360 static void
361 361 checkfilesys(char *filesys)
362 362 {
363 363 daddr32_t n_ffree, n_bfree;
364 364 char *devstr;
365 365 fsck_ino_t files;
366 366 daddr32_t blks;
367 367 fsck_ino_t inumber;
368 368 int zlinks_printed;
369 369 fsck_ino_t limbo_victim;
370 370 double dbl_nffree, dbl_dsize;
371 371 int quiet_dups;
372 372
373 373 mountfd = -1;
374 374 hotroot = 0;
375 375 mountedfs = M_NOMNT;
376 376 reattached_dir = 0;
377 377 broke_dir_link = 0;
378 378 iscorrupt = 1; /* assume failure in setup() */
379 379 islog = 0;
380 380 islogok = 0;
381 381 overflowed_lf = 0;
382 382 errorlocked = is_errorlocked(filesys);
383 383 limbo_dirs = NULL;
384 384
385 385 if ((devstr = setup(filesys)) == NULL) {
386 386 if (!iscorrupt) {
387 387 return;
388 388 }
389 389
390 390 if (preen)
391 391 pfatal("CAN'T CHECK FILE SYSTEM.");
392 392 if ((exitstat == 0) && (mflag))
393 393 exitstat = EXUMNTCHK;
394 394 exit(exitstat);
395 395 } else {
396 396 devname = devstr;
397 397 }
398 398
399 399 if (mflag) {
400 400 check_sanity(filesys);
401 401 /* NOTREACHED */
402 402 }
403 403
404 404 if (debug)
405 405 printclean();
406 406
407 407 iscorrupt = 0; /* setup() succeeded, assume good filesystem */
408 408
409 409 /*
410 410 * 1: scan inodes tallying blocks used
411 411 */
412 412 if (!preen) {
413 413 /* hotroot is reported as such in setup() if debug is on */
414 414 if (mountedfs != M_NOMNT)
415 415 (void) printf("** Currently Mounted on %s\n",
416 416 sblock.fs_fsmnt);
417 417 else
418 418 (void) printf("** Last Mounted on %s\n",
419 419 sblock.fs_fsmnt);
420 420 (void) printf("** Phase 1 - Check Blocks and Sizes\n");
421 421 }
422 422 pass1();
423 423
424 424 /*
425 425 * 1b: locate first references to duplicates, if any
426 426 */
427 427 if (have_dups()) {
428 428 if (preen)
429 429 pfatal("INTERNAL ERROR: dups with -o p");
430 430 (void) printf("** Phase 1b - Rescan For More DUPS\n");
431 431 pass1b();
432 432 }
433 433
434 434 /*
435 435 * 2: traverse directories from root to mark all connected directories
436 436 */
437 437 if (!preen)
438 438 (void) printf("** Phase 2 - Check Pathnames\n");
439 439 pass2();
440 440
441 441 /*
442 442 * 3a: scan inodes looking for disconnected directories.
443 443 */
444 444 if (!preen)
445 445 (void) printf("** Phase 3a - Check Connectivity\n");
446 446 pass3a();
447 447
448 448 /*
449 449 * 3b: check acls
450 450 */
451 451 if (!preen)
452 452 (void) printf("** Phase 3b - Verify Shadows/ACLs\n");
453 453 pass3b();
454 454
455 455 /*
456 456 * 4: scan inodes looking for disconnected files; check reference counts
457 457 */
458 458 if (!preen)
459 459 (void) printf("** Phase 4 - Check Reference Counts\n");
460 460 pass4();
461 461
462 462 /*
463 463 * 5: check and repair resource counts in cylinder groups
464 464 */
465 465 if (!preen)
466 466 (void) printf("** Phase 5 - Check Cylinder Groups\n");
467 467 recount:
468 468 pass5();
469 469
470 470 if (overflowed_lf) {
471 471 iscorrupt = 1;
472 472 }
473 473
474 474 if (!nflag && mountedfs == M_RW) {
475 475 (void) printf("FILESYSTEM MAY STILL BE INCONSISTENT.\n");
476 476 rerun = 1;
477 477 }
478 478
479 479 if (have_dups()) {
480 480 quiet_dups = (reply("LIST REMAINING DUPS") == 0);
481 481 if (report_dups(quiet_dups) > 0)
482 482 iscorrupt = 1;
483 483
484 484 (void) printf("WARNING: DATA LOSS MAY HAVE OCCURRED DUE TO "
485 485 "DUP BLOCKS.\nVERIFY FILE CONTENTS BEFORE USING.\n");
486 486 }
487 487
488 488 if (limbo_dirs != NULL) {
489 489 /*
490 490 * Don't force iscorrupt, as this is sufficiently
491 491 * harmless that the filesystem can be mounted and
492 492 * used. We just leak some inodes and/or blocks.
493 493 */
494 494 pwarn("Orphan directories not cleared or reconnected:\n");
495 495
496 496 twalk(limbo_dirs, report_limbo);
497 497
498 498 while (limbo_dirs != NULL) {
499 499 limbo_victim = *(fsck_ino_t *)limbo_dirs;
500 500 if (limbo_victim != NULL) {
501 501 (void) tdelete((void *)limbo_victim,
502 502 &limbo_dirs,
503 503 ino_t_cmp);
504 504 }
505 505 }
506 506
507 507 rerun = 1;
508 508 }
509 509
510 510 if (iscorrupt) {
511 511 if (mountedfs == M_RW)
512 512 (void) printf("FS IS MOUNTED R/W AND"
513 513 " FSCK DID ITS BEST TO FIX"
514 514 " INCONSISTENCIES.\n");
515 515 else
516 516 (void) printf("FILESYSTEM MAY STILL BE"
517 517 " INCONSISTENT.\n");
518 518 rerun = 1;
519 519 }
520 520
521 521 /*
522 522 * iscorrupt must be stable at this point.
523 523 * updateclean() returns true when it had to discard the log.
524 524 * This can only happen once, since sblock.fs_logbno gets
525 525 * cleared as part of that operation.
526 526 */
527 527 if (updateclean()) {
528 528 if (!preen)
529 529 (void) printf(
530 530 "Log was discarded, updating cyl groups\n");
531 531 goto recount;
532 532 }
533 533
534 534 if (debug)
535 535 printclean();
536 536
537 537 ckfini();
538 538
539 539 /*
540 540 * print out summary statistics
541 541 */
542 542 n_ffree = sblock.fs_cstotal.cs_nffree;
543 543 n_bfree = sblock.fs_cstotal.cs_nbfree;
544 544 files = maxino - UFSROOTINO - sblock.fs_cstotal.cs_nifree - n_files;
545 545 blks = n_blks +
546 546 sblock.fs_ncg * (cgdmin(&sblock, 0) - cgsblock(&sblock, 0));
547 547 blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0);
548 548 blks += howmany(sblock.fs_cssize, sblock.fs_fsize);
549 549 blks = maxfsblock - (n_ffree + sblock.fs_frag * n_bfree) - blks;
550 550 if (debug && (files > 0 || blks > 0)) {
551 551 countdirs = sblock.fs_cstotal.cs_ndir - countdirs;
552 552 pwarn("Reclaimed: %d directories, %d files, %lld fragments\n",
553 553 countdirs, files - countdirs,
554 554 (longlong_t)blks);
555 555 }
556 556
557 557 dbl_nffree = (double)n_ffree;
558 558 dbl_dsize = (double)sblock.fs_dsize;
559 559
560 560 if (!verbose) {
561 561 /*
562 562 * Done as one big string to try for a single write,
563 563 * so the output doesn't get interleaved with other
564 564 * preening fscks.
565 565 */
566 566 pwarn("%ld files, %lld used, %lld free "
567 567 "(%lld frags, %lld blocks, %.1f%% fragmentation)\n",
568 568 (long)n_files, (longlong_t)n_blks,
569 569 (longlong_t)n_ffree + sblock.fs_frag * n_bfree,
570 570 (longlong_t)n_ffree, (longlong_t)n_bfree,
571 571 (dbl_nffree * 100.0) / dbl_dsize);
572 572 } else {
573 573 pwarn("\nFilesystem summary:\n");
574 574 pwarn("Inodes in use: %ld\n", (long)n_files);
575 575 pwarn("Blocks in use: %lld\n", (longlong_t)n_blks);
576 576 pwarn("Total free fragments: %lld\n",
577 577 (longlong_t)n_ffree + sblock.fs_frag * n_bfree);
578 578 pwarn("Free fragments not in blocks: %lld\n",
579 579 (longlong_t)n_ffree);
580 580 pwarn("Total free blocks: %lld\n", (longlong_t)n_bfree);
581 581 pwarn("Fragment/block fragmentation: %.1f%%\n",
582 582 (dbl_nffree * 100.0) / dbl_dsize);
583 583 pwarn("");
584 584
585 585 if (files < 0)
586 586 pwarn("%d inodes missing\n", -files);
587 587 if (blks < 0)
588 588 pwarn("%lld blocks missing\n", -(longlong_t)blks);
589 589
590 590 zlinks_printed = 0;
591 591 for (inumber = UFSROOTINO; inumber < maxino; inumber++) {
592 592 if (S_IS_ZLINK(statemap[inumber])) {
593 593 if (zlinks_printed == 0) {
594 594 pwarn("The following zero "
595 595 "link count inodes remain:");
596 596 }
597 597 if (zlinks_printed) {
598 598 if ((zlinks_printed % 9) == 0)
599 599 (void) puts(",\n");
600 600 else
601 601 (void) puts(", ");
602 602 }
603 603 (void) printf("%u", inumber);
604 604 zlinks_printed++;
605 605 }
606 606 }
607 607 if ((zlinks_printed != 0) && ((zlinks_printed % 9) != 0))
608 608 (void) putchar('\n');
609 609 }
610 610
611 611 /*
612 612 * Clean up after ourselves, so we can do the next filesystem.
613 613 */
614 614 free_dup_state();
615 615 inocleanup();
616 616 free(blockmap);
617 617 free(statemap);
618 618 free((void *)lncntp);
619 619 lncntp = NULL;
620 620 blockmap = NULL;
621 621 statemap = NULL;
622 622 if (iscorrupt && exitstat == 0)
623 623 exitstat = EXFNDERRS;
624 624 if (fsmodified)
625 625 (void) printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
626 626 if (overflowed_lf)
627 627 (void) printf("\n***** %s FULL, MUST REMOVE ENTRIES *****\n",
628 628 lfname);
629 629 if (reattached_dir) {
630 630 (void) printf("ORPHANED DIRECTORIES REATTACHED; DIR LINK "
631 631 "COUNTS MAY NOT BE CORRECT.\n");
632 632 rerun = 1;
633 633 }
634 634 if (broke_dir_link) {
635 635 (void) printf(
636 636 "DIRECTORY HARDLINK BROKEN; LOOPS MAY STILL EXIST.\n");
637 637 rerun = 1;
638 638 }
639 639 if (iscorrupt)
640 640 (void) printf("***** FILE SYSTEM IS BAD *****\n");
641 641
642 642 if (rerun) {
643 643 if (mountedfs == M_RW)
644 644 (void) printf("\n***** PLEASE RERUN FSCK ON UNMOUNTED"
645 645 " FILE SYSTEM *****\n");
646 646 else
647 647 (void) printf("\n***** PLEASE RERUN FSCK *****\n");
648 648 }
649 649
650 650 if ((exitstat == 0) &&
651 651 (((mountedfs != M_NOMNT) && !errorlocked) || hotroot)) {
652 652 exitstat = EXROOTOKAY;
653 653 }
654 654
655 655 if ((exitstat == 0) && rerun)
656 656 exitstat = EXFNDERRS;
657 657
658 658 if (mountedfs != M_NOMNT) {
659 659 if (!fsmodified)
660 660 return;
661 661 /*
662 662 * _FIOFFS is much more effective than a simple sync().
663 663 * Note that the original fswritefd was discarded in
664 664 * ckfini().
665 665 */
666 666 fswritefd = open(devstr, O_RDWR, 0);
667 667 if (fswritefd != -1) {
668 668 (void) ioctl(fswritefd, _FIOFFS, NULL);
669 669 (void) close(fswritefd);
670 670 }
671 671
672 672 if (!preen)
673 673 (void) printf("\n***** REBOOT NOW *****\n");
674 674
675 675 exitstat = EXREBOOTNOW;
676 676 }
677 677 }
678 678
679 679 /*
680 680 * fsck -m: does the filesystem pass cursory examination
681 681 *
682 682 * XXX This is very redundant with setup(). The right thing would be
683 683 * for setup() to modify its behaviour when mflag is set (less
684 684 * chatty, exit instead of return, etc).
685 685 */
686 686 void
687 687 check_sanity(char *filename)
688 688 {
|
↓ open down ↓ |
649 lines elided |
↑ open up ↑ |
689 689 struct stat64 stbd, stbr;
690 690 char *devname;
691 691 struct ustat usb;
692 692 char vfsfilename[MAXPATHLEN];
693 693 struct vfstab vfsbuf;
694 694 FILE *vfstab;
695 695 struct statvfs vfs_stat;
696 696 int found_magic[MAGIC_LIMIT];
697 697 int magic_cnt;
698 698 int is_magic = 0;
699 - int is_block;
699 + int is_block = 0;
700 + int is_file = 0;
700 701
701 702 (void) memset((void *)found_magic, 0, sizeof (found_magic));
702 703
703 704 if (stat64(filename, &stbd) < 0) {
704 705 (void) fprintf(stderr,
705 706 "ufs fsck: sanity check failed : cannot stat %s\n", filename);
706 707 exit(EXNOSTAT);
707 708 }
708 709
709 - if ((stbd.st_mode & S_IFMT) == S_IFBLK) {
710 + if (S_ISBLK(stbd.st_mode)) {
710 711 is_block = 1;
711 - } else if ((stbd.st_mode & S_IFMT) == S_IFCHR) {
712 + } else if (S_ISCHR(stbd.st_mode)) {
712 713 is_block = 0;
713 - } else {
714 - /*
715 - * In !mflag mode, we allow checking the contents
716 - * of a file. Since this is intended primarily for
717 - * speeding up boot-time checks and allowing for a
718 - * file complicates the ok-input tests, we'll disallow
719 - * that option.
720 - */
721 - (void) fprintf(stderr,
722 - "ufs fsck: sanity check failed: "
723 - "%s not block or character device\n", filename);
724 - exit(EXNOSTAT);
714 + } else if (S_ISREG(stbd.st_mode)) {
715 + is_file = 1;
725 716 }
726 717
727 718 /*
728 719 * Determine if this is the root file system via vfstab. Give up
729 720 * silently on failures. The whole point of this is to be tolerant
730 721 * of the magic file systems being already mounted.
731 722 */
732 - if ((vfstab = fopen(VFSTAB, "r")) != 0) {
723 + if (!is_file && (vfstab = fopen(VFSTAB, "r")) != NULL) {
733 724 for (magic_cnt = 0; magic_cnt < MAGIC_LIMIT; magic_cnt++) {
734 725 if (magic_cnt == MAGIC_NONE)
735 726 continue;
736 727 if (getvfsfile(vfstab, &vfsbuf,
737 728 magic_fs[magic_cnt]) == 0) {
738 729 if (is_block)
739 730 devname = vfsbuf.vfs_special;
740 731 else
741 732 devname = vfsbuf.vfs_fsckdev;
742 733 if (stat64(devname, &stbr) == 0) {
743 734 if (stbr.st_rdev == stbd.st_rdev) {
744 735 found_magic[magic_cnt] = 1;
745 736 is_magic = magic_cnt;
746 737 break;
747 738 }
748 739 }
749 740 }
750 741 }
751 742 }
752 743
753 744 /*
754 745 * Only works if filename is a block device or if
755 746 * character and block device has the same dev_t value.
756 747 * This is currently true, but nothing really forces it.
757 748 */
758 749 if (!is_magic && (ustat(stbd.st_rdev, &usb) == 0)) {
759 750 (void) fprintf(stderr,
760 751 "ufs fsck: sanity check: %s already mounted\n", filename);
761 752 exit(EXMOUNTED);
762 753 }
763 754
764 755 if (is_magic) {
765 756 (void) strcpy(vfsfilename, magic_fs[is_magic]);
766 757 if (statvfs(vfsfilename, &vfs_stat) != 0) {
767 758 (void) fprintf(stderr, "ufs fsck: Cannot stat %s\n",
768 759 vfsfilename);
769 760 exit(EXNOSTAT);
770 761 }
771 762
772 763 if (!(vfs_stat.f_flag & ST_RDONLY)) {
773 764 /*
774 765 * The file system is mounted read/write
775 766 * We need to exit saying this. If it's only
776 767 * mounted readonly, we can continue.
777 768 */
778 769
779 770 (void) fprintf(stderr,
780 771 "ufs fsck: sanity check:"
781 772 "%s already mounted read/write\n", filename);
782 773 exit(EXMOUNTED);
783 774 }
784 775 }
785 776
786 777 /*
787 778 * We know that at boot, the ufs root file system is mounted
788 779 * read-only first. After fsck runs, it is remounted as
789 780 * read-write. Therefore, we do not need to check for different
790 781 * values for fs_state between the root file system and the
791 782 * rest of the file systems.
792 783 */
793 784 if (islog && !islogok) {
794 785 (void) fprintf(stderr,
795 786 "ufs fsck: sanity check: %s needs checking\n", filename);
796 787 exit(EXUMNTCHK);
797 788 }
798 789 if ((sblock.fs_state + (long)sblock.fs_time == FSOKAY) &&
799 790 (sblock.fs_clean == FSCLEAN || sblock.fs_clean == FSSTABLE ||
800 791 (sblock.fs_clean == FSLOG && islog))) {
801 792 (void) fprintf(stderr,
802 793 "ufs fsck: sanity check: %s okay\n", filename);
803 794 } else {
804 795 (void) fprintf(stderr,
805 796 "ufs fsck: sanity check: %s needs checking\n", filename);
806 797 exit(EXUMNTCHK);
807 798 }
808 799 exit(EXOKAY);
809 800 }
810 801
811 802 caddr_t
812 803 hasvfsopt(struct vfstab *vfs, char *opt)
813 804 {
814 805 struct mnttab mtab;
815 806
816 807 if (vfs->vfs_mntopts == NULL)
817 808 return (NULL);
818 809 mtab.mnt_mntopts = vfs->vfs_mntopts;
819 810 return (hasmntopt(&mtab, opt));
820 811 }
821 812
822 813 void
823 814 usage(void)
824 815 {
825 816 (void) fprintf(stderr,
826 817 "ufs usage: fsck [-F ufs] [-m] [-n] [-V] [-v] [-y] "
827 818 "[-o p,b=#,w,f] [special ....]\n");
828 819
829 820 exit(EXBADPARM);
830 821 }
831 822
832 823 /*ARGSUSED*/
833 824 static void
834 825 report_limbo(const void *node, VISIT order, int level)
835 826 {
836 827 fsck_ino_t ino = *(fsck_ino_t *)node;
837 828
838 829 if ((order == postorder) || (order == leaf)) {
839 830 (void) printf(" Inode %d\n", ino);
840 831 }
841 832 }
|
↓ open down ↓ |
99 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX