Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / vfsck / main.c
1 /*
2 * Copyright (c) 1980, 1986 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 */
17
18 #include <afsconfig.h>
19 #include <afs/param.h>
20
21 #ifdef AFS_HPUX_ENV
22 /* We need the old directory type headers (included below), so don't include
23 * the normal dirent.h, or it will conflict. */
24 # undef HAVE_DIRENT_H
25 # include <sys/inode.h>
26 # define LONGFILENAMES 1
27 # include <sys/sysmacros.h>
28 # include <sys/ino.h>
29 # define DIRSIZ_MACRO
30 # ifdef HAVE_USR_OLD_USR_INCLUDE_NDIR_H
31 # include </usr/old/usr/include/ndir.h>
32 # else
33 # include <ndir.h>
34 # endif
35 #endif
36
37 #include <roken.h>
38
39 #include <ctype.h>
40
41 #ifdef HAVE_SYS_FILE_H
42 #include <sys/file.h>
43 #endif
44
45 #define VICE /* allow us to put our changes in at will */
46
47 #ifdef AFS_SUN_ENV
48 #define KERNEL
49 #endif /* AFS_SUN_ENV */
50 #include <sys/mount.h>
51 #ifdef AFS_SUN_ENV
52 #undef KERNEL
53 #endif
54
55 #ifdef AFS_OSF_ENV
56 #include <sys/vnode.h>
57 #include <sys/mount.h>
58 #include <ufs/inode.h>
59 #include <ufs/fs.h>
60 #else /* AFS_OSF_ENV */
61 #ifdef AFS_VFSINCL_ENV
62 #define VFS
63 #include <sys/vnode.h>
64 #ifdef AFS_SUN5_ENV
65 #include <sys/fs/ufs_inode.h>
66 #include <sys/fs/ufs_fs.h>
67 #define _KERNEL
68 #include <sys/fs/ufs_fsdir.h>
69 #undef _KERNEL
70 #include <sys/fs/ufs_mount.h>
71 #else
72 #include <ufs/inode.h>
73 #include <ufs/fs.h>
74 #define KERNEL
75 #include <ufs/fsdir.h>
76 #undef KERNEL
77 #endif
78 #else /* AFS_VFSINCL_ENV */
79
80 #include <sys/inode.h>
81 #ifndef AFS_HPUX_ENV
82 #define KERNEL
83 #include <sys/dir.h>
84 #undef KERNEL
85 #endif
86 #include <sys/fs.h>
87 #endif /* AFS_VFSINCL_ENV */
88 #endif /* AFS_OSF_ENV */
89
90 #include <sys/wait.h>
91 #ifdef XAFS_SUN_ENV
92 #include <mntent.h>
93 #else
94 #ifdef AFS_SUN5_ENV
95 #include <sys/mnttab.h>
96 #include <sys/mntent.h>
97 #include <sys/vfstab.h>
98 #include <sys/ustat.h>
99 #else
100 #include <fstab.h>
101 #endif
102 #endif
103 #include "fsck.h"
104 #include <sys/signal.h>
105
106 char *rawname(), *unrawname(), *blockcheck();
107 void catch(), catchquit(), voidquit();
108 static int tryForce;
109 int returntosingle;
110
111 extern int errno;
112
113 struct part {
114 char *name; /* device name */
115 char *fsname; /* mounted filesystem name */
116 struct part *next; /* forward link of partitions on disk */
117 } *badlist, **badnext = &badlist;
118
119 struct disk {
120 char *name; /* disk base name */
121 struct disk *next; /* forward link for list of disks */
122 struct part *part; /* head of list of partitions on disk */
123 int pid; /* If != 0, pid of proc working on */
124 } *disks;
125
126 int nrun, ndisks, maxrun, wflag = 0;
127 #ifdef AFS_HPUX_ENV
128 int fixed;
129 #endif
130
131 #if defined(AFS_HPUX100_ENV)
132 #include <ustat.h>
133 #include <mntent.h>
134 #endif
135
136 #ifdef VICE
137 #define msgprintf vfscklogprintf
138 #else /* VICE */
139 #define msgprintf printf
140 #endif /* VICE */
141
142 #ifdef AFS_SUN5_ENV
143 int mnt_passno = 0;
144 #endif
145
146 #include "AFS_component_version_number.c"
147
148 #ifdef AFS_HPUX_ENV
149 int ge_danger = 0; /* on when fsck is not able to fix the dirty file
150 * system within single run. Problems like dup table
151 * overflow, maxdup is exceeding MAXDUP.. etc. could
152 * potentailly prevent fsck from doing a complete
153 * repair. This is found in a GE hotsite. */
154 #endif
155
156 main(argc, argv)
157 int argc;
158 char *argv[];
159 {
160 struct fstab *fsp;
161 int pid, passno, sumstatus;
162 char *name;
163 struct disk *dk, *nextdisk;
164 struct part *pt;
165 extern char *AFSVersion; /* generated version */
166 #ifdef AFS_SUN5_ENV
167 int other_than_ufs = 0;
168 char *subopt;
169 struct vfstab vt;
170 FILE *vfile;
171 int ret;
172 struct vfstab vget;
173 FILE *fd;
174 #endif
175
176 sync();
177 tryForce = 0;
178 #if defined(AFS_HPUX_ENV)
179 pclean = 0;
180 #endif
181 #if defined(AFS_HPUX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV)
182 fflag = 0;
183 #endif
184 #ifdef AFS_SUN5_ENV
185 fsflag = oflag = mflag = exitstat = 0;
186 #endif
187 #if defined(AFS_HPUX100_ENV)
188 mflag = 0;
189 #endif
190 printf("----Open AFS (R) %s fsck----\n", AFSVersion); /* generated version */
191 if (access("/TRYFORCE", 0) == 0)
192 tryForce = 1;
193 while (--argc > 0 && **++argv == '-') {
194 switch (*++*argv) {
195
196 #if defined(AFS_HPUX_ENV)
197 #if defined(AFS_HPUX100_ENV)
198 case 'f': /* default yes to answer force to check */
199 fflag++;
200 break;
201 #else /* AFS_HPUX100_ENV */
202 #ifdef AFS_HPUX_ENV
203 case 'F': /* default yes to answer force to check */
204 fflag++;
205 break;
206 #endif /* AFS_HPUX_ENV */
207 #endif /* AFS_HPUX100_ENV */
208 case 'P':
209 pclean++;
210 preen++;
211 break;
212 #endif
213 case 'p':
214 preen++;
215 break;
216 #if defined(AFS_HPUX100_ENV)
217 case 'V':
218 {
219 int opt_count;
220 char *opt_text;
221
222 (void)fprintf(stdout, "fsck -F hfs ");
223 for (opt_count = 1; opt_count < argc; opt_count++) {
224 opt_text = argv[opt_count];
225 if (opt_text)
226 (void)fprintf(stdout, " %s ", opt_text);
227 }
228 (void)fprintf(stdout, "\n");
229 exit(0);
230 }
231 break;
232 case 'm':
233 mflag++;
234 break;
235 #endif
236 #ifdef AFS_SUN5_ENV
237 case 'V':
238 {
239 int opt_count;
240 char *opt_text;
241
242 (void)fprintf(stdout, "fsck -F ufs ");
243 for (opt_count = 1; opt_count < argc; opt_count++) {
244 opt_text = argv[opt_count];
245 if (opt_text)
246 (void)fprintf(stdout, " %s ", opt_text);
247 }
248 (void)fprintf(stdout, "\n");
249 }
250 break;
251
252 case 'o':
253 subopt = *++argv;
254 argc--;
255 while (*subopt != '\0') {
256 if (*subopt == 'p') {
257 preen++;
258 break;
259 } else if (*subopt == 'b') {
260 if (argv[0][1] != '\0') {
261 bflag = atoi(argv[0] + 1);
262 } else {
263 bflag = atoi(*++argv);
264 argc--;
265 }
266 msgprintf("Alternate super block location: %d\n", bflag);
267 break;
268 } else if (*subopt == 'd') {
269 debug++;
270 break;
271 } else if (*subopt == 'r') {
272 break;
273 } else if (*subopt == 'w') {
274 wflag++;
275 break;
276 } else if (*subopt == 'c') {
277 cvtflag++;
278 break;
279 } else if (*subopt == 'f') {
280 fflag++;
281 break;
282 } else {
283 errexit("-o %c option?\n", *subopt);
284 }
285 subopt++;
286 ++argv;
287 argc--;
288 }
289 oflag++;
290 break;
291 case 'm':
292 mflag++;
293 break;
294 #else
295 case 'b':
296 if (argv[0][1] != '\0') {
297 bflag = atoi(argv[0] + 1);
298 } else {
299 bflag = atoi(*++argv);
300 argc--;
301 }
302 msgprintf("Alternate super block location: %d\n", bflag);
303 break;
304
305 case 'c':
306 cvtflag++;
307 break;
308
309 /* who knows? defined, but doesn't do much */
310 case 'r':
311 break;
312
313 case 'w': /* check writable only */
314 wflag++;
315 break;
316 case 'd':
317 debug++;
318 break;
319 case 'l':
320 if (!isdigit(argv[1][0]))
321 errexit("-l flag requires a number\n");
322 maxrun = atoi(*++argv);
323 argc--;
324 break;
325 #if !defined(AFS_HPUX100_ENV)
326 case 'm':
327 if (!isdigit(argv[1][0]))
328 errexit("-m flag requires a mode\n");
329 sscanf(*++argv, "%o", &lfmode);
330 if (lfmode & ~07777)
331 errexit("bad mode to -m: %o\n", lfmode);
332 argc--;
333 printf("** lost+found creation mode %o\n", lfmode);
334 break;
335 #endif /* AFS_HPUX100_ENV */
336 #endif /* AFS_SUN5_ENV */
337 #ifdef AFS_OSF_ENV
338 case 'o':
339 fflag++;
340 break;
341 #endif /* AFS_OSF_ENV */
342 case 'n':
343 case 'N':
344 nflag++;
345 yflag = 0;
346 break;
347
348 /*
349 * NOTE: -q flag is used only by HPux fsck versions but we add it for all systems since
350 * it's general/useful flag to use.
351 */
352 case 'q':
353 qflag++;
354 break;
355
356 case 'y':
357 case 'Y':
358 yflag++;
359 nflag = 0;
360 break;
361
362 default:
363 errexit("%c option?\n", **argv);
364 }
365 }
366 /*
367 * The following checks were only available on hpux but are useful to all systems.
368 */
369 if (nflag && preen)
370 errexit("Incompatible options: -n and -p\n");
371 if (nflag && qflag)
372 errexit("Incompatible options: -n and -q\n");
373
374 #ifdef AFS_SUN5_ENV
375 rflag++; /* check raw devices */
376 #endif
377 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
378 (void)signal(SIGINT, catch);
379 if (preen)
380 (void)signal(SIGQUIT, catchquit);
381 if (argc) {
382 while (argc-- > 0) {
383 hotroot = 0;
384 #ifdef AFS_SUN5_ENV
385 if (wflag && !writable(*argv)) {
386 (void)fprintf(stderr, "not writable '%s'\n", *argv);
387 argv++;
388 } else
389 #endif
390 checkfilesys(*argv++, NULL);
391 }
392 #ifdef AFS_HPUX_ENV
393 if (ge_danger)
394 exit(-1);
395 #endif
396 #ifdef AFS_SUN5_ENV
397 exit(exitstat);
398 #else
399 exit(0);
400 #endif
401 }
402 #ifndef AFS_SUN5_ENV
403 sumstatus = 0;
404 #ifdef AFS_SUN5_ENV
405 if (fstype == NULL || strcmp(fstype, MNTTYPE_UFS) == 0) {
406 int status;
407
408 if ((fd = fopen(VFSTAB, "r")) == NULL) {
409 errexit("vfsck: cannot open vfstab\n");
410 }
411 while ((ret = getvfsent(fd, &vget)) == 0) {
412 if (strcmp(vget.vfs_fstype, MNTTYPE_UFS)
413 && numbers(vget.vfs_fsckpass)) {
414 other_than_ufs++;
415 continue;
416 }
417 if (numbers(vget.vfs_fsckpass))
418 passno = atoi(vget.vfs_fsckpass);
419 else
420 continue;
421 if (passno < 1)
422 continue;
423 if (preen == 0 || passno == 1) {
424 checkfilesys(vget.vfs_fsckdev, get.vfs_mountp);
425 } else if (passno > 1) {
426 addpart(vget.vfs_fsckdev, vget.vfs_special);
427 }
428 }
429 #else
430 for (passno = 1; passno <= 2; passno++) {
431 if (setfsent() == 0)
432 errexit("Can't open checklist file: %s\n", FSTAB);
433 while ((fsp = getfsent()) != 0) {
434 if (strcmp(fsp->fs_type, FSTAB_RW)
435 && strcmp(fsp->fs_type, FSTAB_RO)
436 && strcmp(fsp->fs_type, FSTAB_RQ))
437 continue;
438 #ifdef AFS_OSF_ENV
439 if (strcmp(fsp->fs_vfstype, "ufs") || fsp->fs_passno == 0) {
440 continue;
441 }
442 #endif /* AFS_OSF_ENV */
443 if (preen == 0 || passno == 1 && fsp->fs_passno == 1) {
444 if (passno == 1) {
445 name = blockcheck(fsp->fs_spec);
446 if (name != NULL) {
447 checkfilesys(name, fsp->fs_file);
448 } else if (preen) {
449 printf("pid %d exiting 8/1\n", getpid());
450 exit(8);
451 }
452 }
453 } else if (passno == 2 && fsp->fs_passno > 1) {
454 name = blockcheck(fsp->fs_spec);
455 if (name == NULL) {
456 pwarn("BAD DISK NAME %s\n", fsp->fs_spec);
457 sumstatus |= 8;
458 printf("pid %d saw bad disk name 8/3\n", getpid());
459 continue;
460 }
461 addpart(name, fsp->fs_file);
462 }
463 }
464 #endif /* AFS_SUN5_ENV */
465 }
466 if (preen) {
467 int status, rc;
468
469 if (maxrun == 0)
470 maxrun = ndisks;
471 if (maxrun > ndisks)
472 maxrun = ndisks;
473 nextdisk = disks;
474 for (passno = 0; passno < maxrun; ++passno) {
475 startdisk(nextdisk);
476 nextdisk = nextdisk->next;
477 }
478 while ((pid = wait(&status)) != -1) {
479 for (dk = disks; dk; dk = dk->next)
480 if (dk->pid == pid)
481 break;
482 if (dk == 0) {
483 printf("Unknown pid %d\n", pid);
484 continue;
485 }
486 rc = WEXITSTATUS(status);
487 if (WIFSIGNALED(status)) {
488 printf("%s (%s): EXITED WITH SIGNAL %d\n", dk->part->name,
489 dk->part->fsname, WTERMSIG(status));
490 rc = 8;
491 }
492 if (rc != 0) {
493 sumstatus |= rc;
494 *badnext = dk->part;
495 badnext = &dk->part->next;
496 dk->part = dk->part->next;
497 *badnext = NULL;
498 } else
499 dk->part = dk->part->next;
500 dk->pid = 0;
501 nrun--;
502 if (dk->part == NULL)
503 ndisks--;
504
505 if (nextdisk == NULL) {
506 if (dk->part)
507 startdisk(dk);
508 } else if (nrun < maxrun && nrun < ndisks) {
509 for (;;) {
510 if ((nextdisk = nextdisk->next) == NULL)
511 nextdisk = disks;
512 if (nextdisk->part != NULL && nextdisk->pid == 0)
513 break;
514 }
515 startdisk(nextdisk);
516 }
517 }
518 }
519 if (sumstatus) {
520 if (badlist == 0) {
521 printf("pid %d exiting 8/2\n", getpid());
522 exit(8);
523 }
524 printf("THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t",
525 badlist->next ? "S" : "", "UNEXPECTED INCONSISTENCY:");
526 for (pt = badlist; pt; pt = pt->next)
527 printf("%s (%s)%s", pt->name, pt->fsname, pt->next ? ", " : "\n");
528 exit(8);
529 }
530 #ifdef AFS_SUN5_ENV
531 fclose(fd);
532 #else
533 (void)endfsent();
534 #endif
535 if (returntosingle)
536 exit(2);
537 #endif /* !AFS_SUN5_ENV */
538 exit(0);
539 }
540
541 struct disk *
542 finddisk(name)
543 char *name;
544 {
545 struct disk *dk, **dkp;
546 char *p;
547 int len;
548
549 for (p = name + strlen(name) - 1; p >= name; --p)
550 if (isdigit(*p)) {
551 len = p - name + 1;
552 break;
553 }
554 if (p < name)
555 len = strlen(name);
556
557 for (dk = disks, dkp = &disks; dk; dkp = &dk->next, dk = dk->next) {
558 if (strncmp(dk->name, name, len) == 0 && dk->name[len] == 0)
559 return (dk);
560 }
561 if ((*dkp = malloc(sizeof(struct disk))) == NULL)
562 errexit("out of memory");
563 dk = *dkp;
564 if ((dk->name = strdup(name)) == NULL)
565 errexit("out of memory");
566 dk->part = NULL;
567 dk->next = NULL;
568 dk->pid = 0;
569 ndisks++;
570 return (dk);
571 }
572
573 addpart(name, fsname)
574 char *name, *fsname;
575 {
576 struct disk *dk = finddisk(name);
577 struct part *pt, **ppt = &dk->part;
578
579 for (pt = dk->part; pt; ppt = &pt->next, pt = pt->next)
580 if (strcmp(pt->name, name) == 0) {
581 printf("%s in fstab more than once!\n", name);
582 return;
583 }
584 if ((*ppt = malloc(sizeof(struct part))) == NULL)
585 errexit("out of memory");
586 pt = *ppt;
587 if ((pt->name = strdup(name)) == NULL)
588 errexit("out of memory");
589 if ((pt->fsname = strdup(fsname)) == NULL)
590 errexit("out of memory");
591 pt->next = NULL;
592 }
593
594 startdisk(dk)
595 struct disk *dk;
596 {
597
598 nrun++;
599 dk->pid = fork();
600 if (dk->pid < 0) {
601 perror("fork");
602 exit(8);
603 }
604 if (dk->pid == 0) {
605 (void)signal(SIGQUIT, voidquit);
606 checkfilesys(dk->part->name, dk->part->fsname);
607 exit(0);
608 }
609 }
610
611 checkfilesys(filesys, parname)
612 char *filesys;
613 {
614 daddr_t n_ffree, n_bfree;
615 struct dups *dp;
616 struct stat tstat; /* for ultrix 3 unmount */
617 struct zlncnt *zlnp;
618 char devbuffer[128];
619 int ret_val;
620
621 #ifdef AFS_OSF_ENV
622 int temp;
623 #endif /* AFS_OSF_ENV */
624
625 #ifdef AFS_SUN_ENV
626 iscorrupt = 1;
627 #endif
628 #ifdef AFS_SUN5_ENV
629 mountedfs = 0;
630 isconvert = 0;
631 #endif
632 #ifdef AFS_HPUX_ENV
633 ge_danger = 0; /* set to 1 by any table overflow or more
634 * dup/bad blocks than expected */
635
636 fixed = 1; /* set to 0 by any 'no' reply */
637 #endif
638 strcpy(devbuffer, filesys); /* copy the file system name to the device buffer */
639 devname = devbuffer; /* remember generic ptr for later */
640 EnsureDevice(devname); /* canonicalize name */
641 if (debug && preen)
642 pinfo("starting\n");
643
644 ret_val = setup(devname);
645
646 if (ret_val == 0) {
647 #ifdef AFS_SUN_ENV
648 if (iscorrupt == 0)
649 return;
650 #endif
651 if (preen)
652 pfatal("CAN'T CHECK FILE SYSTEM.");
653 #ifdef AFS_SUN5_ENV
654 if ((exitstat == 0) && (mflag))
655 exitstat = 32;
656 exit(exitstat);
657 #endif
658 return (0);
659 #ifdef AFS_HPUX_ENV
660 } else if (ret_val == -1) { /* pclean && FS_CLEAN */
661 return (1);
662 #endif
663 #if defined(AFS_OSF_ENV)
664 } else if (ret_val == FS_CLEAN) { /* pclean && FS_CLEAN */
665 return (1);
666 #endif
667 }
668 #if defined(AFS_HPUX100_ENV)
669 if (mflag)
670 check_sanity(filesys);
671 #endif
672
673 #ifdef AFS_SUN5_ENV
674 if (mflag)
675 check_sanity(filesys);
676 if (debug)
677 printclean();
678 #endif
679 #ifdef AFS_SUN_ENV
680 iscorrupt = 0;
681 #endif
682 /*
683 * 1: scan inodes tallying blocks used
684 */
685 if (preen == 0) {
686 #if defined(AFS_SUN5_ENV)
687 if (mountedfs)
688 msgprintf("** Currently Mounted on %s\n", sblock.fs_fsmnt);
689 else
690 #endif
691 msgprintf("** Last Mounted on %s\n", sblock.fs_fsmnt);
692 if (hotroot)
693 msgprintf("** Root file system\n");
694 #ifdef AFS_SUN5_ENV
695 if (mflag) {
696 printf("** Phase 1 - Sanity Check only\n");
697 return;
698 } else
699 #endif
700 msgprintf("** Phase 1 - Check Blocks and Sizes\n");
701 }
702 pass1();
703
704 /*
705 * 1b: locate first references to duplicates, if any
706 */
707 if (duplist) {
708 if (preen)
709 pfatal("INTERNAL ERROR: dups with -p");
710 msgprintf("** Phase 1b - Rescan For More DUPS\n");
711 pass1b();
712 }
713
714 /*
715 * 2: traverse directories from root to mark all connected directories
716 */
717 if (preen == 0)
718 msgprintf("** Phase 2 - Check Pathnames\n");
719 pass2();
720
721 /*
722 * 3: scan inodes looking for disconnected directories
723 */
724 if (preen == 0)
725 msgprintf("** Phase 3 - Check Connectivity\n");
726 pass3();
727
728 /*
729 * 4: scan inodes looking for disconnected files; check reference counts
730 */
731 if (preen == 0)
732 msgprintf("** Phase 4 - Check Reference Counts\n");
733 pass4();
734
735 /*
736 * 5: check and repair resource counts in cylinder groups
737 */
738 if (preen == 0)
739 msgprintf("** Phase 5 - Check Cyl groups\n");
740 pass5();
741
742 #if defined(AFS_SUN_ENV)
743 updateclean();
744 if (debug)
745 printclean();
746 #endif
747 /*
748 * print out summary statistics
749 */
750 n_ffree = sblock.fs_cstotal.cs_nffree;
751 n_bfree = sblock.fs_cstotal.cs_nbfree;
752 #ifdef VICE
753 #if defined(ACLS) && defined(AFS_HPUX_ENV)
754 pinfo("%d files, %d icont, %d used, %d free", n_files, n_cont, n_blks,
755 n_ffree + sblock.fs_frag * n_bfree);
756 #else
757 pinfo("%d files, %d used, %d free", n_files, n_blks,
758 n_ffree + sblock.fs_frag * n_bfree);
759 #endif
760 if (nViceFiles)
761 msgprintf(", %d AFS files", nViceFiles);
762 msgprintf(" (%d frags, %d blocks, %.1f%% fragmentation)\n", n_ffree,
763 n_bfree, (float)(n_ffree * 100) / sblock.fs_dsize);
764 #else /* VICE */
765 #if defined(ACLS) && defined(AFS_HPUX_ENV)
766 pinfo("%d files, %d icont, %d used, %d free ", n_files, n_cont, n_blks,
767 n_ffree + sblock.fs_frag * n_bfree);
768 #else
769 pinfo("%d files, %d used, %d free ", n_files, n_blks,
770 n_ffree + sblock.fs_frag * n_bfree);
771 #endif
772 n printf("(%d frags, %d blocks, %.1f%% fragmentation)\n", n_ffree,
773 n_bfree, (float)(n_ffree * 100) / sblock.fs_dsize);
774 #endif /* VICE */
775 if (debug && (n_files -= maxino - ROOTINO - sblock.fs_cstotal.cs_nifree))
776 msgprintf("%d files missing\n", n_files);
777 if (debug) {
778 n_blks += sblock.fs_ncg * (cgdmin(&sblock, 0) - cgsblock(&sblock, 0));
779 n_blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0);
780 n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize);
781 if (n_blks -= maxfsblock - (n_ffree + sblock.fs_frag * n_bfree))
782 printf("%d blocks missing\n", n_blks);
783 if (duplist != NULL) {
784 msgprintf("The following duplicate blocks remain:");
785 for (dp = duplist; dp; dp = dp->next)
786 msgprintf(" %d,", dp->dup);
787 msgprintf("\n");
788 }
789 if (zlnhead != NULL) {
790 msgprintf("The following zero link count inodes remain:");
791 for (zlnp = zlnhead; zlnp; zlnp = zlnp->next)
792 msgprintf(" %d,", zlnp->zlncnt);
793 msgprintf("\n");
794 }
795 }
796 #ifdef AFS_HPUX_ENV
797 /* if user's specification denotes that the file system block
798 * is going to be modified (nflag == 0) then fsck store the
799 * correct magic number in the super block if it is not already
800 * there
801 */
802 if (!nflag && !(fswritefd < 0)) {
803 if (ge_danger) {
804 printf("***** FILE SYSTEM IS NOT CLEAN, FSCK AGAIN *****\n");
805 fsmodified++;
806 } else {
807 if (!hotroot) {
808 if (fixed && (sblock.fs_clean != FS_CLEAN)) {
809 if (!preen && !qflag)
810 printf("***** MARKING FILE SYSTEM CLEAN *****\n");
811 sblock.fs_clean = FS_CLEAN;
812 fsmodified++;
813 }
814 } else {
815 /* fix FS_CLEAN if changes made and no 'no' replies */
816 if (fsmodified && fixed)
817 sblock.fs_clean = FS_CLEAN;
818 /*
819 * Fix fs_clean if there were no 'no' replies.
820 * This is done for both the s300 and s800. The s800 root will be
821 * guaranteed clean as of 7.0.
822 */
823 if (fixed && (sblock.fs_clean != FS_OK)) {
824 if (!preen && !qflag)
825 printf("***** MARKING FILE SYSTEM CLEAN *****\n");
826 sblock.fs_clean = FS_CLEAN;
827 fsmodified++;
828 }
829 }
830 }
831 }
832 #endif
833 zlnhead = NULL;
834 duplist = NULL;
835
836 #if defined(AFS_SUN_ENV) && !defined(AFS_SUN3_ENV) /* WAS AFS_SUN5_ENV */
837 #ifdef notdef
838 inocleanup();
839 #endif
840 if (fsmodified)
841 fixstate = 1;
842 else
843 fixstate = 0;
844 if (hotroot && sblock.fs_clean == FSACTIVE)
845 rebflg = 1;
846 #ifdef AFS_SUN5_ENV
847 else if (!((sblock.fs_state + (afs_int32) sblock.fs_time == FSOKAY) &&
848 #else
849 else if (!((fs_get_state(&sblock) + (afs_int32) sblock.fs_time == FSOKAY)
850 &&
851 #endif
852 (sblock.fs_clean == FSCLEAN || sblock.fs_clean == FSSTABLE))) {
853 if (yflag || !iscorrupt) {
854 printf("%s FILE SYSTEM STATE SET TO OKAY\n", devname);
855 fixstate = 1;
856 } else {
857 printf("%s FILE SYSTEM STATE NOT SET TO OKAY\n", devname);
858 fixstate = 0;
859 }
860 }
861 if (fixstate) {
862 (void)time(&sblock.fs_time);
863 if (!iscorrupt) {
864 if (hotroot && rebflg)
865 sblock.fs_clean = FSACTIVE;
866 else
867 sblock.fs_clean = FSSTABLE;
868 #ifdef AFS_SUN5_ENV
869 sblock.fs_state = FSOKAY - (afs_int32) sblock.fs_time;
870 #else
871 fs_set_state(&sblock, FSOKAY - (afs_int32) sblock.fs_time);
872 #endif
873 }
874 sbdirty();
875 }
876 #else
877 #ifdef AFS_OSF_ENV
878 if (!nflag && !bflag && !hotroot) {
879 temp = fsmodified;
880 sblock.fs_clean = FS_CLEAN;
881 (void)time(&sblock.fs_time);
882 sbdirty();
883 flush(fswritefd, &sblk);
884 fsmodified = temp;
885 }
886 #else /* AFS_OSF_ENV */
887 if (fsmodified) {
888 (void)time(&sblock.fs_time);
889 sbdirty();
890 }
891 #endif
892 #endif
893 ckfini();
894 free(blockmap);
895 free(statemap);
896 free(lncntp);
897 lncntp = NULL;
898 blockmap = statemap = NULL;
899 #ifdef AFS_SUN5_ENV
900 if (iscorrupt)
901 exitstat = 36;
902 #endif
903 if (!fsmodified)
904 return;
905 if (!preen) {
906 msgprintf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
907
908 if (hotroot)
909 msgprintf("\n***** REBOOT UNIX *****\n");
910 }
911 #ifdef AFS_SUN5_ENV
912 if (mountedfs || hotroot) {
913 exitstat = 40;
914 }
915 #endif
916 if (hotroot) {
917 sync();
918 #ifdef AFS_HPUX_ENV
919 if (ge_danger)
920 exit(-1);
921 else
922 #endif
923 #ifdef AFS_SUN5_ENV
924 exit(exitstat);
925 #else
926 exit(4);
927 #endif
928 }
929 #ifdef VICE
930 (void)close(fsreadfd);
931 (void)close(fswritefd);
932 if (nViceFiles || tryForce) {
933 /* Modified file system with vice files: force full salvage */
934 /* Salvager recognizes the file FORCESALVAGE in the root of each partition */
935 struct ufs_args ufsargs;
936
937 char pname[100], fname[100], *special;
938 int fd, code, failed = 0;
939
940 msgprintf
941 ("%s: AFS file system partition was modified; forcing full salvage\n",
942 devname);
943 devname = unrawname(devname);
944 special = (char *)strrchr(devname, '/');
945 if (!special++)
946 special = devname;
947 strcpy(pname, "/etc/vfsck."); /* Using /etc, rather than /tmp, since
948 * /tmp is a link to /usr/tmp on some systems, and isn't mounted now */
949 strcat(pname, special);
950 #ifdef AFS_SUN_ENV
951 /* if system mounted / as read-only, we'll try to fix now */
952 if (access("/", W_OK) < 0 && errno == EROFS) {
953 code = system("mount -o remount /");
954 if (code) {
955 printf("Couldn't remount / R/W; continuing anyway (%d).\n",
956 errno);
957 failed = 1;
958 }
959 }
960 #endif
961 #ifdef AFS_OSF_ENV
962 /* if system mounted / as read-only, we'll try to fix now */
963 if (access("/", W_OK) < 0 && errno == EROFS) {
964 printf("Can't RW acceess /; %d\n", errno);
965 code = system("/sbin/mount -u /");
966 if (code) {
967 printf("Couldn't remount / R/W; continuing anyway (%d).\n",
968 errno);
969 failed = 1;
970 }
971 }
972 #endif
973 rmdir(pname);
974 unlink(pname);
975 if (mkdir(pname, 0777) < 0) {
976 if (errno != EEXIST) {
977 perror("fsck mkdir");
978 failed = 1;
979 }
980 }
981 if (failed && parname) {
982 strcpy(pname, parname);
983 }
984 #if !defined(AFS_HPUX_ENV)
985 #ifdef AFS_SUN5_ENV
986 ufsargs.flags = UFSMNT_NOINTR;
987 #else
988 ufsargs.fspec = devname;
989 #endif
990 #ifdef AFS_SUN5_ENV
991 if (mount
992 (devname, pname, MS_DATA, "ufs", (char *)&ufsargs,
993 sizeof(ufsargs)) < 0) {
994 #else
995 if (mount(MOUNT_UFS, pname, 0, &ufsargs) < 0) {
996 #endif
997 #else
998 if (mount(devname, pname, 0) < 0) {
999 #endif
1000 printf
1001 ("Couldn't mount %s on %s to force FULL SALVAGE; continuing anyway (%d)!\n",
1002 devname, pname, errno);
1003 } else {
1004 strcpy(fname, pname);
1005 strcat(fname, "/FORCESALVAGE");
1006 fd = open(fname, O_CREAT, 0);
1007 if (fd == -1) {
1008 errexit("Couldn't create %s to force full salvage!\n", fname);
1009 } else {
1010 fstat(fd, &tstat);
1011 close(fd);
1012 }
1013 #if !defined(AFS_HPUX_ENV) && !defined(AFS_SUN5_ENV) && !defined(AFS_OSF_ENV)
1014 unmount(pname);
1015 #else
1016 #if defined(AFS_OSF_ENV)
1017 umount(pname, MNT_NOFORCE);
1018 #else /* AFS_OSF_ENV */
1019 umount(devname);
1020 #endif
1021 #endif
1022 }
1023 rmdir(pname);
1024 }
1025 if (logfile) {
1026 fsync(fileno(logfile)); /* Since update isn't running */
1027 fclose(logfile);
1028 logfile = 0;
1029 }
1030 #endif /* VICE */
1031
1032 }
1033
1034 char *
1035 blockcheck(name)
1036 char *name;
1037 {
1038 struct stat stslash, stblock, stchar;
1039 char *raw;
1040 int retried = 0;
1041
1042 hotroot = 0;
1043 if (stat("/", &stslash) < 0) {
1044 perror("/");
1045 printf("Can't stat root\n");
1046 return (0);
1047 }
1048 retry:
1049 if (stat(name, &stblock) < 0) {
1050 perror(name);
1051 printf("Can't stat %s\n", name);
1052 return (0);
1053 }
1054 if ((stblock.st_mode & S_IFMT) == S_IFBLK) {
1055 if (stslash.st_dev == stblock.st_rdev) {
1056 hotroot++;
1057 #if !defined(AFS_OSF_ENV) /* OSF/1 always uses the raw device, even for / */
1058 return (name);
1059 #endif /* AFS_OSF_ENV */
1060 }
1061 raw = rawname(name);
1062 if (raw) {
1063 return (raw);
1064 } else {
1065 printf("Cannot find character device for %s\n", name);
1066 return (name);
1067 }
1068 } else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) {
1069 name = unrawname(name);
1070 retried++;
1071 goto retry;
1072 }
1073 printf("Can't make sense out of name %s\n", name);
1074 return (0);
1075 }
1076
1077
1078 #if defined(AFS_HPUX_ENV) || defined(AFS_SUN5_ENV)
1079
1080 #ifdef AFS_SUN5_ENV
1081 /*
1082 * exit 0 - file system is unmounted and okay
1083 * exit 32 - file system is unmounted and needs checking
1084 * exit 33 - file system is mounted for root file system
1085 * exit 34 - cannot stat device
1086 */
1087 check_sanity(filename)
1088 char *filename;
1089 {
1090 struct stat stbd, stbr;
1091 struct ustat usb;
1092 char *devname;
1093 struct vfstab vfsbuf;
1094 FILE *vfstab;
1095 int is_root = 0;
1096 int is_usr = 0;
1097 int is_block = 0;
1098
1099 if (stat(filename, &stbd) < 0) {
1100 fprintf(stderr, "ufs fsck: sanity check failed : cannot stat %s\n",
1101 filename);
1102 exit(34);
1103 }
1104
1105 if ((stbd.st_mode & S_IFMT) == S_IFBLK)
1106 is_block = 1;
1107 else if ((stbd.st_mode & S_IFMT) == S_IFCHR)
1108 is_block = 0;
1109 else {
1110 fprintf(stderr,
1111 "ufs fsck: sanity check failed: %s not block or character device\n",
1112 filename);
1113 exit(34);
1114 }
1115 /*
1116 * Determine if this is the root file system via vfstab. Give up
1117 * silently on failures. The whole point of this is not to care
1118 * if the root file system is already mounted.
1119 *
1120 * XXX - similar for /usr. This should be fixed to simply return
1121 * a new code indicating, mounted and needs to be checked.
1122 */
1123 if ((vfstab = fopen(VFSTAB, "r")) != 0) {
1124 if (getvfsfile(vfstab, &vfsbuf, "/") == 0) {
1125 if (is_block)
1126 devname = vfsbuf.vfs_special;
1127 else
1128 devname = vfsbuf.vfs_fsckdev;
1129 if (stat(devname, &stbr) == 0)
1130 if (stbr.st_rdev == stbd.st_rdev)
1131 is_root = 1;
1132 }
1133 if (getvfsfile(vfstab, &vfsbuf, "/usr") == 0) {
1134 if (is_block)
1135 devname = vfsbuf.vfs_special;
1136 else
1137 devname = vfsbuf.vfs_fsckdev;
1138 if (stat(devname, &stbr) == 0)
1139 if (stbr.st_rdev == stbd.st_rdev)
1140 is_usr = 1;
1141 }
1142 }
1143
1144 /* XXX - only works if filename is a block device or if
1145 * character and block device has the same dev_t value */
1146 if (is_root == 0 && is_usr == 0 && ustat(stbd.st_rdev, &usb) == 0) {
1147 fprintf(stderr, "ufs fsck: sanity check: %s already mounted\n",
1148 filename);
1149 exit(33);
1150 }
1151 /*
1152 * We mount the ufs root file system read-only first. After fsck
1153 * runs, we remount the root as read-write. Therefore, we no longer
1154 * check for different values for fs_state between the root file
1155 * system and the rest of file systems.
1156 */
1157 if (!((sblock.fs_state + (time_t) sblock.fs_time == FSOKAY)
1158 && (sblock.fs_clean == FSCLEAN || sblock.fs_clean == FSSTABLE))) {
1159 fprintf(stderr, "ufs fsck: sanity check: %s needs checking\n",
1160 filename);
1161 exit(32);
1162 }
1163 fprintf(stderr, "ufs fsck: sanity check: %s okay\n", filename);
1164 exit(0);
1165 }
1166 #endif
1167
1168 #if defined(AFS_HPUX100_ENV)
1169 check_sanity(filename)
1170 char *filename;
1171 {
1172 struct stat stbd, stbr;
1173 struct ustat usb;
1174 char *devname;
1175 FILE *vfstab;
1176 struct mntent *mnt;
1177 int is_root = 0;
1178 int is_usr = 0;
1179 int is_block = 0;
1180
1181 if (stat(filename, &stbd) < 0) {
1182 fprintf(stderr, "hfs fsck: sanity check failed : cannot stat %s\n",
1183 filename);
1184 exit(34);
1185 }
1186
1187 if ((stbd.st_mode & S_IFMT) == S_IFBLK)
1188 is_block = 1;
1189 else if ((stbd.st_mode & S_IFMT) == S_IFCHR)
1190 is_block = 0;
1191 else {
1192 fprintf(stderr,
1193 "hfs fsck: sanity check failed: %s not block or character device\n",
1194 filename);
1195 exit(34);
1196 }
1197 /*
1198 * Determine if this is the root file system via vfstab. Give up
1199 * silently on failures. The whole point of this is not to care
1200 * if the root file system is already mounted.
1201 *
1202 * XXX - similar for /usr. This should be fixed to simply return
1203 * a new code indicating, mounted and needs to be checked.
1204 */
1205 if ((vfstab = setmntent(FSTAB, "r")) != 0) {
1206 while (mnt = getmntent(vfstab)) {
1207 if (!strcmp(mnt->mnt_dir, "/"))
1208 if (stat(mnt->mnt_fsname, &stbr) == 0)
1209 if (stbr.st_rdev == stbd.st_rdev)
1210 is_root = 1;
1211
1212 if (!strcmp(mnt->mnt_dir, "/usr"))
1213 if (stat(mnt->mnt_fsname, &stbr) == 0)
1214 if (stbr.st_rdev == stbd.st_rdev)
1215 is_usr = 1;
1216 }
1217 endmntent(vfstab);
1218 }
1219
1220 /* XXX - only works if filename is a block device or if
1221 * character and block device has the same dev_t value */
1222 if (is_root == 0 && is_usr == 0 && ustat(stbd.st_rdev, &usb) == 0) {
1223 fprintf(stderr, "hfs fsck: sanity check: %s already mounted\n",
1224 filename);
1225 exit(33);
1226 }
1227 /*
1228 * We mount the ufs root file system read-only first. After fsck
1229 * runs, we remount the root as read-write. Therefore, we no longer
1230 * check for different values for fs_state between the root file
1231 * system and the rest of file systems.
1232 */
1233 if (!((sblock.fs_clean == FS_CLEAN || sblock.fs_clean == FS_OK))) {
1234 fprintf(stderr, "hfs fsck: sanity check: %s needs checking\n",
1235 filename);
1236 exit(32);
1237 }
1238 fprintf(stderr, "hfs fsck: sanity check: %s okay\n", filename);
1239 exit(0);
1240 }
1241 #endif
1242 /* see if all numbers */
1243 numbers(yp)
1244 char *yp;
1245 {
1246 if (yp == NULL)
1247 return (0);
1248 while ('0' <= *yp && *yp <= '9')
1249 yp++;
1250 if (*yp)
1251 return (0);
1252 return (1);
1253 }
1254 #endif
1255
1256 /* Convert a raw device name into a block device name.
1257 * If the block device is not found, return the raw device name.
1258 * For HP and SUN, the returned value is not changed. For other
1259 * platforms it is changed (I see no rhyme or reason -jpm).
1260 */
1261 char *
1262 unrawname(rawdev)
1263 char *rawdev;
1264 {
1265 static char bldev[256];
1266 struct stat statbuf;
1267 int code, i;
1268
1269 code = stat(rawdev, &statbuf);
1270 if ((code < 0) || !S_ISCHR(statbuf.st_mode))
1271 return (rawdev); /* Not a char device */
1272
1273 for (i = strlen(rawdev) - 2; i >= 0; i--) {
1274 if ((rawdev[i] == '/') && (rawdev[i + 1] == 'r')) {
1275 strcpy(bldev, rawdev);
1276 bldev[i + 1] = 0;
1277 strcat(bldev, &rawdev[i + 2]);
1278
1279 code = stat(bldev, &statbuf); /* test for block device */
1280 if (!code && S_ISBLK(statbuf.st_mode)) {
1281 #if defined(AFS_HPUX_ENV) || defined(AFS_SUN5_ENV)
1282 return (bldev);
1283 #else
1284 strcpy(rawdev, bldev); /* Replace */
1285 return (rawdev);
1286 #endif
1287 }
1288 }
1289 }
1290 return (rawdev);
1291 }
1292
1293 /* Convert a block device name into a raw device name.
1294 * If the block device is not found, return null
1295 */
1296 char *
1297 rawname(bldev)
1298 char *bldev;
1299 {
1300 static char rawdev[256];
1301 struct stat statbuf;
1302 int code, i;
1303
1304 for (i = strlen(bldev) - 1; i >= 0; i--) {
1305 if (bldev[i] == '/') {
1306 strcpy(rawdev, bldev);
1307 rawdev[i + 1] = 'r';
1308 rawdev[i + 2] = 0;
1309 strcat(rawdev, &bldev[i + 1]);
1310
1311 code = stat(rawdev, &statbuf);
1312 if (!code && S_ISCHR(statbuf.st_mode))
1313 return (rawdev);
1314 }
1315 }
1316 return NULL;
1317 }