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