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