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