2329b35e9b76923f6305237e5167638b9e51c085
[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 #ifdef  AFS_SUN5_ENV
1078                     exit(exitstat);
1079 #else
1080                 exit(4);
1081 #endif
1082         }
1083 #endif
1084 #ifdef VICE
1085         (void)close(fsreadfd);
1086         (void)close(fswritefd);
1087         if (nViceFiles || tryForce) {
1088             /* Modified file system with vice files: force full salvage */
1089             /* Salvager recognizes the file FORCESALVAGE in the root of each partition */
1090 #if !defined(AFS_DEC_ENV)
1091             struct ufs_args ufsargs;
1092 #endif 
1093
1094             char pname[100], fname[100], *special;
1095             int fd, code, failed=0;
1096
1097             msgprintf("%s: AFS file system partition was modified; forcing full salvage\n", devname);
1098             devname = unrawname(devname);
1099             special = (char *) strrchr(devname, '/');
1100             if (!special++) 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", errno);
1110                     failed = 1;
1111                 }
1112             }
1113 #endif
1114 #ifdef  AFS_OSF_ENV
1115             /* if system mounted / as read-only, we'll try to fix now */
1116             if (access("/", W_OK) < 0 && errno == EROFS) {
1117                 printf("Can't RW acceess /; %d\n", errno);
1118                 code = system("/sbin/mount -u /");
1119                 if (code) {
1120                     printf("Couldn't remount / R/W; continuing anyway (%d).\n", errno);
1121                     failed = 1;
1122                 }
1123             }
1124 #endif
1125             rmdir(pname);
1126             unlink(pname);
1127             if (mkdir(pname, 0777) < 0) {
1128                 if (errno != EEXIST) {
1129                     perror("fsck mkdir");
1130                     failed = 1;
1131                 }
1132             }
1133             if (failed && parname) {
1134                 strcpy(pname, parname);
1135             }
1136 #if !defined(AFS_DEC_ENV) && !defined(AFS_HPUX_ENV)
1137 #ifdef  AFS_SUN5_ENV
1138             ufsargs.flags = UFSMNT_NOINTR;
1139 #else
1140             ufsargs.fspec = devname;
1141 #endif
1142 #ifdef AFS_SUN_ENV
1143 #ifdef  AFS_SUN5_ENV
1144             if (mount(devname, pname, MS_DATA, "ufs", (char *)&ufsargs, sizeof(ufsargs)) < 0) {
1145 #else
1146             if (mount("4.2", pname, M_NEWTYPE, &ufsargs) < 0) {
1147 #endif
1148 #else
1149             if (mount(MOUNT_UFS, pname, 0, &ufsargs) < 0) {
1150 #endif
1151 #else 
1152 #ifdef AFS_DEC_ENV
1153             if (mount(devname, pname, 0, GT_ULTRIX, (char *) 0)) {
1154 #else 
1155             if (mount(devname, pname, 0) < 0) {
1156 #endif
1157 #endif          
1158                 printf("Couldn't mount %s on %s to force FULL SALVAGE; continuing anyway (%d)!\n", devname, pname, errno);
1159             } else {
1160                 strcpy(fname, pname);
1161                 strcat(fname, "/FORCESALVAGE");
1162                 fd = open(fname, O_CREAT, 0);
1163                 if (fd == -1) {
1164                     errexit("Couldn't create %s to force full salvage!\n", fname);
1165 #if defined(AFS_DEC_ENV)
1166                     stat(".", &tstat);
1167 #endif
1168                 } else {
1169                     fstat(fd, &tstat);
1170                     close(fd);
1171                 }
1172 #if /*defined(AFS_VFS_ENV) &&*/ !defined(AFS_DEC_ENV) && !defined(AFS_HPUX_ENV) && !defined(AFS_SUN5_ENV) && !defined(AFS_OSF_ENV)
1173                 unmount(pname);
1174 #else
1175 #if defined(AFS_DEC_ENV)
1176                 umount(tstat.st_dev);
1177 #else
1178 #if     defined(AFS_OSF_ENV)
1179                 umount(pname, MNT_NOFORCE);
1180 #else   /* AFS_OSF_ENV */
1181                 umount(devname);
1182 #endif
1183 #endif
1184 #endif
1185             }
1186             rmdir(pname);
1187         }
1188         if (logfile) {
1189             fsync(fileno(logfile)); /* Since update isn't running */
1190             fclose(logfile);
1191             logfile = 0;
1192         }
1193 #endif /* VICE */
1194
1195 }
1196
1197 char *
1198 blockcheck(name)
1199         char *name;
1200 {
1201         struct stat stslash, stblock, stchar;
1202         char *raw;
1203         int retried = 0;
1204
1205         hotroot = 0;
1206         if (stat("/", &stslash) < 0) {
1207                 perror("/");
1208                 printf("Can't stat root\n");
1209                 return (0);
1210         }
1211 retry:
1212         if (stat(name, &stblock) < 0) {
1213                 perror(name);
1214                 printf("Can't stat %s\n", name);
1215                 return (0);
1216         }
1217         if ((stblock.st_mode & S_IFMT) == S_IFBLK) {
1218                 if (stslash.st_dev == stblock.st_rdev) {
1219                         hotroot++;
1220 #if     !defined(AFS_OSF_ENV)           /*  OSF/1 always uses the raw device, even for / */
1221                         return (name);
1222 #endif  /* AFS_OSF_ENV */
1223                 }
1224                 raw = rawname(name);
1225                 if (raw) {
1226                    return (raw);
1227                 } else {
1228                    printf("Cannot find character device for %s\n", name);
1229                    return (name);
1230                 }
1231         } else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) {
1232                 name = unrawname(name);
1233                 retried++;
1234                 goto retry;
1235         }
1236         printf("Can't make sense out of name %s\n", name);
1237         return (0);
1238 }
1239
1240
1241 #if     defined(AFS_HPUX_ENV) || defined(AFS_SUN5_ENV)
1242
1243 #ifdef  AFS_SUN5_ENV
1244 /*
1245  * exit 0 - file system is unmounted and okay
1246  * exit 32 - file system is unmounted and needs checking
1247  * exit 33 - file system is mounted for root file system
1248  * exit 34 - cannot stat device
1249  */
1250 check_sanity(filename)
1251 char    *filename;
1252 {
1253     struct stat stbd, stbr;
1254     struct ustat usb;
1255     char *devname;
1256     struct vfstab vfsbuf;
1257     FILE *vfstab;
1258     int is_root = 0;
1259     int is_usr = 0;
1260     int is_block = 0;
1261
1262     if (stat(filename, &stbd) < 0) {
1263         fprintf(stderr, "ufs fsck: sanity check failed : cannot stat %s\n", filename);
1264         exit(34);
1265     }
1266
1267     if ((stbd.st_mode & S_IFMT) == S_IFBLK) 
1268         is_block = 1;
1269     else if ((stbd.st_mode & S_IFMT) == S_IFCHR) 
1270         is_block = 0;
1271     else {
1272         fprintf(stderr, "ufs fsck: sanity check failed: %s not block or character device\n", filename);
1273         exit(34);
1274     }
1275     /*
1276      * Determine if this is the root file system via vfstab. Give up
1277      * silently on failures. The whole point of this is not to care
1278      * if the root file system is already mounted.
1279      *
1280      * XXX - similar for /usr. This should be fixed to simply return
1281      * a new code indicating, mounted and needs to be checked.
1282      */
1283     if ((vfstab = fopen(VFSTAB, "r")) != 0) {
1284         if (getvfsfile(vfstab, &vfsbuf, "/") == 0) {
1285             if (is_block)
1286                 devname = vfsbuf.vfs_special;
1287             else
1288                 devname = vfsbuf.vfs_fsckdev;
1289             if (stat(devname, &stbr) == 0)
1290                 if (stbr.st_rdev == stbd.st_rdev)
1291                     is_root = 1;
1292         }
1293         if (getvfsfile(vfstab, &vfsbuf, "/usr") == 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_usr = 1;
1301         }
1302     }
1303
1304     /* XXX - only works if filename is a block device or if
1305        character and block device has the same dev_t value */
1306     if (is_root == 0 && is_usr == 0 && ustat(stbd.st_rdev, &usb) == 0) {
1307         fprintf(stderr, "ufs fsck: sanity check: %s already mounted\n", filename);
1308         exit(33);
1309     }
1310     /*
1311      * We mount the ufs root file system read-only first.  After fsck
1312      * runs, we remount the root as read-write.  Therefore, we no longer
1313      * check for different values for fs_state between the root file 
1314      * system and the rest of file systems.
1315      */
1316     if (!((sblock.fs_state + (time_t)sblock.fs_time == FSOKAY) &&
1317           (sblock.fs_clean ==FSCLEAN || sblock.fs_clean ==FSSTABLE))) {
1318         fprintf(stderr, "ufs fsck: sanity check: %s needs checking\n", filename);
1319         exit(32);
1320     }
1321     fprintf(stderr, "ufs fsck: sanity check: %s okay\n", filename);
1322     exit(0);
1323 }
1324 #endif
1325
1326 #if     defined(AFS_HPUX100_ENV)
1327 check_sanity(filename)
1328 char    *filename;
1329 {
1330     struct stat stbd, stbr;
1331     struct ustat usb;
1332     char *devname;
1333     FILE *vfstab;
1334     struct mntent *mnt;
1335     int is_root = 0;
1336     int is_usr = 0;
1337     int is_block = 0;
1338
1339     if (stat(filename, &stbd) < 0) {
1340         fprintf(stderr, "hfs fsck: sanity check failed : cannot stat %s\n", filename);
1341         exit(34);
1342     }
1343
1344     if ((stbd.st_mode & S_IFMT) == S_IFBLK) 
1345         is_block = 1;
1346     else if ((stbd.st_mode & S_IFMT) == S_IFCHR) 
1347         is_block = 0;
1348     else {
1349         fprintf(stderr, "hfs fsck: sanity check failed: %s not block or character device\n", filename);
1350         exit(34);
1351     }
1352     /*
1353      * Determine if this is the root file system via vfstab. Give up
1354      * silently on failures. The whole point of this is not to care
1355      * if the root file system is already mounted.
1356      *
1357      * XXX - similar for /usr. This should be fixed to simply return
1358      * a new code indicating, mounted and needs to be checked.
1359      */
1360     if ((vfstab = setmntent(FSTAB, "r")) != 0) 
1361     {
1362         while ( mnt = getmntent(vfstab))
1363         {
1364           if ( !strcmp(mnt->mnt_dir,"/") )      
1365             if (stat(mnt->mnt_fsname, &stbr) == 0)
1366                 if (stbr.st_rdev == stbd.st_rdev)
1367                     is_root = 1;
1368
1369           if ( !strcmp(mnt->mnt_dir,"/usr") )
1370             if (stat(mnt->mnt_fsname, &stbr) == 0)
1371                 if (stbr.st_rdev == stbd.st_rdev)
1372                     is_usr = 1;
1373         }
1374         endmntent(vfstab);
1375     }
1376
1377     /* XXX - only works if filename is a block device or if
1378        character and block device has the same dev_t value */
1379     if (is_root == 0 && is_usr == 0 && ustat(stbd.st_rdev, &usb) == 0) {
1380         fprintf(stderr, "hfs fsck: sanity check: %s already mounted\n", filename);
1381         exit(33);
1382     }
1383     /*
1384      * We mount the ufs root file system read-only first.  After fsck
1385      * runs, we remount the root as read-write.  Therefore, we no longer
1386      * check for different values for fs_state between the root file 
1387      * system and the rest of file systems.
1388      */
1389     if (! ((sblock.fs_clean ==FS_CLEAN || sblock.fs_clean ==FS_OK))) {
1390         fprintf(stderr, "hfs fsck: sanity check: %s needs checking\n", filename);
1391         exit(32);
1392     }
1393     fprintf(stderr, "hfs fsck: sanity check: %s okay\n", filename);
1394     exit(0);
1395 }
1396 #endif
1397 /* see if all numbers */
1398 numbers(yp)
1399         char    *yp;
1400 {
1401         if (yp == NULL)
1402                 return (0);
1403         while ('0' <= *yp && *yp <= '9')
1404                 yp++;
1405         if (*yp)
1406                 return (0);
1407         return (1);
1408 }
1409 #endif
1410
1411 /* Convert a raw device name into a block device name. 
1412  * If the block device is not found, return the raw device name.
1413  * For HP and SUN, the returned value is not changed. For other 
1414  * platforms it is changed (I see no rhyme or reason -jpm).
1415  */
1416 char *
1417 unrawname(rawdev)
1418   char *rawdev;
1419 {
1420   static char bldev[256];
1421   struct stat statbuf;
1422   int code, i;
1423
1424   code = stat(rawdev, &statbuf);
1425   if ((code < 0) || !S_ISCHR(statbuf.st_mode))
1426      return(rawdev);                           /* Not a char device */
1427
1428   for (i=strlen(rawdev)-2; i>=0; i--) {
1429      if ((rawdev[i] == '/') && (rawdev[i+1] == 'r')) {
1430         strcpy(bldev, rawdev);
1431         bldev[i+1] = 0;
1432         strcat(bldev, &rawdev[i+2]);
1433
1434         code = stat(bldev, &statbuf);          /* test for block device */
1435         if (!code && S_ISBLK(statbuf.st_mode)) {
1436 #if defined(AFS_HPUX_ENV) || defined(AFS_SUN5_ENV)
1437            return(bldev);
1438 #else
1439            strcpy(rawdev, bldev);              /* Replace */
1440            return(rawdev);
1441 #endif
1442         }
1443      }
1444   }
1445   return(rawdev);
1446 }
1447
1448 /* Convert a block device name into a raw device name. 
1449  * If the block device is not found, return null
1450  */
1451 char *
1452 rawname(bldev)
1453   char *bldev;
1454 {
1455   static char rawdev[256];
1456   struct stat statbuf;
1457   int code, i;
1458
1459   for (i=strlen(bldev)-1; i>=0; i--) {
1460      if (bldev[i] == '/') {
1461         strcpy(rawdev, bldev);
1462         rawdev[i+1] = 'r';
1463         rawdev[i+2] = 0;
1464         strcat(rawdev, &bldev[i+1]);
1465
1466         code = stat(rawdev, &statbuf);
1467         if (!code && S_ISCHR(statbuf.st_mode))
1468            return(rawdev);
1469      }
1470   }
1471   return (char *)0;
1472 }