fileserver & friends: Don't cast from malloc()
[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 }