reindent-20030715
[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 #ifdef AFS_DEC_ENV
84 #include <sys/fs_types.h>
85 #endif
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 #if     defined(AFS_DEC_ENV)
219             /* On the late versions of Ultrix they changed the defn of '-p' a bit. Particularly,
220              * -p is used to check a file system that was not unmounted cleanly, and they added,
221              * -P to check a file system regardless of how it was unmounted; this, unfortunately,
222              * is identical to '-p' on the rest of the systems but we have to maintain vendor's
223              * semantics so we leave it the way Dec likes it.
224              */
225         case 'p':
226             only_when_needed++;
227             /* P is for Ultrix compatibility */
228         case 'P':
229 #else
230         case 'p':
231 #endif
232             preen++;
233             break;
234 #if     defined(AFS_HPUX100_ENV)
235         case 'V':
236             {
237                 int opt_count;
238                 char *opt_text;
239
240                 (void)fprintf(stdout, "fsck -F hfs ");
241                 for (opt_count = 1; opt_count < argc; opt_count++) {
242                     opt_text = argv[opt_count];
243                     if (opt_text)
244                         (void)fprintf(stdout, " %s ", opt_text);
245                 }
246                 (void)fprintf(stdout, "\n");
247                 exit(0);
248             }
249             break;
250         case 'm':
251             mflag++;
252             break;
253 #endif
254 #ifdef  AFS_SUN5_ENV
255         case 'V':
256             {
257                 int opt_count;
258                 char *opt_text;
259
260                 (void)fprintf(stdout, "fsck -F ufs ");
261                 for (opt_count = 1; opt_count < argc; opt_count++) {
262                     opt_text = argv[opt_count];
263                     if (opt_text)
264                         (void)fprintf(stdout, " %s ", opt_text);
265                 }
266                 (void)fprintf(stdout, "\n");
267             }
268             break;
269
270         case 'o':
271             subopt = *++argv;
272             argc--;
273             while (*subopt != '\0') {
274                 if (*subopt == 'p') {
275                     preen++;
276                     break;
277                 } else if (*subopt == 'b') {
278                     if (argv[0][1] != '\0') {
279                         bflag = atoi(argv[0] + 1);
280                     } else {
281                         bflag = atoi(*++argv);
282                         argc--;
283                     }
284                     msgprintf("Alternate super block location: %d\n", bflag);
285                     break;
286                 } else if (*subopt == 'd') {
287                     debug++;
288                     break;
289                 } else if (*subopt == 'r') {
290                     break;
291                 } else if (*subopt == 'w') {
292                     wflag++;
293                     break;
294                 } else if (*subopt == 'c') {
295                     cvtflag++;
296                     break;
297                 } else if (*subopt == 'f') {
298                     fflag++;
299                     break;
300                 } else {
301                     errexit("-o %c option?\n", *subopt);
302                 }
303                 subopt++;
304                 ++argv;
305                 argc--;
306             }
307             oflag++;
308             break;
309         case 'm':
310             mflag++;
311             break;
312 #else
313         case 'b':
314             if (argv[0][1] != '\0') {
315                 bflag = atoi(argv[0] + 1);
316             } else {
317                 bflag = atoi(*++argv);
318                 argc--;
319             }
320             msgprintf("Alternate super block location: %d\n", bflag);
321             break;
322
323         case 'c':
324             cvtflag++;
325             break;
326
327             /* who knows?  defined, but doesn't do much */
328         case 'r':
329             break;
330
331         case 'w':               /* check writable only */
332             wflag++;
333             break;
334         case 'd':
335             debug++;
336             break;
337         case 'l':
338             if (!isdigit(argv[1][0]))
339                 errexit("-l flag requires a number\n");
340             maxrun = atoi(*++argv);
341             argc--;
342             break;
343 #if     !defined(AFS_HPUX100_ENV)
344         case 'm':
345             if (!isdigit(argv[1][0]))
346                 errexit("-m flag requires a mode\n");
347             sscanf(*++argv, "%o", &lfmode);
348             if (lfmode & ~07777)
349                 errexit("bad mode to -m: %o\n", lfmode);
350             argc--;
351             printf("** lost+found creation mode %o\n", lfmode);
352             break;
353 #endif /* AFS_HPUX100_ENV */
354 #endif /* AFS_SUN5_ENV */
355 #ifdef  AFS_OSF_ENV
356         case 'o':
357             fflag++;
358             break;
359 #endif /* AFS_OSF_ENV */
360         case 'n':
361         case 'N':
362             nflag++;
363             yflag = 0;
364             break;
365
366             /*
367              * NOTE: -q flag is used only by HPux fsck versions but we add it for all systems since
368              * it's general/useful flag to use.
369              */
370         case 'q':
371             qflag++;
372             break;
373
374         case 'y':
375         case 'Y':
376             yflag++;
377             nflag = 0;
378             break;
379
380         default:
381             errexit("%c option?\n", **argv);
382         }
383     }
384     /*
385      * The following checks were only available on hpux but are useful to all systems.
386      */
387     if (nflag && preen)
388         errexit("Incompatible options: -n and -p\n");
389     if (nflag && qflag)
390         errexit("Incompatible options: -n and -q\n");
391
392 #ifdef  AFS_SUN5_ENV
393     rflag++;                    /* check raw devices */
394 #endif
395     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
396         (void)signal(SIGINT, catch);
397     if (preen)
398         (void)signal(SIGQUIT, catchquit);
399     if (argc) {
400         while (argc-- > 0) {
401             hotroot = 0;
402 #ifdef  AFS_SUN5_ENV
403             if (wflag && !writable(*argv)) {
404                 (void)fprintf(stderr, "not writeable '%s'\n", *argv);
405                 argv++;
406             } else
407 #endif
408                 checkfilesys(*argv++, NULL);
409         }
410 #ifdef  AFS_HPUX_ENV
411         if (ge_danger)
412             exit(-1);
413 #endif
414 #ifdef  AFS_SUN5_ENV
415         exit(exitstat);
416 #else
417         exit(0);
418 #endif
419     }
420 #ifndef AFS_SUN5_ENV
421     sumstatus = 0;
422 #ifdef  AFS_SUN5_ENV
423     if (fstype == NULL || strcmp(fstype, MNTTYPE_UFS) == 0) {
424         int status;
425
426         if ((fd = fopen(VFSTAB, "r")) == NULL) {
427             errexit("vfsck: cannot open vfstab\n");
428         }
429         while ((ret = getvfsent(fd, &vget)) == 0) {
430             if (strcmp(vget.vfs_fstype, MNTTYPE_UFS)
431                 && numbers(vget.vfs_fsckpass)) {
432                 other_than_ufs++;
433                 continue;
434             }
435             if (numbers(vget.vfs_fsckpass))
436                 passno = atoi(vget.vfs_fsckpass);
437             else
438                 continue;
439             if (passno < 1)
440                 continue;
441             if (preen == 0 || passno == 1) {
442                 checkfilesys(vget.vfs_fsckdev, get.vfs_mountp);
443             } else if (passno > 1) {
444                 addpart(vget.vfs_fsckdev, vget.vfs_special);
445             }
446         }
447 #else
448     for (passno = 1; passno <= 2; passno++) {
449         if (setfsent() == 0)
450             errexit("Can't open checklist file: %s\n", FSTAB);
451         while ((fsp = getfsent()) != 0) {
452             if (strcmp(fsp->fs_type, FSTAB_RW)
453                 && strcmp(fsp->fs_type, FSTAB_RO)
454                 && strcmp(fsp->fs_type, FSTAB_RQ))
455                 continue;
456 #ifdef  AFS_DEC_ENV
457             /* Only check local (i.e. ufs) file systems */
458             if (strcmp(fsp->fs_name, "4.2") && strcmp(fsp->fs_name, "ufs"))
459                 continue;
460 #endif
461 #ifdef  AFS_OSF_ENV
462             if (strcmp(fsp->fs_vfstype, "ufs") || fsp->fs_passno == 0) {
463                 continue;
464             }
465 #endif /* AFS_OSF_ENV */
466             if (preen == 0 || passno == 1 && fsp->fs_passno == 1) {
467                 if (passno == 1) {
468                     name = blockcheck(fsp->fs_spec);
469                     if (name != NULL) {
470                         checkfilesys(name, fsp->fs_file);
471                     } else if (preen) {
472                         printf("pid %d exiting 8/1\n", getpid());
473                         exit(8);
474                     }
475                 }
476             } else if (passno == 2 && fsp->fs_passno > 1) {
477                 name = blockcheck(fsp->fs_spec);
478                 if (name == NULL) {
479                     pwarn("BAD DISK NAME %s\n", fsp->fs_spec);
480                     sumstatus |= 8;
481                     printf("pid %d saw bad disk name 8/3\n", getpid());
482                     continue;
483                 }
484                 addpart(name, fsp->fs_file);
485             }
486         }
487 #endif /* AFS_SUN5_ENV */
488     }
489     if (preen) {
490         int status, rc;
491
492         if (maxrun == 0)
493             maxrun = ndisks;
494         if (maxrun > ndisks)
495             maxrun = ndisks;
496         nextdisk = disks;
497         for (passno = 0; passno < maxrun; ++passno) {
498             startdisk(nextdisk);
499             nextdisk = nextdisk->next;
500         }
501         while ((pid = wait(&status)) != -1) {
502             for (dk = disks; dk; dk = dk->next)
503                 if (dk->pid == pid)
504                     break;
505             if (dk == 0) {
506                 printf("Unknown pid %d\n", pid);
507                 continue;
508             }
509             rc = WEXITSTATUS(status);
510             if (WIFSIGNALED(status)) {
511                 printf("%s (%s): EXITED WITH SIGNAL %d\n", dk->part->name,
512                        dk->part->fsname, WTERMSIG(status));
513                 rc = 8;
514             }
515             if (rc != 0) {
516                 sumstatus |= rc;
517                 *badnext = dk->part;
518                 badnext = &dk->part->next;
519                 dk->part = dk->part->next;
520                 *badnext = NULL;
521             } else
522                 dk->part = dk->part->next;
523             dk->pid = 0;
524             nrun--;
525             if (dk->part == NULL)
526                 ndisks--;
527
528             if (nextdisk == NULL) {
529                 if (dk->part)
530                     startdisk(dk);
531             } else if (nrun < maxrun && nrun < ndisks) {
532                 for (;;) {
533                     if ((nextdisk = nextdisk->next) == NULL)
534                         nextdisk = disks;
535                     if (nextdisk->part != NULL && nextdisk->pid == 0)
536                         break;
537                 }
538                 startdisk(nextdisk);
539             }
540         }
541     }
542     if (sumstatus) {
543         if (badlist == 0) {
544             printf("pid %d exiting 8/2\n", getpid());
545             exit(8);
546         }
547         printf("THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t",
548                badlist->next ? "S" : "", "UNEXPECTED INCONSISTENCY:");
549         for (pt = badlist; pt; pt = pt->next)
550             printf("%s (%s)%s", pt->name, pt->fsname, pt->next ? ", " : "\n");
551         exit(8);
552     }
553 #ifdef  AFS_SUN5_ENV
554     fclose(fd);
555 #else
556     (void)endfsent();
557 #endif
558     if (returntosingle)
559         exit(2);
560 #endif /* !AFS_SUN5_ENV */
561     exit(0);
562 }
563
564 struct disk *
565 finddisk(name)
566      char *name;
567 {
568     register struct disk *dk, **dkp;
569     register char *p;
570     int len;
571
572     for (p = name + strlen(name) - 1; p >= name; --p)
573         if (isdigit(*p)) {
574             len = p - name + 1;
575             break;
576         }
577     if (p < name)
578         len = strlen(name);
579
580     for (dk = disks, dkp = &disks; dk; dkp = &dk->next, dk = dk->next) {
581         if (strncmp(dk->name, name, len) == 0 && dk->name[len] == 0)
582             return (dk);
583     }
584     if ((*dkp = (struct disk *)malloc(sizeof(struct disk))) == NULL)
585         errexit("out of memory");
586     dk = *dkp;
587     if ((dk->name = malloc((unsigned int)len + 1)) == NULL)
588         errexit("out of memory");
589     strncpy(dk->name, name, len);
590     dk->name[len] = '\0';
591     dk->part = NULL;
592     dk->next = NULL;
593     dk->pid = 0;
594     ndisks++;
595     return (dk);
596 }
597
598 addpart(name, fsname)
599      char *name, *fsname;
600 {
601     struct disk *dk = finddisk(name);
602     register struct part *pt, **ppt = &dk->part;
603
604     for (pt = dk->part; pt; ppt = &pt->next, pt = pt->next)
605         if (strcmp(pt->name, name) == 0) {
606             printf("%s in fstab more than once!\n", name);
607             return;
608         }
609     if ((*ppt = (struct part *)malloc(sizeof(struct part))) == NULL)
610         errexit("out of memory");
611     pt = *ppt;
612     if ((pt->name = malloc((unsigned int)strlen(name) + 1)) == NULL)
613         errexit("out of memory");
614     strcpy(pt->name, name);
615     if ((pt->fsname = malloc((unsigned int)strlen(fsname) + 1)) == NULL)
616         errexit("out of memory");
617     strcpy(pt->fsname, fsname);
618     pt->next = NULL;
619 }
620
621 startdisk(dk)
622      register struct disk *dk;
623 {
624
625     nrun++;
626     dk->pid = fork();
627     if (dk->pid < 0) {
628         perror("fork");
629         exit(8);
630     }
631     if (dk->pid == 0) {
632         (void)signal(SIGQUIT, voidquit);
633         checkfilesys(dk->part->name, dk->part->fsname);
634         exit(0);
635     }
636 }
637
638 checkfilesys(filesys, parname)
639      char *filesys;
640 {
641     daddr_t n_ffree, n_bfree;
642     struct dups *dp;
643     struct stat tstat;          /* for ultrix 3 unmount */
644     struct zlncnt *zlnp;
645     char devbuffer[128];
646     int ret_val;
647 #ifdef  AFS_DEC_ENV
648     int retries = 3;            /* # of retries fora clean fsck pass */
649     int fsdirty = 0;            /* file system was or is dirty */
650     int rootdirty = 0;          /* Root was or is dirty */
651 #endif
652
653 #ifdef  AFS_OSF_ENV
654     int temp;
655 #endif /* AFS_OSF_ENV */
656
657 #ifdef  AFS_SUN_ENV
658     iscorrupt = 1;
659 #endif
660 #ifdef  AFS_SUN5_ENV
661     mountedfs = 0;
662     isconvert = 0;
663 #endif
664 #ifdef  AFS_HPUX_ENV
665     ge_danger = 0;              /* set to 1 by any table overflow or more 
666                                  * dup/bad blocks than expected */
667
668     fixed = 1;                  /* set to 0 by any 'no' reply */
669 #endif
670     strcpy(devbuffer, filesys); /* copy the file system name to the device buffer */
671     devname = devbuffer;        /* remember generic ptr for later */
672     EnsureDevice(devname);      /* canonicalize name */
673     if (debug && preen)
674         pinfo("starting\n");
675 #ifdef  AFS_DEC_ENV
676     for (; retries > 0; retries--) {    /* 003 - Loop for NUMRETRIES or until clean */
677 #endif
678
679         ret_val = setup(devname);
680
681         if (ret_val == 0) {
682 #ifdef  AFS_SUN_ENV
683             if (iscorrupt == 0)
684                 return;
685 #endif
686             if (preen)
687                 pfatal("CAN'T CHECK FILE SYSTEM.");
688 #ifdef  AFS_SUN5_ENV
689             if ((exitstat == 0) && (mflag))
690                 exitstat = 32;
691             exit(exitstat);
692 #endif
693             return (0);
694 #ifdef  AFS_HPUX_ENV
695         } else if (ret_val == -1) {     /* pclean && FS_CLEAN */
696             return (1);
697 #endif
698 #if     defined(AFS_DEC_ENV) || defined(AFS_OSF_ENV)
699         } else if (ret_val == FS_CLEAN) {       /* pclean && FS_CLEAN */
700             return (1);
701 #endif
702         }
703 #if     defined(AFS_HPUX100_ENV)
704         if (mflag)
705             check_sanity(filesys);
706 #endif
707
708 #ifdef  AFS_SUN5_ENV
709         if (mflag)
710             check_sanity(filesys);
711         if (debug)
712             printclean();
713 #endif
714 #ifdef  AFS_SUN_ENV
715         iscorrupt = 0;
716 #endif
717         /*
718          * 1: scan inodes tallying blocks used
719          */
720         if (preen == 0) {
721 #if     defined(AFS_SUN5_ENV)
722             if (mountedfs)
723                 msgprintf("** Currently Mounted on %s\n", sblock.fs_fsmnt);
724             else
725 #endif
726                 msgprintf("** Last Mounted on %s\n", sblock.fs_fsmnt);
727             if (hotroot)
728                 msgprintf("** Root file system\n");
729 #ifdef  AFS_SUN5_ENV
730             if (mflag) {
731                 printf("** Phase 1 - Sanity Check only\n");
732                 return;
733             } else
734 #endif
735                 msgprintf("** Phase 1 - Check Blocks and Sizes\n");
736         }
737         pass1();
738
739         /*
740          * 1b: locate first references to duplicates, if any
741          */
742         if (duplist) {
743             if (preen)
744                 pfatal("INTERNAL ERROR: dups with -p");
745             msgprintf("** Phase 1b - Rescan For More DUPS\n");
746             pass1b();
747         }
748
749         /*
750          * 2: traverse directories from root to mark all connected directories
751          */
752         if (preen == 0)
753             msgprintf("** Phase 2 - Check Pathnames\n");
754         pass2();
755
756         /*
757          * 3: scan inodes looking for disconnected directories
758          */
759         if (preen == 0)
760             msgprintf("** Phase 3 - Check Connectivity\n");
761         pass3();
762
763         /*
764          * 4: scan inodes looking for disconnected files; check reference counts
765          */
766         if (preen == 0)
767             msgprintf("** Phase 4 - Check Reference Counts\n");
768         pass4();
769
770         /*
771          * 5: check and repair resource counts in cylinder groups
772          */
773         if (preen == 0)
774             msgprintf("** Phase 5 - Check Cyl groups\n");
775         pass5();
776
777 #ifdef  AFS_DEC_ENV
778         if (fsmodified || (sblk.b_dirty) || (cgblk.b_dirty)) {
779             fsdirty = 1;
780             if (hotroot)
781                 rootdirty = 1;
782             if (retries <= 1) {
783                 /*
784                  * 003 - Number of retry attempts have been
785                  * exhausted. Mark super block as dirty.
786                  */
787                 (void)time(&sblock.fs_time);
788                 sbdirty();
789             }
790         } else {
791             /*
792              * 003 - If checking root file system, and it was
793              * modified during any pass, don't assume it is ok. Must reboot.
794              */
795             if (rootdirty) {
796                 sbdirty();
797                 retries = 0;
798             } else {
799                 if ((!hotroot) && (!bflag) && (!nflag) && (!iscorrupt)) {
800                     sblock.fs_fmod = 0;
801                     sblock.fs_clean = FS_CLEAN;
802                     (void)time(&sblock.fs_time);
803                     (void)time(&sblock.fs_lastfsck);
804                     if ((sblock.fs_deftimer) && (sblock.fs_deftimer > 0)
805                         && (sblock.fs_deftimer < 255))
806                         sblock.fs_cleantimer = sblock.fs_deftimer;
807                     else
808                         sblock.fs_cleantimer = sblock.fs_deftimer =
809                             FSCLEAN_TIMEOUTFACTOR;
810                     sbdirty();
811                 }
812                 /*
813                  * 006 - If an alternate super block was used,
814                  * we want to re fsck the partition after 
815                  * updating the primary super block.
816                  */
817                 if (!bflag)
818                     retries = 0;
819             }
820         }
821         /* Unless no updates are to be done, write out maps. */
822         if (nflag)
823             retries = 0;
824         else
825             ckfini();
826         if (debug) {
827             daddr_t nn_files = n_files;
828             daddr_t nn_blks = n_blks;
829
830             n_ffree = sblock.fs_cstotal.cs_nffree;
831             n_bfree = sblock.fs_cstotal.cs_nbfree;
832             if (nn_files -= maxino - ROOTINO - sblock.fs_cstotal.cs_nifree)
833                 printf("%d files missing\n", nn_files);
834             nn_blks +=
835                 sblock.fs_ncg * (cgdmin(&sblock, 0) - cgsblock(&sblock, 0));
836             nn_blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0);
837             nn_blks += howmany(sblock.fs_cssize, sblock.fs_fsize);
838             if (nn_blks -= maxfsblock - (n_ffree + sblock.fs_frag * n_bfree))
839                 printf("%d blocks missing\n", nn_blks);
840         }
841         if (duplist != NULL) {
842             if (debug)
843                 printf("The following duplicate blocks remain:");
844             for (dp = duplist; dp; dp = dp->next) {
845                 if (debug)
846                     printf(" %d,", dp->dup);
847                 free(dp);
848             }
849             if (debug)
850                 printf("\n");
851         }
852         if (zlnhead != NULL) {
853             if (debug)
854                 printf("The following zero link count inodes remain:");
855             for (zlnp = zlnhead; zlnp; zlnp = zlnp->next) {
856                 if (debug)
857                     printf(" %d,", zlnp->zlncnt);
858                 free(zlnp);
859             }
860             if (debug)
861                 printf("\n");
862         }
863         zlnhead = NULL;
864         duplist = NULL;
865
866         free(blockmap);
867         free(statemap);
868         free((char *)lncntp);
869         /* Print out retry message, and fsck file system again. */
870         if (retries > 1)
871             if (preen)
872                 printf("%s: FILE SYSTEM MODIFIED, VERIFYING\n", filesys);
873             else
874                 printf("**** FILE SYSTEM MODIFIED, VERIFYING\n");
875     }                           /* for retries */
876 #endif
877
878 #if     defined(AFS_SUN_ENV) && !defined(AFS_SUN3_ENV)
879     updateclean();
880     if (debug)
881         printclean();
882 #endif
883     /*
884      * print out summary statistics
885      */
886     n_ffree = sblock.fs_cstotal.cs_nffree;
887     n_bfree = sblock.fs_cstotal.cs_nbfree;
888 #ifdef VICE
889 #if defined(ACLS) && defined(AFS_HPUX_ENV)
890     pinfo("%d files, %d icont, %d used, %d free", n_files, n_cont, n_blks,
891           n_ffree + sblock.fs_frag * n_bfree);
892 #else
893     pinfo("%d files, %d used, %d free", n_files, n_blks,
894           n_ffree + sblock.fs_frag * n_bfree);
895 #endif
896     if (nViceFiles)
897         msgprintf(", %d AFS files", nViceFiles);
898     msgprintf(" (%d frags, %d blocks, %.1f%% fragmentation)\n", n_ffree,
899               n_bfree, (float)(n_ffree * 100) / sblock.fs_dsize);
900 #else /* VICE */
901 #if defined(ACLS) && defined(AFS_HPUX_ENV)
902     pinfo("%d files, %d icont, %d used, %d free ", n_files, n_cont, n_blks,
903           n_ffree + sblock.fs_frag * n_bfree);
904 #else
905     pinfo("%d files, %d used, %d free ", n_files, n_blks,
906           n_ffree + sblock.fs_frag * n_bfree);
907 #endif
908     n printf("(%d frags, %d blocks, %.1f%% fragmentation)\n", n_ffree,
909              n_bfree, (float)(n_ffree * 100) / sblock.fs_dsize);
910 #endif /* VICE */
911 #ifdef  AFS_DEC_ENV
912     if ((!fsdirty) && (!rootdirty))
913         return;
914     if (!preen) {
915         printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
916         if (hotroot)
917             printf("\n***** HALT PROCESSOR WITHOUT SYNCING DISK *****\n");
918     }
919     if (hotroot) {
920         sync();
921         exit(4);
922     }
923 #else
924     if (debug && (n_files -= maxino - ROOTINO - sblock.fs_cstotal.cs_nifree))
925         msgprintf("%d files missing\n", n_files);
926     if (debug) {
927         n_blks += sblock.fs_ncg * (cgdmin(&sblock, 0) - cgsblock(&sblock, 0));
928         n_blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0);
929         n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize);
930         if (n_blks -= maxfsblock - (n_ffree + sblock.fs_frag * n_bfree))
931             printf("%d blocks missing\n", n_blks);
932         if (duplist != NULL) {
933             msgprintf("The following duplicate blocks remain:");
934             for (dp = duplist; dp; dp = dp->next)
935                 msgprintf(" %d,", dp->dup);
936             msgprintf("\n");
937         }
938         if (zlnhead != NULL) {
939             msgprintf("The following zero link count inodes remain:");
940             for (zlnp = zlnhead; zlnp; zlnp = zlnp->next)
941                 msgprintf(" %d,", zlnp->zlncnt);
942             msgprintf("\n");
943         }
944     }
945 #endif
946 #ifdef  AFS_HPUX_ENV
947     /* if user's specification denotes that the file system block
948      * is going to be modified (nflag == 0) then fsck store the
949      * correct magic number in the super block if it is not already
950      * there
951      */
952     if (!nflag && !(fswritefd < 0)) {
953         if (ge_danger) {
954             printf("***** FILE SYSTEM IS NOT CLEAN, FSCK AGAIN *****\n");
955             fsmodified++;
956         } else {
957             if (!hotroot) {
958                 if (fixed && (sblock.fs_clean != FS_CLEAN)) {
959                     if (!preen && !qflag)
960                         printf("***** MARKING FILE SYSTEM CLEAN *****\n");
961                     sblock.fs_clean = FS_CLEAN;
962                     fsmodified++;
963                 }
964             } else {
965                 /* fix FS_CLEAN if changes made and no 'no' replies */
966                 if (fsmodified && fixed)
967                     sblock.fs_clean = FS_CLEAN;
968                 /*
969                  *  Fix fs_clean if there were no 'no' replies.
970                  *  This is done for both the s300 and s800.  The s800 root will be 
971                  *  guaranteed clean as of 7.0.
972                  */
973                 if (fixed && (sblock.fs_clean != FS_OK)) {
974                     if (!preen && !qflag)
975                         printf("***** MARKING FILE SYSTEM CLEAN *****\n");
976                     sblock.fs_clean = FS_CLEAN;
977                     fsmodified++;
978                 }
979             }
980         }
981     }
982 #endif
983     zlnhead = NULL;
984     duplist = NULL;
985
986 #if     defined(AFS_SUN_ENV) && !defined(AFS_SUN3_ENV)  /* WAS AFS_SUN5_ENV */
987 #ifdef  notdef
988     inocleanup();
989 #endif
990     if (fsmodified)
991         fixstate = 1;
992     else
993         fixstate = 0;
994     if (hotroot && sblock.fs_clean == FSACTIVE)
995         rebflg = 1;
996 #ifdef  AFS_SUN5_ENV
997     else if (!((sblock.fs_state + (afs_int32) sblock.fs_time == FSOKAY) &&
998 #else
999     else if (!((fs_get_state(&sblock) + (afs_int32) sblock.fs_time == FSOKAY)
1000                &&
1001 #endif
1002                (sblock.fs_clean == FSCLEAN || sblock.fs_clean == FSSTABLE))) {
1003         if (yflag || !iscorrupt) {
1004             printf("%s FILE SYSTEM STATE SET TO OKAY\n", devname);
1005             fixstate = 1;
1006         } else {
1007             printf("%s FILE SYSTEM STATE NOT SET TO OKAY\n", devname);
1008             fixstate = 0;
1009         }
1010     }
1011     if (fixstate) {
1012         (void)time(&sblock.fs_time);
1013         if (!iscorrupt) {
1014             if (hotroot && rebflg)
1015                 sblock.fs_clean = FSACTIVE;
1016             else
1017                 sblock.fs_clean = FSSTABLE;
1018 #ifdef  AFS_SUN5_ENV
1019             sblock.fs_state = FSOKAY - (afs_int32) sblock.fs_time;
1020 #else
1021             fs_set_state(&sblock, FSOKAY - (afs_int32) sblock.fs_time);
1022 #endif
1023         }
1024         sbdirty();
1025     }
1026 #else
1027 #ifdef  AFS_OSF_ENV
1028     if (!nflag && !bflag && !hotroot) {
1029         temp = fsmodified;
1030         sblock.fs_clean = FS_CLEAN;
1031         (void)time(&sblock.fs_time);
1032         sbdirty();
1033         flush(fswritefd, &sblk);
1034         fsmodified = temp;
1035     }
1036 #else /* AFS_OSF_ENV */
1037     if (fsmodified) {
1038         (void)time(&sblock.fs_time);
1039         sbdirty();
1040     }
1041 #endif
1042 #endif
1043 #ifndef AFS_DEC_ENV
1044     ckfini();
1045     free(blockmap);
1046     free(statemap);
1047     free((char *)lncntp);
1048     lncntp = NULL;
1049     blockmap = statemap = NULL;
1050 #ifdef  AFS_SUN5_ENV
1051     if (iscorrupt)
1052         exitstat = 36;
1053 #endif
1054     if (!fsmodified)
1055         return;
1056     if (!preen) {
1057         msgprintf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
1058
1059         if (hotroot)
1060             msgprintf("\n***** REBOOT UNIX *****\n");
1061     }
1062 #ifdef  AFS_SUN5_ENV
1063     if (mountedfs || hotroot) {
1064         exitstat = 40;
1065     }
1066 #endif
1067     if (hotroot) {
1068         sync();
1069 #ifdef  AFS_HPUX_ENV
1070         if (ge_danger)
1071             exit(-1);
1072         else
1073 #endif
1074 #ifdef  AFS_SUN5_ENV
1075             exit(exitstat);
1076 #else
1077             exit(4);
1078 #endif
1079     }
1080 #endif
1081 #ifdef VICE
1082     (void)close(fsreadfd);
1083     (void)close(fswritefd);
1084     if (nViceFiles || tryForce) {
1085         /* Modified file system with vice files: force full salvage */
1086         /* Salvager recognizes the file FORCESALVAGE in the root of each partition */
1087 #if !defined(AFS_DEC_ENV)
1088         struct ufs_args ufsargs;
1089 #endif
1090
1091         char pname[100], fname[100], *special;
1092         int fd, code, failed = 0;
1093
1094         msgprintf
1095             ("%s: AFS file system partition was modified; forcing full salvage\n",
1096              devname);
1097         devname = unrawname(devname);
1098         special = (char *)strrchr(devname, '/');
1099         if (!special++)
1100             special = devname;
1101         strcpy(pname, "/etc/vfsck.");   /* Using /etc, rather than /tmp, since
1102                                          * /tmp is a link to /usr/tmp on some systems, and isn't mounted now */
1103         strcat(pname, special);
1104 #ifdef AFS_SUN_ENV
1105         /* if system mounted / as read-only, we'll try to fix now */
1106         if (access("/", W_OK) < 0 && errno == EROFS) {
1107             code = system("mount -o remount /");
1108             if (code) {
1109                 printf("Couldn't remount / R/W; continuing anyway (%d).\n",
1110                        errno);
1111                 failed = 1;
1112             }
1113         }
1114 #endif
1115 #ifdef  AFS_OSF_ENV
1116         /* if system mounted / as read-only, we'll try to fix now */
1117         if (access("/", W_OK) < 0 && errno == EROFS) {
1118             printf("Can't RW acceess /; %d\n", errno);
1119             code = system("/sbin/mount -u /");
1120             if (code) {
1121                 printf("Couldn't remount / R/W; continuing anyway (%d).\n",
1122                        errno);
1123                 failed = 1;
1124             }
1125         }
1126 #endif
1127         rmdir(pname);
1128         unlink(pname);
1129         if (mkdir(pname, 0777) < 0) {
1130             if (errno != EEXIST) {
1131                 perror("fsck mkdir");
1132                 failed = 1;
1133             }
1134         }
1135         if (failed && parname) {
1136             strcpy(pname, parname);
1137         }
1138 #if !defined(AFS_DEC_ENV) && !defined(AFS_HPUX_ENV)
1139 #ifdef  AFS_SUN5_ENV
1140         ufsargs.flags = UFSMNT_NOINTR;
1141 #else
1142         ufsargs.fspec = devname;
1143 #endif
1144 #ifdef AFS_SUN_ENV
1145 #ifdef  AFS_SUN5_ENV
1146         if (mount
1147             (devname, pname, MS_DATA, "ufs", (char *)&ufsargs,
1148              sizeof(ufsargs)) < 0) {
1149 #else
1150         if (mount("4.2", pname, M_NEWTYPE, &ufsargs) < 0) {
1151 #endif
1152 #else
1153         if (mount(MOUNT_UFS, pname, 0, &ufsargs) < 0) {
1154 #endif
1155 #else
1156 #ifdef AFS_DEC_ENV
1157         if (mount(devname, pname, 0, GT_ULTRIX, NULL)) {
1158 #else
1159         if (mount(devname, pname, 0) < 0) {
1160 #endif
1161 #endif
1162             printf
1163                 ("Couldn't mount %s on %s to force FULL SALVAGE; continuing anyway (%d)!\n",
1164                  devname, pname, errno);
1165         } else {
1166             strcpy(fname, pname);
1167             strcat(fname, "/FORCESALVAGE");
1168             fd = open(fname, O_CREAT, 0);
1169             if (fd == -1) {
1170                 errexit("Couldn't create %s to force full salvage!\n", fname);
1171 #if defined(AFS_DEC_ENV)
1172                 stat(".", &tstat);
1173 #endif
1174             } else {
1175                 fstat(fd, &tstat);
1176                 close(fd);
1177             }
1178 #if /*defined(AFS_VFS_ENV) &&*/ !defined(AFS_DEC_ENV) && !defined(AFS_HPUX_ENV) && !defined(AFS_SUN5_ENV) && !defined(AFS_OSF_ENV)
1179             unmount(pname);
1180 #else
1181 #if defined(AFS_DEC_ENV)
1182             umount(tstat.st_dev);
1183 #else
1184 #if     defined(AFS_OSF_ENV)
1185             umount(pname, MNT_NOFORCE);
1186 #else /* AFS_OSF_ENV */
1187             umount(devname);
1188 #endif
1189 #endif
1190 #endif
1191         }
1192         rmdir(pname);
1193     }
1194     if (logfile) {
1195         fsync(fileno(logfile)); /* Since update isn't running */
1196         fclose(logfile);
1197         logfile = 0;
1198     }
1199 #endif /* VICE */
1200
1201 }
1202
1203 char *
1204 blockcheck(name)
1205      char *name;
1206 {
1207     struct stat stslash, stblock, stchar;
1208     char *raw;
1209     int retried = 0;
1210
1211     hotroot = 0;
1212     if (stat("/", &stslash) < 0) {
1213         perror("/");
1214         printf("Can't stat root\n");
1215         return (0);
1216     }
1217   retry:
1218     if (stat(name, &stblock) < 0) {
1219         perror(name);
1220         printf("Can't stat %s\n", name);
1221         return (0);
1222     }
1223     if ((stblock.st_mode & S_IFMT) == S_IFBLK) {
1224         if (stslash.st_dev == stblock.st_rdev) {
1225             hotroot++;
1226 #if     !defined(AFS_OSF_ENV)   /*  OSF/1 always uses the raw device, even for / */
1227             return (name);
1228 #endif /* AFS_OSF_ENV */
1229         }
1230         raw = rawname(name);
1231         if (raw) {
1232             return (raw);
1233         } else {
1234             printf("Cannot find character device for %s\n", name);
1235             return (name);
1236         }
1237     } else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) {
1238         name = unrawname(name);
1239         retried++;
1240         goto retry;
1241     }
1242     printf("Can't make sense out of name %s\n", name);
1243     return (0);
1244 }
1245
1246
1247 #if     defined(AFS_HPUX_ENV) || defined(AFS_SUN5_ENV)
1248
1249 #ifdef  AFS_SUN5_ENV
1250 /*
1251  * exit 0 - file system is unmounted and okay
1252  * exit 32 - file system is unmounted and needs checking
1253  * exit 33 - file system is mounted for root file system
1254  * exit 34 - cannot stat device
1255  */
1256 check_sanity(filename)
1257      char *filename;
1258 {
1259     struct stat stbd, stbr;
1260     struct ustat usb;
1261     char *devname;
1262     struct vfstab vfsbuf;
1263     FILE *vfstab;
1264     int is_root = 0;
1265     int is_usr = 0;
1266     int is_block = 0;
1267
1268     if (stat(filename, &stbd) < 0) {
1269         fprintf(stderr, "ufs fsck: sanity check failed : cannot stat %s\n",
1270                 filename);
1271         exit(34);
1272     }
1273
1274     if ((stbd.st_mode & S_IFMT) == S_IFBLK)
1275         is_block = 1;
1276     else if ((stbd.st_mode & S_IFMT) == S_IFCHR)
1277         is_block = 0;
1278     else {
1279         fprintf(stderr,
1280                 "ufs fsck: sanity check failed: %s not block or character device\n",
1281                 filename);
1282         exit(34);
1283     }
1284     /*
1285      * Determine if this is the root file system via vfstab. Give up
1286      * silently on failures. The whole point of this is not to care
1287      * if the root file system is already mounted.
1288      *
1289      * XXX - similar for /usr. This should be fixed to simply return
1290      * a new code indicating, mounted and needs to be checked.
1291      */
1292     if ((vfstab = fopen(VFSTAB, "r")) != 0) {
1293         if (getvfsfile(vfstab, &vfsbuf, "/") == 0) {
1294             if (is_block)
1295                 devname = vfsbuf.vfs_special;
1296             else
1297                 devname = vfsbuf.vfs_fsckdev;
1298             if (stat(devname, &stbr) == 0)
1299                 if (stbr.st_rdev == stbd.st_rdev)
1300                     is_root = 1;
1301         }
1302         if (getvfsfile(vfstab, &vfsbuf, "/usr") == 0) {
1303             if (is_block)
1304                 devname = vfsbuf.vfs_special;
1305             else
1306                 devname = vfsbuf.vfs_fsckdev;
1307             if (stat(devname, &stbr) == 0)
1308                 if (stbr.st_rdev == stbd.st_rdev)
1309                     is_usr = 1;
1310         }
1311     }
1312
1313     /* XXX - only works if filename is a block device or if
1314      * character and block device has the same dev_t value */
1315     if (is_root == 0 && is_usr == 0 && ustat(stbd.st_rdev, &usb) == 0) {
1316         fprintf(stderr, "ufs fsck: sanity check: %s already mounted\n",
1317                 filename);
1318         exit(33);
1319     }
1320     /*
1321      * We mount the ufs root file system read-only first.  After fsck
1322      * runs, we remount the root as read-write.  Therefore, we no longer
1323      * check for different values for fs_state between the root file 
1324      * system and the rest of file systems.
1325      */
1326     if (!((sblock.fs_state + (time_t) sblock.fs_time == FSOKAY)
1327           && (sblock.fs_clean == FSCLEAN || sblock.fs_clean == FSSTABLE))) {
1328         fprintf(stderr, "ufs fsck: sanity check: %s needs checking\n",
1329                 filename);
1330         exit(32);
1331     }
1332     fprintf(stderr, "ufs fsck: sanity check: %s okay\n", filename);
1333     exit(0);
1334 }
1335 #endif
1336
1337 #if     defined(AFS_HPUX100_ENV)
1338 check_sanity(filename)
1339      char *filename;
1340 {
1341     struct stat stbd, stbr;
1342     struct ustat usb;
1343     char *devname;
1344     FILE *vfstab;
1345     struct mntent *mnt;
1346     int is_root = 0;
1347     int is_usr = 0;
1348     int is_block = 0;
1349
1350     if (stat(filename, &stbd) < 0) {
1351         fprintf(stderr, "hfs fsck: sanity check failed : cannot stat %s\n",
1352                 filename);
1353         exit(34);
1354     }
1355
1356     if ((stbd.st_mode & S_IFMT) == S_IFBLK)
1357         is_block = 1;
1358     else if ((stbd.st_mode & S_IFMT) == S_IFCHR)
1359         is_block = 0;
1360     else {
1361         fprintf(stderr,
1362                 "hfs fsck: sanity check failed: %s not block or character device\n",
1363                 filename);
1364         exit(34);
1365     }
1366     /*
1367      * Determine if this is the root file system via vfstab. Give up
1368      * silently on failures. The whole point of this is not to care
1369      * if the root file system is already mounted.
1370      *
1371      * XXX - similar for /usr. This should be fixed to simply return
1372      * a new code indicating, mounted and needs to be checked.
1373      */
1374     if ((vfstab = setmntent(FSTAB, "r")) != 0) {
1375         while (mnt = getmntent(vfstab)) {
1376             if (!strcmp(mnt->mnt_dir, "/"))
1377                 if (stat(mnt->mnt_fsname, &stbr) == 0)
1378                     if (stbr.st_rdev == stbd.st_rdev)
1379                         is_root = 1;
1380
1381             if (!strcmp(mnt->mnt_dir, "/usr"))
1382                 if (stat(mnt->mnt_fsname, &stbr) == 0)
1383                     if (stbr.st_rdev == stbd.st_rdev)
1384                         is_usr = 1;
1385         }
1386         endmntent(vfstab);
1387     }
1388
1389     /* XXX - only works if filename is a block device or if
1390      * character and block device has the same dev_t value */
1391     if (is_root == 0 && is_usr == 0 && ustat(stbd.st_rdev, &usb) == 0) {
1392         fprintf(stderr, "hfs fsck: sanity check: %s already mounted\n",
1393                 filename);
1394         exit(33);
1395     }
1396     /*
1397      * We mount the ufs root file system read-only first.  After fsck
1398      * runs, we remount the root as read-write.  Therefore, we no longer
1399      * check for different values for fs_state between the root file 
1400      * system and the rest of file systems.
1401      */
1402     if (!((sblock.fs_clean == FS_CLEAN || sblock.fs_clean == FS_OK))) {
1403         fprintf(stderr, "hfs fsck: sanity check: %s needs checking\n",
1404                 filename);
1405         exit(32);
1406     }
1407     fprintf(stderr, "hfs fsck: sanity check: %s okay\n", filename);
1408     exit(0);
1409 }
1410 #endif
1411 /* see if all numbers */
1412 numbers(yp)
1413      char *yp;
1414 {
1415     if (yp == NULL)
1416         return (0);
1417     while ('0' <= *yp && *yp <= '9')
1418         yp++;
1419     if (*yp)
1420         return (0);
1421     return (1);
1422 }
1423 #endif
1424
1425 /* Convert a raw device name into a block device name. 
1426  * If the block device is not found, return the raw device name.
1427  * For HP and SUN, the returned value is not changed. For other 
1428  * platforms it is changed (I see no rhyme or reason -jpm).
1429  */
1430 char *
1431 unrawname(rawdev)
1432      char *rawdev;
1433 {
1434     static char bldev[256];
1435     struct stat statbuf;
1436     int code, i;
1437
1438     code = stat(rawdev, &statbuf);
1439     if ((code < 0) || !S_ISCHR(statbuf.st_mode))
1440         return (rawdev);        /* Not a char device */
1441
1442     for (i = strlen(rawdev) - 2; i >= 0; i--) {
1443         if ((rawdev[i] == '/') && (rawdev[i + 1] == 'r')) {
1444             strcpy(bldev, rawdev);
1445             bldev[i + 1] = 0;
1446             strcat(bldev, &rawdev[i + 2]);
1447
1448             code = stat(bldev, &statbuf);       /* test for block device */
1449             if (!code && S_ISBLK(statbuf.st_mode)) {
1450 #if defined(AFS_HPUX_ENV) || defined(AFS_SUN5_ENV)
1451                 return (bldev);
1452 #else
1453                 strcpy(rawdev, bldev);  /* Replace */
1454                 return (rawdev);
1455 #endif
1456             }
1457         }
1458     }
1459     return (rawdev);
1460 }
1461
1462 /* Convert a block device name into a raw device name. 
1463  * If the block device is not found, return null
1464  */
1465 char *
1466 rawname(bldev)
1467      char *bldev;
1468 {
1469     static char rawdev[256];
1470     struct stat statbuf;
1471     int code, i;
1472
1473     for (i = strlen(bldev) - 1; i >= 0; i--) {
1474         if (bldev[i] == '/') {
1475             strcpy(rawdev, bldev);
1476             rawdev[i + 1] = 'r';
1477             rawdev[i + 2] = 0;
1478             strcat(rawdev, &bldev[i + 1]);
1479
1480             code = stat(rawdev, &statbuf);
1481             if (!code && S_ISCHR(statbuf.st_mode))
1482                 return (rawdev);
1483         }
1484     }
1485     return NULL;
1486 }