49cbd5c60c31313388e84ac86ec3b9207150dc8d
[openafs.git] / src / vfsck / setup.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 #include <roken.h>
22
23 #include <ctype.h>
24
25 #define VICE
26
27 #if     defined(AFS_SUN_ENV) || defined(AFS_OSF_ENV)
28 #define AFS_NEWCG_ENV
29 #else
30 #undef AFS_NEWCG_ENV
31 #endif
32
33 #ifdef VICE
34 #define msgprintf vfscklogprintf
35 extern vfscklogprintf();
36 #endif
37
38 #define DKTYPENAMES
39
40 #ifdef  AFS_OSF_ENV
41 #include <sys/vnode.h>
42 #include <sys/mount.h>
43 #include <ufs/inode.h>
44 #include <ufs/fs.h>
45 #define _BSD
46 #define _KERNEL
47 #include <ufs/dir.h>
48 #undef  _KERNEL
49 #undef  _BSD
50 #else /* AFS_OSF_ENV */
51 #ifdef AFS_VFSINCL_ENV
52 #include <sys/vnode.h>
53 #ifdef    AFS_SUN5_ENV
54 #include <sys/fs/ufs_inode.h>
55 #include <sys/fs/ufs_fs.h>
56 #define _KERNEL
57 #include <sys/fs/ufs_fsdir.h>
58 #undef _KERNEL
59 #include <sys/fs/ufs_mount.h>
60 #else
61 #include <ufs/inode.h>
62 #include <ufs/fs.h>
63 #endif
64 #else /* AFS_VFSINCL_ENV */
65 #include <sys/inode.h>
66 #ifdef  AFS_HPUX_ENV
67 #define LONGFILENAMES   1
68 #include <sys/sysmacros.h>
69 #include <sys/ino.h>
70 #endif
71 #include <sys/fs.h>
72 #endif /* AFS_VFSINCL_ENV */
73 #endif /* AFS_OSF_ENV */
74
75 #include <sys/file.h>
76 #ifdef  AFS_SUN5_ENV
77 #include <sys/mntent.h>
78 #include <sys/vfstab.h>
79 #endif
80
81 #include <afs/osi_inode.h>
82 #include "fsck.h"
83
84 struct bufarea asblk;
85 struct bufarea *pbp;
86
87 #define altsblock (*asblk.b_un.b_fs)
88 #define POWEROF2(num)   (((num) & ((num) - 1)) == 0)
89
90 /*
91  * The size of a cylinder group is calculated by CGSIZE. The maximum size
92  * is limited by the fact that cylinder groups are at most one block.
93  * Its size is derived from the size of the maps maintained in the
94  * cylinder group and the (struct cg) size.
95  */
96 #define CGSIZE(fs) \
97     /* base cg */       (sizeof(struct cg) + \
98     /* blktot size */   (fs)->fs_cpg * sizeof(afs_int32) + \
99     /* blks size */     (fs)->fs_cpg * (fs)->fs_nrpos * sizeof(short) + \
100     /* inode map */     howmany((fs)->fs_ipg, NBBY) + \
101     /* block map */     howmany((fs)->fs_cpg * (fs)->fs_spc / NSPF(fs), NBBY))
102
103 char *malloc(), *calloc();
104 struct disklabel *getdisklabel();
105
106 setup(dev)
107      char *dev;
108 {
109     dev_t rootdev;
110     long cg, size, asked, i, j;
111     long bmapsize;
112     struct disklabel *lp;
113     struct stat statb;
114     struct fs proto;
115 #if     defined(AFS_SUN5_ENV)
116     static char sname[MAXPATHLEN];
117 #endif
118
119     /* reset static variables that may have been damaged by parent fork */
120     mlk_pbp = 0;
121     pbp = 0;
122     mlk_startinum = 0;
123 #if defined(ACLS) && defined(AFS_HPUX_ENV)
124     n_cont = 0;
125 #endif
126     havesb = 0;
127     if (stat("/", &statb) < 0)
128         errexit("Can't stat root\n");
129     rootdev = statb.st_dev;
130 #if     defined(AFS_SUN5_ENV)
131     strncpy(sname, dev, sizeof(sname));
132   restat:
133     if (stat(sname, &statb) < 0) {
134         perror(sname);
135         msgprintf("Can't stat %s\n", sname);
136 #else
137     if (stat(dev, &statb) < 0) {
138         perror(dev);
139         printf("Can't stat %s\n", dev);
140 #endif
141         return (0);
142     }
143 #ifdef  AFS_SUN5_ENV
144     if ((statb.st_mode & S_IFMT) == S_IFDIR) {
145         FILE *fp;
146         struct vfstab vtab;
147
148         if ((fp = fopen(VFSTAB, "r")) == NULL) {
149             pfatal("Can't open %s file\n", VFSTAB);
150             exit(1);
151         }
152         while (!getvfsent(fp, &vtab)) {
153             if (vtab.vfs_mountp && !strcmp(vtab.vfs_mountp, sname)) {
154                 strcpy(sname, vtab.vfs_special);
155                 if (rflag) {
156                     char *s = vtab.vfs_fsckdev;
157                     strcpy(sname, s);
158                 }
159                 goto restat;
160             }
161         }
162         fclose(fp);
163     }
164 #endif
165     if ((statb.st_mode & S_IFMT) != S_IFBLK
166         && (statb.st_mode & S_IFMT) != S_IFCHR) {
167         pfatal("device is not a block or character device");
168         if (reply("file is not a block or character device; OK") == 0)
169             return (0);
170     }
171 #ifdef  AFS_SUN5_ENV
172     if (mounted(sname))
173         if (rflag)
174             mountedfs++;
175         else {
176             printf("%s is mounted, fsck on BLOCK device ignored\n", sname);
177             exit(33);
178         }
179     if (rflag) {
180         char bname[MAXPATHLEN], *tname;
181
182         strcpy(bname, sname);
183         tname = unrawname(bname);
184         if (stat(tname, &statb) < 0) {
185             pfatal("Can't stat %s\n", tname);
186             return (0);
187         }
188         dev = sname;
189     }
190 #endif
191     hotroot = is_hotroot(dev);
192
193     /*
194      * The following code is added to improve usability of fsck.
195      * we need to give user a warning if the device being checked is
196      * a hotroot, a mounted file system, or a swap device.
197      * The rules are:
198      *      1) if nflag is set, it's pretty safe to fsck the target dev
199      *      2) if the target device is a swap, exit
200      *      3) if hotroot is set, and "-F" is not specified prompt the
201      *              user and wait for reply
202      *      4) if the target is a mounted file system, and "-F" is not
203      *              specified, prompt the user and wait for reply
204      *      5) if the "-m" is specifed, do no prompting since only a sanity
205      *              check is being done. important during booting
206      *
207      * Caveat: There is no way to tell the current run level, so we cannot
208      * tell whether or not we are in single user mode.
209      */
210     if (!nflag) {
211         int mounted, swap;
212         struct stat st_mounted;
213
214         mounted = swap = 0;
215         if (!hotroot) {
216             mounted = is_mounted(dev, &st_mounted);
217 #ifdef  AFS_HPUX_ENV
218             swap = is_swap(st_mounted.st_rdev);
219 #endif
220         }
221         if (!fflag
222 #ifdef  AFS_HPUX_ENV
223             && !mflag
224 #endif
225             ) {
226             if (hotroot) {
227                 msgprintf("fsck: %s: root file system", dev);
228                 if (preen)
229                     msgprintf(" (CONTINUING)\n");
230                 else {
231                     if (!freply("continue (y/n)"))
232                         return (0);
233                 }
234             } else if (mounted) {
235                 msgprintf("fsck: %s: mounted file system", dev);
236                 if (preen)
237                     msgprintf(" (CONTINUING)\n");
238                 else {
239                     if (!freply("continue (y/n)"))
240                         return (0);
241                 }
242             } else if (swap) {
243                 msgprintf("fsck: %s: swap device\n", dev);
244                 if (preen)
245                     msgprintf(" (CONTINUING)\n");
246                 else {
247                     if (!freply("continue (y/n)"))
248                         return (0);
249                 }
250             }
251         }
252     }
253     if (rootdev == statb.st_rdev)
254         hotroot++;
255     if ((fsreadfd = open(dev, O_RDONLY)) < 0) {
256         perror(dev);
257         msgprintf("Can't open %s\n", dev);
258         return (0);
259     }
260     if (preen == 0)
261         msgprintf("** %s", dev);
262     if (nflag || (fswritefd = open(dev, O_WRONLY)) < 0) {
263         fswritefd = -1;
264         msgprintf(" (NO WRITE)");
265 #ifdef  notdef
266         if (preen) {
267             pfatal("NO WRITE ACCESS");
268         }
269 #endif
270     }
271     if (preen == 0)
272         msgprintf("\n");
273 #if     defined(AFS_HPUX101_ENV)
274     setup_all_block_seek();
275 #endif
276 #ifdef  AFS_SUN5_ENV
277     if (!preen && debug)
278         printf(" pid %d\n", getpid());
279     if (debug && (hotroot || mountedfs)) {
280         printf("** %s", sname);
281         if (hotroot) {
282             printf(" is root fs");
283             if (mountedfs)
284                 printf(" and");
285         }
286         if (mountedfs)
287             printf(" is mounted");
288         printf(".\n");
289     }
290 #endif
291     fsmodified = 0;
292     lfdir = 0;
293     initbarea(&sblk);
294     initbarea(&asblk);
295 #ifdef __alpha
296     sblk.b_un.b_buf = malloc(SBSIZE + ALPHA_EXT);
297     asblk.b_un.b_buf = malloc(SBSIZE + ALPHA_EXT);
298 #else /* __alpha */
299     sblk.b_un.b_buf = malloc(SBSIZE);
300     asblk.b_un.b_buf = malloc(SBSIZE);
301 #endif
302     if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL)
303         errexit("cannot allocate space for superblock\n");
304     dev_bsize = secsize = DEV_BSIZE;
305
306     /*
307      * Read in the superblock, looking for alternates if necessary
308      */
309     if (readsb(1) == 0) {
310         if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0)
311             return (0);
312         if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0)
313             return (0);
314         for (cg = 0; cg < proto.fs_ncg; cg++) {
315             bflag = fsbtodb(&proto, cgsblock(&proto, cg));
316             if (readsb(0) != 0)
317                 break;
318         }
319         if (cg >= proto.fs_ncg) {
320             msgprintf("%s %s\n%s %s\n%s %s\n",
321                       "SEARCH FOR ALTERNATE SUPER-BLOCK",
322                       "FAILED. YOU MUST USE THE",
323                       "-b OPTION TO FSCK TO SPECIFY THE",
324                       "LOCATION OF AN ALTERNATE",
325                       "SUPER-BLOCK TO SUPPLY NEEDED",
326                       "INFORMATION; SEE fsck(8).");
327             return (0);
328         }
329         pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag);
330     }
331     maxfsblock = sblock.fs_size;
332     maxino = sblock.fs_ncg * sblock.fs_ipg;
333     /*
334      * Check and potentially fix certain fields in the super block.
335      */
336     if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) {
337         pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK");
338         if (reply("SET TO DEFAULT") == 1) {
339             sblock.fs_optim = FS_OPTTIME;
340             sbdirty();
341         }
342     }
343     if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) {
344         pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK", sblock.fs_minfree);
345         if (reply("SET TO DEFAULT") == 1) {
346             sblock.fs_minfree = 10;
347             sbdirty();
348         }
349     }
350 #ifdef  AFS_HPUX_ENV
351     /*
352      * Do we need to continue ?
353      */
354     if (pclean && sblock.fs_clean == FS_CLEAN)
355         return (-1);
356     if (pclean && hotroot && sblock.fs_clean == FS_OK)
357         return (-1);
358 #endif
359 #ifdef AFS_NEWCG_ENV
360 # ifndef AFS_SUN59_ENV
361     if (sblock.fs_interleave < 1) {
362         pwarn("IMPOSSIBLE INTERLEAVE=%d IN SUPERBLOCK", sblock.fs_interleave);
363         sblock.fs_interleave = 1;
364         if (preen)
365             msgprintf(" (FIXED)\n");
366         if (preen || reply("SET TO DEFAULT") == 1) {
367             sbdirty();
368             dirty(&asblk);
369         }
370     }
371 # endif /* AFS_SUN59_ENV */
372 #endif /* AFS_NEWCG_ENV */
373 #ifdef AFS_NEWCG_ENV
374     if (sblock.fs_npsect < sblock.fs_nsect) {
375         pwarn("IMPOSSIBLE NPSECT=%d IN SUPERBLOCK", sblock.fs_npsect);
376         sblock.fs_npsect = sblock.fs_nsect;
377         if (preen)
378             msgprintf(" (FIXED)\n");
379         if (preen || reply("SET TO DEFAULT") == 1) {
380             sbdirty();
381             dirty(&asblk);
382         }
383     }
384 #endif /* AFS_NEWCG_ENV */
385 #ifdef AFS_NEWCG_ENV
386     if (cvtflag) {
387         if (sblock.fs_postblformat == FS_42POSTBLFMT) {
388             /*
389              * Requested to convert from old format to new format
390              */
391             if (preen)
392                 pwarn("CONVERTING TO NEW FILE SYSTEM FORMAT\n");
393             else if (!reply("CONVERT TO NEW FILE SYSTEM FORMAT"))
394                 return (0);
395             isconvert = 1;
396             sblock.fs_postblformat = FS_DYNAMICPOSTBLFMT;
397             sblock.fs_nrpos = 8;
398             sblock.fs_postbloff =
399                 (char *)(&sblock.fs_opostbl[0][0]) -
400                 (char *)(&sblock.fs_link);
401             sblock.fs_rotbloff =
402                 &sblock.fs_space[0] - (u_char *) (&sblock.fs_link);
403             sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock));
404             /*
405              * Planning now for future expansion.
406              */
407 #                       if (BYTE_ORDER == BIG_ENDIAN)
408             sblock.fs_qbmask.val[0] = 0;
409             sblock.fs_qbmask.val[1] = ~sblock.fs_bmask;
410             sblock.fs_qfmask.val[0] = 0;
411             sblock.fs_qfmask.val[1] = ~sblock.fs_fmask;
412 #                       endif /* BIG_ENDIAN */
413 #                       if (BYTE_ORDER == LITTLE_ENDIAN)
414             sblock.fs_qbmask.val[0] = ~sblock.fs_bmask;
415             sblock.fs_qbmask.val[1] = 0;
416             sblock.fs_qfmask.val[0] = ~sblock.fs_fmask;
417             sblock.fs_qfmask.val[1] = 0;
418 #                       endif /* LITTLE_ENDIAN */
419 #if     defined(AFS_SUN_ENV) && !defined(AFS_SUN3_ENV)
420 #ifdef  AFS_SUN5_ENV
421             sblock.fs_state = FSOKAY - sblock.fs_time;  /* make mountable */
422 #else
423             fs_set_state(&sblock, FSOKAY - sblock.fs_time);
424 #endif
425             sblock.fs_clean = FSCLEAN;
426 #endif
427             sbdirty();
428             dirty(&asblk);
429         } else if (sblock.fs_postblformat == FS_DYNAMICPOSTBLFMT) {
430             /*
431              * Requested to convert from new format to old format
432              */
433             if (sblock.fs_nrpos != 8 || sblock.fs_ipg > 2048
434                 || sblock.fs_cpg > 32 || sblock.fs_cpc > 16) {
435                 msgprintf("PARAMETERS OF CURRENT FILE SYSTEM DO NOT\n\t");
436                 msgprintf("ALLOW CONVERSION TO OLD FILE SYSTEM FORMAT\n");
437                 errexit("");
438
439             }
440             if (preen)
441                 pwarn("CONVERTING TO OLD FILE SYSTEM FORMAT\n");
442             else if (!reply("CONVERT TO OLD FILE SYSTEM FORMAT"))
443                 return (0);
444             isconvert = 1;
445             sblock.fs_postblformat = FS_42POSTBLFMT;
446             sblock.fs_cgsize =
447                 fragroundup(&sblock,
448                             sizeof(struct ocg) + howmany(sblock.fs_fpg,
449                                                          NBBY));
450 #if     defined(AFS_SUN_ENV) && !defined(AFS_SUN3_ENV)
451 #ifdef  AFS_SUN5_ENV
452             sblock.fs_npsect = 0;
453 # ifndef AFS_SUN59_ENV
454             sblock.fs_interleave = 0;
455 # endif
456             sblock.fs_state = FSOKAY - sblock.fs_time;  /* make mountable */
457 #else
458             fs_set_state(&sblock, FSOKAY - sblock.fs_time);
459 #endif
460             sblock.fs_clean = FSCLEAN;
461 #endif
462             sbdirty();
463             dirty(&asblk);
464         } else {
465             errexit("UNKNOWN FILE SYSTEM FORMAT\n");
466         }
467     }
468 #endif /* AFS_NEWCG_ENV */
469     if (asblk.b_dirty) {
470         memcpy((char *)&altsblock, (char *)&sblock, (int)sblock.fs_sbsize);
471         flush(fswritefd, &asblk);
472     }
473     /*
474      * read in the summary info.
475      */
476     asked = 0;
477 #if     defined(AFS_SUN56_ENV)
478     {
479         caddr_t sip;
480         sip = calloc(1, sblock.fs_cssize);
481         sblock.fs_u.fs_csp = (struct csum *)sip;
482         for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
483             size =
484                 sblock.fs_cssize - i <
485                 sblock.fs_bsize ? sblock.fs_cssize - i : sblock.fs_bsize;
486             if (bread
487                 (fsreadfd, sip,
488                  fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
489                  size) != 0 && !asked) {
490                 pfatal("BAD SUMMARY INFORMATION");
491                 if (reply("CONTINUE") == 0)
492                     errexit("");
493                 return (0);
494             }
495             sip += size;
496         }
497     }
498 #else /* AFS_SUN56_ENV */
499 #if     defined(AFS_HPUX110_ENV)
500     size = fragroundup(&sblock, sblock.fs_cssize);
501     sblock.fs_csp = (struct csum *)calloc(1, (unsigned)size);
502     if ((bread
503          (fsreadfd, (char *)sblock.fs_csp, fsbtodb(&sblock, sblock.fs_csaddr),
504           size) != 0) && !asked) {
505         pfatal("BAD SUMMARY INFORMATION");
506         if (reply("CONTINUE") == 0)
507             errexit("");
508         asked++;
509     }
510 #else /* AFS_HPUX110_ENV */
511 #if     defined(AFS_HPUX101_ENV)
512     {
513         j = 0;
514         size = fragroundup(&sblock, sblock.fs_cssize);
515 #else
516     for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
517         size =
518             sblock.fs_cssize - i <
519             sblock.fs_bsize ? sblock.fs_cssize - i : sblock.fs_bsize;
520 #endif /* AFS_HPUX101_ENV */
521         sblock.fs_csp[j] = (struct csum *)calloc(1, (unsigned)size);
522         if (bread
523             (fsreadfd, (char *)sblock.fs_csp[j],
524              fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
525              size) != 0 && !asked) {
526             pfatal("BAD SUMMARY INFORMATION");
527             if (reply("CONTINUE") == 0)
528                 errexit("");
529 #ifdef  AFS_SUN_ENV
530             return (0);
531 #else
532             asked++;
533 #endif
534         }
535     }
536 #endif /* else AFS_HPUX110_ENV */
537 #endif /* else AFS_SUN56_ENV */
538
539 #if     defined(AFS_SUN_ENV) && !defined(AFS_SUN3_ENV)
540     /*
541      * if not forced, preening, not converting, and is clean; stop checking
542      */
543 #ifdef  AFS_SUN5_ENV
544     if ((fflag == 0) && preen && (isconvert == 0)
545         && (FSOKAY == (sblock.fs_state + sblock.fs_time)) &&
546 #else
547     if (preen && (isconvert == 0)
548         && (FSOKAY == (fs_get_state(&sblock) + sblock.fs_time)) &&
549 #endif
550         ((sblock.fs_clean == FSCLEAN) || (sblock.fs_clean == FSSTABLE))) {
551         iscorrupt = 0;
552         printclean();
553         return (0);
554     }
555 #endif
556 #ifdef  AFS_OSF_ENV
557     if (!fflag && !bflag && !nflag && !hotroot && sblock.fs_clean == FS_CLEAN
558         && !sblk.b_dirty) {
559         pwarn("Clean file system - skipping fsck\n");
560         return (FS_CLEAN);
561     }
562 #endif /* AFS_OSF_ENV */
563
564     /*
565      * allocate and initialize the necessary maps
566      */
567     bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(short));
568     blockmap = calloc((unsigned)bmapsize, sizeof(char));
569     if (blockmap == NULL) {
570         msgprintf("cannot alloc %d bytes for blockmap\n", bmapsize);
571         goto badsb;
572     }
573     statemap = calloc((unsigned)(maxino + 1), sizeof(char));
574     if (statemap == NULL) {
575         msgprintf("cannot alloc %d bytes for statemap\n", maxino + 1);
576         goto badsb;
577     }
578     lncntp = (short *)calloc((unsigned)(maxino + 1), sizeof(short));
579     if (lncntp == NULL) {
580         msgprintf("cannot alloc %d bytes for lncntp\n",
581                   (maxino + 1) * sizeof(short));
582         goto badsb;
583     }
584
585     bufinit();
586     return (1);
587
588   badsb:
589     ckfini();
590     return (0);
591 }
592
593 /*
594  * Read in the super block and its summary info.
595  */
596 readsb(listerr)
597      int listerr;
598 {
599 #ifdef AFS_NEWCG_ENV
600     daddr_t super = bflag ? bflag : SBOFF / dev_bsize;
601 #else /* AFS_NEWCG_ENV */
602     daddr_t super = bflag ? bflag : SBLOCK;
603
604 #endif /* AFS_NEWCG_ENV */
605     if (bread(fsreadfd, (char *)&sblock, super, (long)SBSIZE) != 0)
606         return (0);
607     sblk.b_bno = super;
608     sblk.b_size = SBSIZE;
609     /*
610      * run a few consistency checks of the super block
611      */
612 #ifdef  AFS_HPUX_ENV
613 #if defined(FD_FSMAGIC)
614     if ((sblock.fs_magic != FS_MAGIC) && (sblock.fs_magic != FS_MAGIC_LFN)
615         && (sblock.fs_magic != FD_FSMAGIC)
616 #if     defined(AFS_HPUX101_ENV)
617         && (sblock.fs_magic != FD_FSMAGIC_2)
618 #endif
619         )
620 #else /* not new magic number */
621     if ((sblock.fs_magic != FS_MAGIC) && (sblock.fs_magic != FS_MAGIC_LFN))
622 #endif /* new magic number */
623 #else
624     if (sblock.fs_magic != FS_MAGIC)
625 #endif
626     {
627         badsb(listerr, "MAGIC NUMBER WRONG");
628         return (0);
629     }
630     if (sblock.fs_ncg < 1) {
631         badsb(listerr, "NCG OUT OF RANGE");
632         return (0);
633     }
634     if (sblock.fs_cpg < 1) {
635         printf("fs_cpg= %d\n", sblock.fs_cpg);
636         badsb(listerr, "CPG OUT OF RANGE");
637         return (0);
638     }
639     if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl
640         || (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl) {
641         badsb(listerr, "NCYL LESS THAN NCG*CPG");
642         return (0);
643     }
644     if (sblock.fs_sbsize > SBSIZE) {
645         badsb(listerr, "SIZE PREPOSTEROUSLY LARGE");
646         return (0);
647     }
648     /*
649      * Compute block size that the filesystem is based on,
650      * according to fsbtodb, and adjust superblock block number
651      * so we can tell if this is an alternate later.
652      */
653     super *= dev_bsize;
654     dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1);
655     sblk.b_bno = super / dev_bsize;
656     /*
657      * Set all possible fields that could differ, then do check
658      * of whole super block against an alternate super block.
659      * When an alternate super-block is specified this check is skipped.
660      */
661     getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), sblock.fs_sbsize);
662     if (asblk.b_errs)
663         return (0);
664     if (bflag) {
665         havesb = 1;
666         return (1);
667     }
668     altsblock.fs_link = sblock.fs_link;
669 #ifdef STRUCT_FS_HAS_FS_ROLLED
670     altsblock.fs_rolled = sblock.fs_rolled;
671 #else
672     altsblock.fs_rlink = sblock.fs_rlink;
673 #endif
674     altsblock.fs_time = sblock.fs_time;
675     altsblock.fs_cstotal = sblock.fs_cstotal;
676     altsblock.fs_cgrotor = sblock.fs_cgrotor;
677     altsblock.fs_fmod = sblock.fs_fmod;
678
679     altsblock.fs_clean = sblock.fs_clean;
680 #if     defined(AFS_SUN_ENV) && !defined(AFS_SUN3_ENV)
681 #ifdef  AFS_SUN5_ENV
682     altsblock.fs_state = sblock.fs_state;
683 #else
684     fs_set_state(&altsblock, fs_get_state(&sblock));
685 #endif
686 #endif
687     altsblock.fs_ronly = sblock.fs_ronly;
688     altsblock.fs_flags = sblock.fs_flags;
689     altsblock.fs_maxcontig = sblock.fs_maxcontig;
690     altsblock.fs_minfree = sblock.fs_minfree;
691     altsblock.fs_optim = sblock.fs_optim;
692     altsblock.fs_rotdelay = sblock.fs_rotdelay;
693     altsblock.fs_maxbpg = sblock.fs_maxbpg;
694 #if     !defined(__alpha) && !defined(AFS_SUN56_ENV)
695 #if !defined(AFS_HPUX110_ENV)
696     /* HPUX110 will use UpdateAlternateSuper() below */
697     memcpy((char *)altsblock.fs_csp, (char *)sblock.fs_csp,
698            sizeof sblock.fs_csp);
699 #endif /* ! AFS_HPUX110_ENV */
700 #endif /* ! __alpha */
701 #if     defined(AFS_SUN56_ENV)
702     memcpy((char *)altsblock.fs_u.fs_csp_pad, (char *)sblock.fs_u.fs_csp_pad,
703            sizeof(sblock.fs_u.fs_csp_pad));
704 #endif
705     memcpy((char *)altsblock.fs_fsmnt, (char *)sblock.fs_fsmnt,
706            sizeof sblock.fs_fsmnt);
707 #ifndef AFS_HPUX_ENV
708     memcpy((char *)altsblock.fs_sparecon, (char *)sblock.fs_sparecon,
709            sizeof sblock.fs_sparecon);
710 #endif
711     /*
712      * The following should not have to be copied.
713      */
714     altsblock.fs_fsbtodb = sblock.fs_fsbtodb;
715 #ifdef AFS_NEWCG_ENV
716 # if defined(AFS_SUN59_ENV) && defined(FS_SI_OK)
717     /* fs_interleave replaced with fs_si and FS_SI_OK defined in */
718     /* ufs_fs.h version 2.63 don't need to compare either */
719     altsblock.fs_si = sblock.fs_si;
720 # else
721     altsblock.fs_interleave = sblock.fs_interleave;
722 # endif
723     altsblock.fs_npsect = sblock.fs_npsect;
724     altsblock.fs_nrpos = sblock.fs_nrpos;
725 #endif /* AFS_NEWCG_ENV */
726 #if     defined(AFS_HPUX110_ENV)
727     UpdateAlternateSuper(&sblock, &altsblock);
728 #endif /* AFS_HPUX110_ENV */
729     if (memcmp((char *)&sblock, (char *)&altsblock, (int)sblock.fs_sbsize)) {
730 #ifdef  __alpha
731         if (memcmp
732             ((char *)&sblock.fs_blank[0], (char *)&altsblock.fs_blank[0],
733              MAXCSBUFS * sizeof(int))) {
734             memset(sblock.fs_blank, 0, sizeof(sblock.fs_blank));
735         } else {
736 #endif /* __alpha */
737             badsb(listerr,
738                   "VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE");
739             return (0);
740 #ifdef  __alpha
741         }
742 #endif /* __alpha */
743     }
744     havesb = 1;
745     return (1);
746 }
747
748 badsb(listerr, s)
749      int listerr;
750      char *s;
751 {
752
753     if (!listerr)
754         return;
755     if (preen)
756         msgprintf("%s: ", devname);
757     pfatal("BAD SUPER BLOCK: %s\n", s);
758 #ifdef  AFS_SUN5_ENV
759     pwarn("USE AN ALTERNATE SUPER-BLOCK TO SUPPLY NEEDED INFORMATION;\n");
760     pwarn("eg. fsck [-F ufs] -o b=# [special ...] \n");
761     pfatal("where # is the alternate super block. SEE fsck_ufs(1M). \n");
762 #endif
763 }
764
765 /* dummy function that fails if ever called */
766 calcsb(dev, devfd, fs)
767      char *dev;
768      int devfd;
769      struct fs *fs;
770 {
771     return 0;
772 }
773
774 #include <sys/ustat.h>
775 #ifdef  AFS_HPUX_ENV
776 #include <sys/pstat.h>
777 #endif
778 #include <sys/errno.h>
779
780 extern int errno;
781
782 is_mounted(device, dev_st)
783      char *device;
784      struct stat *dev_st;
785 {
786     char blockdev[BUFSIZ];
787     struct ustat ust;
788     char *dp;
789
790     strcpy(blockdev, device);
791     if (stat(blockdev, dev_st) < 0)
792         return (0);
793
794     if (is_pre_init(dev_st->st_rdev))
795         return (0);
796
797     if ((dev_st->st_mode & S_IFMT) == S_IFCHR) {
798         dp = strrchr(blockdev, '/');
799         if (strncmp(dp, "/r", 2) != 0)
800             while (dp >= blockdev && *--dp != '/');
801         if (*(dp + 1) == 'r')
802             (void)strcpy(dp + 1, dp + 2);
803         if (stat(blockdev, dev_st) < 0)
804             return (0);
805     }
806     if (ustat(dev_st->st_rdev, &ust) >= 0) {
807         /* make sure we are not in pre_init_rc. If we are 0 should be returned in here. */
808         if ((is_root(dev_st->st_rdev)) && is_roroot())
809             return (0);
810         return (1);
811     }
812     return (0);
813 }
814
815 #ifdef  AFS_HPUX_ENV
816
817 #define PS_BURST 1
818 #ifdef AFS_HPUX102_ENV
819 #define PSTAT(P, N, I) pstat_getswap(P, sizeof(*P), (size_t)N, I)
820 #else
821 #define PSTAT(P, N, I) pstat(PSTAT_SWAPINFO, P, sizeof(*P), (size_t)N, I)
822 #endif
823 is_swap(devno)
824      dev_t devno;
825 {
826     struct pst_swapinfo pst[PS_BURST];
827     struct pst_swapinfo *psp = &pst[0];
828     int idx = 0, count, match = 0;
829
830     while ((count = PSTAT(psp, PS_BURST, idx) != 0)) {
831         idx = pst[count - 1].pss_idx + 1;
832         if ((psp->pss_flags & SW_BLOCK) && (psp->pss_major == major(devno))
833             && (psp->pss_minor == minor(devno))) {
834             match = 1;
835             break;
836         }
837     }
838     return (match);
839 }
840
841 #endif /* AFS_HPUX_ENV */
842
843
844 is_pre_init(rdevnum)
845      dev_t rdevnum;
846 {
847     if (rdevnum == -1)
848         return (1);
849     return (0);
850 }
851
852 is_roroot()
853 {
854 #ifndef UID_NO_CHANGE
855     struct stat stslash;
856
857     if (stat("/", &stslash) < 0)
858         return (0);
859     if (chown("/", stslash.st_uid, stslash.st_gid) == 0)
860         return (0);
861 #else
862     if (chown("/", UID_NO_CHANGE, GID_NO_CHANGE) == 0)
863         return (0);
864 #endif
865     else if (errno != EROFS) {
866         printf("fsck: chown failed: %d\n", errno);
867         return (0);
868     }
869     return (1);
870 }
871
872 is_hotroot(fs_device)
873      char *fs_device;
874 {
875     struct stat stslash, stblock, stchar;
876     char blockdev[BUFSIZ];
877
878     strcpy(blockdev, fs_device);
879     if (stat("/", &stslash) < 0) {
880         pfatal("Can't stat root\n");
881         return (0);
882     }
883
884     if (stat(blockdev, &stblock) < 0) {
885         pfatal("Can't stat %s\n", blockdev);
886         return (0);
887     }
888
889     if (is_pre_init(stblock.st_rdev))
890         return (0);
891
892     /* convert the device name to be block device name */
893     if ((stblock.st_mode & S_IFMT) == S_IFCHR) {
894         unrawname(blockdev);
895         if (stat(blockdev, &stblock) < 0)
896             return (0);
897     }
898     if ((stblock.st_mode & S_IFMT) != S_IFBLK)
899         return (0);
900     if (stslash.st_dev != stblock.st_rdev)
901         return (0);
902     /* is root file system mounted read only? */
903     if (is_roroot())
904         return (0);
905     return (1);
906 }
907
908 is_root(rdev_num)
909      dev_t rdev_num;
910 {
911     struct stat stslash;
912
913     if (stat("/", &stslash) < 0)
914         return (0);
915     if (stslash.st_dev != rdev_num)
916         return (0);
917     return (1);
918 }
919
920 getline(fp, loc, maxlen)
921      FILE *fp;
922      char *loc;
923 {
924     int n;
925     char *p, *lastloc;
926
927     p = loc;
928     lastloc = &p[maxlen - 1];
929     while ((n = getc(fp)) != '\n') {
930         if (n == EOF)
931             return (EOF);
932         if (!isspace(n) && p < lastloc)
933             *p++ = n;
934     }
935     *p = 0;
936     return (p - loc);
937 }
938
939 /*
940  * freply - prints the string, s, gets a reply fromterminal and returns
941  * 0 - no (don't continue), and 1 - yes (continue)
942  */
943 freply(s)
944      char *s;
945 {
946     char line[80];
947
948     if (!isatty(0))
949         errexit("exiting\n");
950     printf("\n%s? ", s);
951     if (getline(stdin, line, sizeof(line)) == EOF)
952         errexit("\n");
953     if (line[0] == 'y' || line[0] == 'Y')
954         return (1);
955     return (0);
956 }
957
958
959 #if   defined(AFS_HPUX110_ENV)
960 /*
961  *  Refer to function compare_sblocks() in HP's fsck.c
962  *
963  *  DESCRIPTION:
964  *     This routine will compare the primary superblock (PRIM_SBLOCK) to the
965  *     alternate superblock (ALT_SBLOCK).  This routine will take into account
966  *     that certain fields in the alternate superblock could be different than
967  *     in the primary superblock.  This routine checks the "static" fields
968  *     and ignores the "dynamic" fields.  Superblocks with the same "static"
969  *     fields are considered equivalent.
970  *
971  */
972 UpdateAlternateSuper(prim_sblock, alt_sblock)
973      struct fs *prim_sblock;
974      struct fs *alt_sblock;     /* will be modified */
975 {
976     /*
977      * Set all possible fields that could differ, then do check
978      * of whole super block against an alternate super block.
979      *
980      * Copy dynamic fields of prim_sblock into alt_sblock
981      */
982     alt_sblock->fs_time = prim_sblock->fs_time;
983     alt_sblock->fs_minfree = prim_sblock->fs_minfree;
984     alt_sblock->fs_rotdelay = prim_sblock->fs_rotdelay;
985     alt_sblock->fs_maxcontig = prim_sblock->fs_maxcontig;
986     alt_sblock->fs_maxbpg = prim_sblock->fs_maxbpg;
987     alt_sblock->fs_mirror = prim_sblock->fs_mirror;
988     alt_sblock->fs_cstotal = prim_sblock->fs_cstotal;
989     alt_sblock->fs_fmod = prim_sblock->fs_fmod;
990     alt_sblock->fs_clean = prim_sblock->fs_clean;
991     alt_sblock->fs_ronly = prim_sblock->fs_ronly;
992     alt_sblock->fs_flags = prim_sblock->fs_flags;
993     alt_sblock->fs_cgrotor = prim_sblock->fs_cgrotor;
994 #ifdef __LP64__
995     alt_sblock->fs_csp = prim_sblock->fs_csp;
996 #else /* not __LP64__ */
997     alt_sblock->fs_csp = prim_sblock->fs_csp;
998     alt_sblock->fs_csp_pad = prim_sblock->fs_csp_pad;
999 #endif /* not __LP64__ */
1000     memcpy((char *)alt_sblock->fs_fsmnt, (char *)prim_sblock->fs_fsmnt,
1001            sizeof prim_sblock->fs_fsmnt);
1002     memcpy((char *)alt_sblock->fs_fname, (char *)prim_sblock->fs_fname,
1003            sizeof prim_sblock->fs_fname);
1004     memcpy((char *)alt_sblock->fs_fpack, (char *)prim_sblock->fs_fpack,
1005            sizeof prim_sblock->fs_fpack);
1006     if (prim_sblock->fs_featurebits & FSF_LARGEUIDS)
1007         alt_sblock->fs_featurebits |= FSF_LARGEUIDS;
1008     else
1009         alt_sblock->fs_featurebits &= ~FSF_LARGEUIDS;
1010 }
1011 #endif /* AFS_HPUX110_ENV */