9a77ceb47ec4e47b6eff4df62c208dcbd27ff054
[openafs.git] / src / vfsck / utilities.c
1 /*
2  * Copyright (c) 1980, 1986 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17
18 #include <afsconfig.h>
19 #include <afs/param.h>
20
21 RCSID
22     ("$Header$");
23
24 #include <sys/param.h>
25 #define VICE                    /* allow us to put our changes in at will */
26 #include <sys/time.h>
27 #ifdef  AFS_OSF_ENV
28 #include <sys/vnode.h>
29 #include <sys/mount.h>
30 #include <ufs/inode.h>
31 #include <ufs/fs.h>
32 #define _BSD
33 #define _KERNEL
34 #include <ufs/dir.h>
35 #undef  _KERNEL
36 #undef  _BSD
37 #define AFS_NEWCG_ENV
38 #else /* AFS_OSF_ENV */
39 #ifdef AFS_VFSINCL_ENV
40 #include <sys/vnode.h>
41 #ifdef    AFS_SUN5_ENV
42 #include <stdio.h>
43 #include <unistd.h>
44 #include <signal.h>
45 #include <sys/fs/ufs_inode.h>
46 #include <sys/fs/ufs_fs.h>
47 #define _KERNEL
48 #include <sys/fs/ufs_fsdir.h>
49 #undef _KERNEL
50 #include <sys/fs/ufs_mount.h>
51 #else
52 #include <ufs/inode.h>
53 #include <ufs/fs.h>
54 #include <ufs/fsdir.h>
55 #endif
56 #else /* AFS_VFSINCL_ENV */
57 #include <sys/inode.h>
58 #ifdef  AFS_HPUX_ENV
59 #include <ctype.h>
60 #define LONGFILENAMES   1
61 #include <sys/sysmacros.h>
62 #include <sys/ino.h>
63 #include <sys/signal.h>
64 #define DIRSIZ_MACRO
65 #include <ndir.h>
66 #else
67 #include <sys/dir.h>
68 #endif
69 #include <sys/fs.h>
70 #endif /* AFS_VFSINCL_ENV */
71 #endif /* AFS_OSF_ENV */
72
73 #include <stdio.h>
74 #include <ctype.h>
75 #include "fsck.h"
76
77 #if     defined(AFS_HPUX101_ENV)
78 #include <unistd.h>
79 #endif
80
81 #if     defined(AFS_SUN_ENV) || defined(AFS_OSF_ENV)
82 #define AFS_NEWCG_ENV
83 #else
84 #undef AFS_NEWCG_ENV
85 #endif
86
87 long diskreads, totalreads;     /* Disk cache statistics */
88 #if     !defined(AFS_HPUX101_ENV)
89 long lseek();
90 #endif
91 char *malloc();
92 #if     defined(AFS_SUN_ENV) || defined(AFS_DEC_ENV)
93 extern int iscorrupt;
94 #endif
95 #ifdef  AFS_SUN_ENV
96 extern int isdirty;
97 #endif
98 #ifdef  AFS_SUN5_ENV
99 #include <sys/mntent.h>
100 #include <sys/mnttab.h>
101 #include <sys/stat.h>
102 #include <sys/vfstab.h>
103
104 offset_t llseek();
105 #endif
106
107 ftypeok(dp)
108      struct dinode *dp;
109 {
110     switch (dp->di_mode & IFMT) {
111
112     case IFDIR:
113     case IFREG:
114     case IFBLK:
115     case IFCHR:
116     case IFLNK:
117     case IFSOCK:
118 #ifdef  AFS_HPUX_ENV
119     case IFNWK:
120 #endif
121 #ifdef IFIFO
122     case IFIFO:
123 #else
124 #ifdef  IFPORT
125     case IFPORT:
126 #endif
127 #endif /* IFIFO */
128         return (1);
129
130     default:
131         if (debug)
132             printf("bad file type 0%o\n", dp->di_mode);
133         return (0);
134     }
135 }
136
137 #ifdef  AFS_HPUX_ENV
138 extern int fixed;
139 #endif
140 reply(question)
141      char *question;
142 {
143     int persevere;
144     char c;
145
146     if (preen)
147         pfatal("INTERNAL ERROR: GOT TO reply()");
148     persevere = !strcmp(question, "CONTINUE");
149     printf("\n");
150     if (!persevere && (nflag || fswritefd < 0)) {
151         printf("%s? no\n\n", question);
152 #if     defined(AFS_SUN_ENV) || defined(AFS_DEC_ENV)
153         iscorrupt = 1;          /* known to be corrupt */
154 #endif
155         return (0);
156     }
157     if (yflag || (persevere && nflag)) {
158         printf("%s? yes\n\n", question);
159         return (1);
160     }
161     do {
162         printf("%s? [yn] ", question);
163         (void)fflush(stdout);
164         c = getc(stdin);
165         while (c != '\n' && getc(stdin) != '\n')
166             if (feof(stdin))
167                 return (0);
168     } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N');
169     printf("\n");
170     if (c == 'y' || c == 'Y')
171         return (1);
172 #ifdef  AFS_HPUX_ENV
173     fixed = 0;
174 #endif
175 #if     defined(AFS_SUN_ENV) || defined(AFS_DEC_ENV)
176     iscorrupt = 1;              /* known to be corrupt */
177 #endif
178     return (0);
179 }
180
181 /*
182  * Malloc buffers and set up cache.
183  */
184 bufinit()
185 {
186     register struct bufarea *bp;
187     long bufcnt, i;
188     char *bufp;
189
190     bufp = malloc((unsigned int)sblock.fs_bsize);
191     if (bufp == 0)
192         errexit("cannot allocate buffer pool\n");
193     cgblk.b_un.b_buf = bufp;
194     initbarea(&cgblk);
195     bufhead.b_next = bufhead.b_prev = &bufhead;
196     bufcnt = MAXBUFSPACE / sblock.fs_bsize;
197     if (bufcnt < MINBUFS)
198         bufcnt = MINBUFS;
199     for (i = 0; i < bufcnt; i++) {
200         bp = (struct bufarea *)malloc(sizeof(struct bufarea));
201         bufp = malloc((unsigned int)sblock.fs_bsize);
202         if (bp == NULL || bufp == NULL) {
203             if (i >= MINBUFS)
204                 break;
205             errexit("cannot allocate buffer pool\n");
206         }
207         bp->b_un.b_buf = bufp;
208         bp->b_prev = &bufhead;
209         bp->b_next = bufhead.b_next;
210         bufhead.b_next->b_prev = bp;
211         bufhead.b_next = bp;
212         initbarea(bp);
213     }
214     bufhead.b_size = i;         /* save number of buffers */
215 #ifdef  AFS_SUN5_ENVX
216     pbp = pdirbp = NULL;
217 #endif
218 }
219
220 /*
221  * Manage a cache of directory blocks.
222  */
223 struct bufarea *
224 getdatablk(blkno, size)
225      daddr_t blkno;
226      long size;
227 {
228     register struct bufarea *bp;
229
230     for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next)
231         if (bp->b_bno == fsbtodb(&sblock, blkno))
232             goto foundit;
233     for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev)
234         if ((bp->b_flags & B_INUSE) == 0)
235             break;
236     if (bp == &bufhead)
237         errexit("deadlocked buffer pool\n");
238     getblk(bp, blkno, size);
239     /* fall through */
240   foundit:
241     totalreads++;
242     bp->b_prev->b_next = bp->b_next;
243     bp->b_next->b_prev = bp->b_prev;
244     bp->b_prev = &bufhead;
245     bp->b_next = bufhead.b_next;
246     bufhead.b_next->b_prev = bp;
247     bufhead.b_next = bp;
248     bp->b_flags |= B_INUSE;
249     return (bp);
250 }
251
252 struct bufarea *
253 getblk(bp, blk, size)
254      register struct bufarea *bp;
255      daddr_t blk;
256      long size;
257 {
258     daddr_t dblk;
259
260     dblk = fsbtodb(&sblock, blk);
261     if (bp->b_bno == dblk)
262         return (bp);
263     flush(fswritefd, bp);
264     diskreads++;
265     bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size);
266     bp->b_bno = dblk;
267     bp->b_size = size;
268     return (bp);
269 }
270
271 flush(fd, bp)
272      int fd;
273      register struct bufarea *bp;
274 {
275     register int i, j;
276     caddr_t sip;
277     long size;
278
279     if (!bp->b_dirty)
280         return;
281     if (bp->b_errs != 0) {
282         pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n",
283                (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ",
284                bp->b_bno);
285 #ifdef  AFS_DEC_ENV
286         iscorrupt = 1;
287 #endif
288     }
289     bp->b_dirty = 0;
290     bp->b_errs = 0;
291     bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
292     if (bp != &sblk)
293         return;
294 #if     defined(AFS_HPUX101_ENV)
295 #if     defined(AFS_HPUX110_ENV)
296     /* jpm: Need a fix here */
297     if (0)
298 #else /* AFS_HPUX110_ENV */
299     if (bwrite
300         (fswritefd, (char *)sblock.fs_csp[0],
301          fsbtodb(&sblock, sblock.fs_csaddr), fragroundup(&sblock,
302                                                          sblock.fs_cssize)) ==
303         1)
304 #endif /* else AFS_HPUX110_ENV */
305     {
306         printf
307             ("\nUnable to write to cylinder group summary area (fs_csaddr)\n");
308         printf("\tDisk write error at block %u\n",
309                fsbtodb(&sblock, sblock.fs_csaddr));
310     }
311 #else
312 #if     defined(AFS_SUN56_ENV)
313     sip = (caddr_t) sblock.fs_u.fs_csp;
314     for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
315         size =
316             sblock.fs_cssize - i <
317             sblock.fs_bsize ? sblock.fs_cssize - i : sblock.fs_bsize;
318         bwrite(fswritefd, sip,
319                fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), size);
320         sip += size;
321     }
322 #else
323     for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
324         bwrite(fswritefd, (char *)sblock.fs_csp[j],
325                fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
326                sblock.fs_cssize - i <
327                sblock.fs_bsize ? sblock.fs_cssize - i : sblock.fs_bsize);
328     }
329 #endif /* AFS_SUN56_ENV */
330 #endif /* AFS_HPUX101_ENV */
331 }
332
333 rwerror(mesg, blk)
334      char *mesg;
335      daddr_t blk;
336 {
337
338     if (preen == 0)
339         printf("\n");
340     pfatal("CANNOT %s: BLK %ld", mesg, blk);
341     if (reply("CONTINUE") == 0)
342         errexit("Program terminated\n");
343 }
344
345 ckfini()
346 {
347     register struct bufarea *bp, *nbp;
348     int cnt = 0;
349
350     flush(fswritefd, &sblk);
351 #ifdef AFS_NEWCG_ENV
352     if (havesb && sblk.b_bno != SBOFF / dev_bsize && !preen
353         && reply("UPDATE STANDARD SUPERBLOCK")) {
354         sblk.b_bno = SBOFF / dev_bsize;
355 #else /* AFS_NEWCG_ENV */
356     if (havesb && sblk.b_bno != SBLOCK && !preen
357         && reply("UPDATE STANDARD SUPERBLOCK")) {
358         sblk.b_bno = SBLOCK;
359 #endif /* AFS_NEWCG_ENV */
360         sbdirty();
361         flush(fswritefd, &sblk);
362     }
363     flush(fswritefd, &cgblk);
364     if (cgblk.b_un.b_buf) {
365         free(cgblk.b_un.b_buf);
366         cgblk.b_un.b_buf = NULL;
367     }
368     for (bp = bufhead.b_prev; bp != &bufhead; bp = nbp) {
369         cnt++;
370         flush(fswritefd, bp);
371         nbp = bp->b_prev;
372         free(bp->b_un.b_buf);
373         free((char *)bp);
374     }
375 #ifdef  AFS_SUN5_ENVX
376     pbp = pdirbp = NULL;
377 #endif
378     if (bufhead.b_size != cnt)
379         errexit("Panic: lost %d buffers\n", bufhead.b_size - cnt);
380     if (debug)
381         printf("cache missed %d of %d (%d%%)\n", diskreads, totalreads,
382                diskreads * 100 / totalreads);
383     (void)close(fsreadfd);
384     (void)close(fswritefd);
385 }
386
387 #if     !defined(AFS_HPUX101_ENV)
388 bread(fd, buf, blk, size)
389      int fd;
390      char *buf;
391      daddr_t blk;
392      long size;
393 {
394     char *cp;
395     int i, errs;
396 #ifdef  AFS_SUN5_ENV
397     offset_t offset = (offset_t) blk << DEV_BSHIFT;
398     offset_t addr;
399 #endif
400
401 #ifdef  AFS_HPUX_ENV
402     /* To fix a stripping related bug?? */
403     if (lseek(fd, blk * dev_bsize, 0) == -1)
404 #else
405 #ifdef  AFS_SUN5_ENV
406     if (llseek(fd, offset, 0) < 0)
407 #else
408     if (lseek(fd, blk * dev_bsize, 0) < 0)
409 #endif
410 #endif
411         rwerror("SEEK", blk);
412     else if (read(fd, buf, (int)size) == size)
413         return (0);
414     rwerror("READ", blk);
415 #ifdef  AFS_HPUX_ENV
416     /* To fix a stripping related bug?? */
417     if (lseek(fd, blk * dev_bsize, 0) == -1)
418 #else
419 #ifdef  AFS_SUN5_ENV
420     if (llseek(fd, offset, 0) < 0)
421 #else
422     if (lseek(fd, blk * dev_bsize, 0) < 0)
423 #endif
424 #endif
425         rwerror("SEEK", blk);
426     errs = 0;
427     memset(buf, 0, (int)size);
428     printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:");
429 #ifdef  AFS_SUN5_ENV
430     for (cp = buf, i = 0; i < btodb(size); i++, cp += DEV_BSIZE) {
431         addr = (offset_t) (blk + i) << DEV_BSHIFT;
432         if (llseek(fd, addr, SEEK_CUR) < 0 || read(fd, cp, (int)secsize) < 0) {
433             printf(" %d", blk + i);
434 #else
435     for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) {
436         if (read(fd, cp, (int)secsize) < 0) {
437             lseek(fd, blk * dev_bsize + i + secsize, 0);
438             if (secsize != dev_bsize && dev_bsize != 1)
439                 printf(" %d (%d),", (blk * dev_bsize + i) / secsize,
440                        blk + i / dev_bsize);
441             else
442                 printf(" %d,", blk + i / dev_bsize);
443 #endif
444             errs++;
445         }
446     }
447     printf("\n");
448     return (errs);
449 }
450
451 bwrite(fd, buf, blk, size)
452      int fd;
453      char *buf;
454      daddr_t blk;
455      long size;
456 {
457     int i, n;
458     char *cp;
459 #ifdef  AFS_SUN5_ENV
460     offset_t offset = (offset_t) blk << DEV_BSHIFT;
461     offset_t addr;
462
463     if (blk < SBLOCK) {
464         char msg[256];
465         sprintf(msg, "WARNING: Attempt to write illegal blkno %d on %s\n",
466                 blk, devname);
467         if (debug)
468             printf(msg);
469         return;
470     }
471 #endif
472
473     if (fd < 0)
474         return;
475 #ifdef  AFS_HPUX_ENV
476     /* To fix a stripping related bug?? */
477     if (lseek(fd, blk * dev_bsize, 0) == -1)
478 #else
479 #ifdef  AFS_SUN5_ENV
480     if (llseek(fd, offset, 0) < 0)
481 #else
482     if (lseek(fd, blk * dev_bsize, 0) < 0)
483 #endif
484 #endif
485         rwerror("SEEK", blk);
486     else if (write(fd, buf, (int)size) == size) {
487         fsmodified = 1;
488         return;
489     }
490     rwerror("WRITE", blk);
491 #ifdef  AFS_HPUX_ENV
492     /* To fix a stripping related bug?? */
493     if (lseek(fd, blk * dev_bsize, 0) == -1)
494 #else
495 #ifdef  AFS_SUN5_ENV
496     if (llseek(fd, offset, 0) < 0)
497 #else
498     if (lseek(fd, blk * dev_bsize, 0) < 0)
499 #endif
500 #endif
501         rwerror("SEEK", blk);
502     printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
503 #ifdef  AFS_SUN5_ENV
504     for (cp = buf, i = 0; i < btodb(size); i++, cp += DEV_BSIZE) {
505         n = 0;
506         addr = (offset_t) (blk + i) << DEV_BSHIFT;
507         if (llseek(fd, addr, SEEK_CUR) < 0
508             || (n = write(fd, cp, DEV_BSIZE)) < 0) {
509             printf(" %d", blk + i);
510         } else if (n > 0) {
511             fsmodified = 1;
512         }
513
514     }
515 #else
516     for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize)
517         if (write(fd, cp, (int)dev_bsize) < 0) {
518             lseek(fd, blk * dev_bsize + i + dev_bsize, 0);
519             printf(" %d,", blk + i / dev_bsize);
520         }
521 #endif
522     printf("\n");
523     return;
524 }
525 #endif /* AFS_HPUX101_ENV */
526 /*
527  * allocate a data block with the specified number of fragments
528  */
529 allocblk(frags)
530      long frags;
531 {
532     register int i, j, k;
533
534     if (frags <= 0 || frags > sblock.fs_frag)
535         return (0);
536     for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) {
537         for (j = 0; j <= sblock.fs_frag - frags; j++) {
538             if (testbmap(i + j))
539                 continue;
540             for (k = 1; k < frags; k++)
541                 if (testbmap(i + j + k))
542                     break;
543             if (k < frags) {
544                 j += k;
545                 continue;
546             }
547             for (k = 0; k < frags; k++)
548                 setbmap(i + j + k);
549             n_blks += frags;
550             return (i + j);
551         }
552     }
553     return (0);
554 }
555
556 /*
557  * Free a previously allocated block
558  */
559 freeblk(blkno, frags)
560      daddr_t blkno;
561      long frags;
562 {
563     struct inodesc idesc;
564
565     idesc.id_blkno = blkno;
566     idesc.id_numfrags = frags;
567     pass4check(&idesc);
568 }
569
570 /*
571  * Find a pathname
572  */
573 getpathname(namebuf, curdir, ino)
574      char *namebuf;
575      ino_t curdir, ino;
576 {
577     int len;
578     register char *cp;
579     struct inodesc idesc;
580     extern int findname();
581
582     if (statemap[ino] != DSTATE && statemap[ino] != DFOUND) {
583         strcpy(namebuf, "?");
584         return;
585     }
586     memset((char *)&idesc, 0, sizeof(struct inodesc));
587     idesc.id_type = DATA;
588     cp = &namebuf[BUFSIZ - 1];
589     *cp = '\0';
590     if (curdir != ino) {
591         idesc.id_parent = curdir;
592         goto namelookup;
593     }
594     while (ino != ROOTINO) {
595         idesc.id_number = ino;
596         idesc.id_func = findino;
597         idesc.id_name = "..";
598 #ifdef  AFS_SUN5_ENV
599         idesc.id_fix = NOFIX;
600 #endif
601         if ((ckinode(ginode(ino), &idesc) & FOUND) == 0)
602             break;
603       namelookup:
604         idesc.id_number = idesc.id_parent;
605         idesc.id_parent = ino;
606         idesc.id_func = findname;
607         idesc.id_name = namebuf;
608 #ifdef  AFS_SUN5_ENV
609         idesc.id_fix = NOFIX;
610 #endif
611         if ((ckinode(ginode(idesc.id_number), &idesc) & FOUND) == 0)
612             break;
613         len = strlen(namebuf);
614         cp -= len;
615         if (cp < &namebuf[MAXNAMLEN])
616             break;
617         memcpy(cp, namebuf, len);
618         *--cp = '/';
619         ino = idesc.id_number;
620     }
621     if (ino != ROOTINO) {
622         strcpy(namebuf, "?");
623         return;
624     }
625     memcpy(namebuf, cp, &namebuf[BUFSIZ] - cp);
626 }
627
628 void
629 catch()
630 {
631     ckfini();
632 #ifdef  AFS_SUN5_ENV
633     exit(37);
634 #else
635     exit(12);
636 #endif
637 }
638
639 /*
640  * When preening, allow a single quit to signal
641  * a special exit after filesystem checks complete
642  * so that reboot sequence may be interrupted.
643  */
644 void
645 catchquit()
646 {
647     extern returntosingle;
648
649     printf("returning to single-user after filesystem check\n");
650     returntosingle = 1;
651     (void)signal(SIGQUIT, SIG_DFL);
652 }
653
654 /*
655  * Ignore a single quit signal; wait and flush just in case.
656  * Used by child processes in preen.
657  */
658 void
659 voidquit()
660 {
661
662     sleep(1);
663     (void)signal(SIGQUIT, SIG_IGN);
664     (void)signal(SIGQUIT, SIG_DFL);
665 }
666
667 /*
668  * determine whether an inode should be fixed.
669  */
670 dofix(idesc, msg)
671      register struct inodesc *idesc;
672      char *msg;
673 {
674
675     switch (idesc->id_fix) {
676
677     case DONTKNOW:
678         if (idesc->id_type == DATA)
679             direrror(idesc->id_number, msg);
680         else
681             pwarn(msg);
682         if (preen) {
683             printf(" (SALVAGED)\n");
684             idesc->id_fix = FIX;
685             return (ALTERED);
686         }
687         if (reply("SALVAGE") == 0) {
688             idesc->id_fix = NOFIX;
689             return (0);
690         }
691         idesc->id_fix = FIX;
692         return (ALTERED);
693
694     case FIX:
695         return (ALTERED);
696
697     case NOFIX:
698         return (0);
699
700     default:
701         errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix);
702     }
703     /* NOTREACHED */
704 }
705
706 /* VARARGS1 */
707 errexit(s1, s2, s3, s4)
708      char *s1;
709      long s2, s3, s4;
710 {
711     printf(s1, s2, s3, s4);
712 #ifdef  AFS_SUN5_ENV
713     exit(39);
714 #else
715     exit(8);
716 #endif
717 }
718
719 /*
720  * An unexpected inconsistency occured.
721  * Die if preening, otherwise just print message and continue.
722  */
723 /* VARARGS1 */
724 pfatal(s, a1, a2, a3)
725      char *s;
726      long a1, a2, a3;
727 {
728     if (preen) {
729         printf("%s: ", devname);
730         printf(s, a1, a2, a3);
731         printf("\n");
732         printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", devname);
733 #ifdef  AFS_SUN5_ENV
734         exit(36);
735 #else
736         exit(8);
737 #endif
738     }
739     printf(s, a1, a2, a3);
740 }
741
742 /*
743  * Pwarn just prints a message when not preening,
744  * or a warning (preceded by filename) when preening.
745  */
746 /* VARARGS1 */
747 pwarn(s, a1, a2, a3, a4, a5, a6)
748      char *s;
749      long a1, a2, a3, a4, a5, a6;
750 {
751     if (preen)
752         printf("%s: ", devname);
753     printf(s, a1, a2, a3, a4, a5, a6);
754 }
755
756 /*
757  * Pwarn just prints a message when not preening,
758  * or a warning (preceded by filename) when preening.
759  */
760 /* VARARGS1 */
761 pinfo(s, a1, a2, a3, a4, a5, a6)
762      char *s;
763      long a1, a2, a3, a4, a5, a6;
764 {
765     if (preen)
766         printf("%s: ", devname);
767     printf(s, a1, a2, a3, a4, a5, a6);
768 }
769
770 #ifndef lint
771 /*
772  * Stub for routines from kernel.
773  */
774 panic(s)
775      char *s;
776 {
777
778     pfatal("INTERNAL INCONSISTENCY:");
779     errexit(s);
780 }
781 #endif
782
783 #if     defined(AFS_SUN_ENV) && !defined(AFS_SUN3_ENV)
784 debugclean()
785 {
786     char s[256];
787
788     if (debug == 0)
789         return;
790     if ((iscorrupt == 0) && (isdirty == 0))
791         return;
792     if ((sblock.fs_clean != FSSTABLE) && (sblock.fs_clean != FSCLEAN))
793         return;
794 #ifdef  AFS_SUN5_ENV
795     if (FSOKAY != (sblock.fs_state + sblock.fs_time))
796 #else
797     if (FSOKAY != (fs_get_state(&sblock) + sblock.fs_time))
798 #endif
799         return;
800
801     sprintf(s, "WARNING: inconsistencies detected on `%s' filesystem %s",
802             sblock.fs_clean == FSSTABLE ? "stable" : "clean", devname);
803     printf("%s\n", s);
804 }
805
806 updateclean()
807 {
808     struct bufarea cleanbuf;
809     unsigned int size;
810     unsigned int bno;
811     unsigned int fsclean;
812 #if     defined(AFS_SUN56_ENV)
813     offset_t sblkoff;
814 #endif
815
816     debugclean();
817     /* set fsclean to its appropriate value */
818     fsclean = sblock.fs_clean;
819 #ifdef  AFS_SUN5_ENV
820     if (FSOKAY != (sblock.fs_state + sblock.fs_time))
821 #else
822     if (FSOKAY != (fs_get_state(&sblock) + sblock.fs_time))
823 #endif
824         fsclean = FSACTIVE;
825
826     /* if necessary, update fs_clean and fs_state */
827     switch (fsclean) {
828     case FSACTIVE:
829         if (iscorrupt == 0)
830             fsclean = FSSTABLE;
831         break;
832     case FSCLEAN:
833     case FSSTABLE:
834         if (iscorrupt)
835             fsclean = FSACTIVE;
836         break;
837     default:
838         if (iscorrupt)
839             fsclean = FSACTIVE;
840         else
841             fsclean = FSSTABLE;
842     }
843     /* if fs_clean and fs_state are ok, do nothing */
844     if ((sblock.fs_clean == fsclean) &&
845 #ifdef  AFS_SUN5_ENV
846         (FSOKAY == (sblock.fs_state + sblock.fs_time)))
847 #else
848         (FSOKAY == (fs_get_state(&sblock) + sblock.fs_time)))
849 #endif
850         return;
851     sblock.fs_clean = fsclean;
852 #ifdef  AFS_SUN5_ENV
853     sblock.fs_state = sblock.fs_time;
854 #else
855     fs_set_state(&sblock, sblock.fs_time);
856 #endif
857     /* if superblock can't be written, return */
858     if (fswritefd < 0)
859         return;
860     /* read private copy of superblock, update clean flag, and write it */
861     bno = sblk.b_bno;
862     size = sblk.b_size;
863 #if     defined(AFS_SUN56_ENV)
864     sblkoff = (OFF_T) (bno) << DEV_BSHIFT;
865     if (llseek(fsreadfd, sblkoff, 0) == -1)
866         return;
867 #else
868     if (lseek(fsreadfd, (off_t) dbtob(bno), 0) == -1)
869         return;
870 #endif
871     if ((cleanbuf.b_un.b_buf = malloc(size)) == NULL)
872         errexit("out of memory");
873     if (read(fsreadfd, cleanbuf.b_un.b_buf, (int)size) != size)
874         return;
875     cleanbuf.b_un.b_fs->fs_clean = sblock.fs_clean;
876 #ifdef  AFS_SUN5_ENV
877     cleanbuf.b_un.b_fs->fs_state = sblock.fs_state;
878 #else
879     fs_set_state(cleanbuf.b_un.b_fs, fs_get_state(&sblock));
880 #endif
881     cleanbuf.b_un.b_fs->fs_time = sblock.fs_time;
882 #if     defined(AFS_SUN56_ENV)
883     if (llseek(fswritefd, sblkoff, 0) == -1)
884         return;
885 #else
886     if (lseek(fswritefd, (off_t) dbtob(bno), 0) == -1)
887         return;
888 #endif
889     if (write(fswritefd, cleanbuf.b_un.b_buf, (int)size) != size)
890         return;
891 }
892
893 printclean()
894 {
895     char *s;
896
897 #ifdef  AFS_SUN5_ENV
898     if (FSOKAY != (sblock.fs_state + sblock.fs_time))
899 #else
900     if (FSOKAY != (fs_get_state(&sblock) + sblock.fs_time))
901 #endif
902         s = "unknown";
903     else
904
905         switch (sblock.fs_clean) {
906         case FSACTIVE:
907             s = "active";
908             break;
909         case FSCLEAN:
910             s = "clean";
911             break;
912         case FSSTABLE:
913             s = "stable";
914             break;
915         default:
916             s = "unknown";
917         }
918     if (preen)
919         pwarn("is %s.\n", s);
920     else
921         printf("** %s is %s.\n", devname, s);
922 }
923 #endif
924
925 #ifdef  AFS_SUN52_ENV
926 char *
927 hasvfsopt(vfs, opt)
928      register struct vfstab *vfs;
929      register char *opt;
930 {
931     char *f, *opts;
932     static char *tmpopts;
933
934     if (vfs->vfs_mntopts == NULL)
935         return (NULL);
936     if (tmpopts == 0) {
937         tmpopts = (char *)calloc(256, sizeof(char));
938         if (tmpopts == 0)
939             return (0);
940     }
941     strncpy(tmpopts, vfs->vfs_mntopts, (sizeof(tmpopts) - 1));
942     opts = tmpopts;
943     f = mntopt(&opts);
944     for (; *f; f = mntopt(&opts)) {
945         if (strncmp(opt, f, strlen(opt)) == 0)
946             return (f - tmpopts + vfs->vfs_mntopts);
947     }
948     return (NULL);
949 }
950
951
952 writable(name)
953      char *name;
954 {
955     int rw = 1;
956     struct vfstab vfsbuf;
957     FILE *vfstab;
958     char *blkname, *unrawname();
959
960     vfstab = fopen(VFSTAB, "r");
961     if (vfstab == NULL) {
962         printf("can't open %s\n", VFSTAB);
963         return (1);
964     }
965     blkname = unrawname(name);
966     if ((getvfsspec(vfstab, &vfsbuf, blkname) == 0)
967         && (vfsbuf.vfs_fstype != NULL)
968         && (strcmp(vfsbuf.vfs_fstype, MNTTYPE_UFS) == 0)
969         && (hasvfsopt(&vfsbuf, MNTOPT_RO))) {
970         rw = 0;
971     }
972     fclose(vfstab);
973     return (rw);
974 }
975
976 mounted(name)
977      char *name;
978 {
979     int found = 0;
980     struct mnttab mnt;
981     FILE *mnttab;
982     struct stat device_stat, mount_stat;
983     char *blkname, *unrawname();
984
985     mnttab = fopen(MNTTAB, "r");
986     if (mnttab == NULL) {
987         printf("can't open %s\n", MNTTAB);
988         return (0);
989     }
990     blkname = unrawname(name);
991     while ((getmntent(mnttab, &mnt)) == NULL) {
992         if (strcmp(mnt.mnt_fstype, MNTTYPE_UFS) != 0) {
993             continue;
994         }
995         if (strcmp(blkname, mnt.mnt_special) == 0) {
996             stat(mnt.mnt_mountp, &mount_stat);
997             stat(mnt.mnt_special, &device_stat);
998             if (device_stat.st_rdev == mount_stat.st_dev) {
999                 if (hasmntopt(&mnt, MNTOPT_RO) != 0)
1000                     found = 2;  /* mounted as RO */
1001                 else
1002                     found = 1;  /* mounted as R/W */
1003             }
1004             break;
1005         }
1006     }
1007     fclose(mnttab);
1008     return (found);
1009 }
1010
1011 #endif
1012
1013 #if     defined(AFS_HPUX101_ENV)
1014
1015 #include "libfs.h"
1016 #include <sys/stat.h>
1017 #include <sys/fcntl.h>
1018
1019 int seek_options;
1020
1021 bread(fd, buf, blk, size)
1022      int fd;
1023      char *buf;
1024      daddr_t blk;
1025      long size;
1026 {
1027     int i = 0;
1028     off_t lseek_offset;
1029
1030     switch (seek_options) {
1031     case BLKSEEK_ENABLED:
1032         lseek_offset = blk;
1033         break;
1034
1035     case BLKSEEK_NOT_ENABLED:   /* File */
1036 #if     defined(AFS_HPUX102_ENV)
1037         lseek_offset = dbtoo(blk);
1038 #else
1039         lseek_offset = dbtob(blk);
1040 #endif
1041         break;
1042
1043     default:
1044         rwerror("BLKSEEK", blk);
1045     }
1046     if (lseek(fd, (off_t) lseek_offset, 0) == (off_t) - 1)
1047         rwerror("SEEK", blk);
1048     else if (read(fd, buf, (int)size) == size)
1049         return 0;
1050     rwerror("READ", blk);
1051     return 1;
1052 }
1053
1054 bwrite(fd, buf, blk, size)
1055      int fd;
1056      char *buf;
1057      daddr_t blk;
1058      long size;
1059 {
1060     off_t lseek_offset;
1061
1062     if (fd < 0)
1063         return 1;
1064
1065     switch (seek_options) {
1066     case BLKSEEK_ENABLED:
1067         lseek_offset = blk;
1068         break;
1069
1070     case BLKSEEK_NOT_ENABLED:   /* File */
1071 #if     defined(AFS_HPUX102_ENV)
1072         lseek_offset = dbtoo(blk);
1073 #else
1074         lseek_offset = dbtob(blk);
1075 #endif
1076         break;
1077
1078     default:
1079         rwerror("BLKSEEK", blk);
1080     }
1081     if (lseek(fd, (off_t) lseek_offset, 0) == (off_t) - 1)
1082         rwerror("SEEK", blk);
1083     else if (write(fd, buf, (int)size) == size) {
1084         fsmodified = 1;
1085         return 0;
1086     }
1087     rwerror("WRITE", blk);
1088     return 1;
1089 }
1090
1091 int
1092 setup_block_seek(fd)
1093      int fd;                    /* File descriptor */
1094 {
1095     int flags = 0;              /* Flags to/from fcntl() */
1096
1097     return setup_block_seek_2(fd, &flags);
1098 }
1099
1100 #define set_fserror printf
1101
1102 int
1103 setup_block_seek_2(fd, cntl_flags)
1104      int fd;                    /* Input.     File descriptor    */
1105      int *cntl_flags;           /* Returned.  Flags from fcntl() */
1106 {
1107     int flags = 0;              /* Flags to/from fcntl() */
1108     off_t lstatus;              /* Status from lseek()   */
1109     struct stat statarea;
1110     char dummy[MAXBSIZE];
1111
1112     *cntl_flags = 0;
1113     /*
1114      *  Get control Flags
1115      */
1116     if ((flags = fcntl(fd, F_GETFL)) == -1) {
1117         set_fserror("Cannot get file control flags.");
1118         return (BLKSEEK_PROCESSING_ERROR);
1119     }
1120
1121     /*
1122      *  Check if fd is a non-device file
1123      */
1124
1125     if (fstat(fd, &statarea) == -1) {
1126         set_fserror("Cannot get status information on file descriptor.");
1127         return (BLKSEEK_PROCESSING_ERROR);
1128     }
1129     if (((statarea.st_mode & S_IFMT) != S_IFCHR)
1130         && ((statarea.st_mode & S_IFMT) != S_IFBLK)) {
1131         /* Not a device file -- BLKSEEK only works on device files */
1132         *cntl_flags = flags;    /* O_BLKSEEK bit never set */
1133         return (BLKSEEK_NOT_ENABLED);
1134     }
1135
1136     /*
1137      *  Set the fd to O_BLKSEEK
1138      */
1139     if (fcntl(fd, F_SETFL, flags | O_BLKSEEK) == -1) {
1140         set_fserror("Cannot set file control flags.");
1141         return (BLKSEEK_PROCESSING_ERROR);
1142     }
1143     if (flags & O_WRONLY) {
1144         /* Set lseek to location 0 before returning */
1145         if (lseek(fd, (off_t) 0, SEEK_SET) == (off_t) - 1) {
1146             set_fserror("Cannot lseek the device.");
1147             return (BLKSEEK_PROCESSING_ERROR);
1148         }
1149         if (debug)
1150             set_fserror
1151                 ("File is write only.  Cannot Verify O_BLKSEEK mode set.");
1152         *cntl_flags = flags | O_BLKSEEK;
1153         return (BLKSEEK_FILE_WRITEONLY);
1154     }
1155
1156     /*
1157      *  Verify that kernel knows how to do O_BLKSEEK
1158      */
1159     if (lseek(fd, (off_t) 0, SEEK_SET) == (off_t) - 1) {
1160         set_fserror("Cannot lseek the device.");
1161         return (BLKSEEK_PROCESSING_ERROR);
1162     }
1163     if (read(fd, &dummy[0], BBSIZE) != BBSIZE) {        /* BBSIZE = 8192 */
1164         set_fserror("Cannot read from the device");
1165         return (BLKSEEK_PROCESSING_ERROR);
1166     }
1167
1168     if ((lstatus = lseek(fd, (off_t) 0, SEEK_CUR)) == (off_t) - 1) {
1169         set_fserror("Cannot lseek the device.");
1170         return (BLKSEEK_PROCESSING_ERROR);
1171     }
1172
1173     /*
1174      *  Set lseek to location 0
1175      */
1176     if (lseek(fd, (off_t) 0, SEEK_SET) == (off_t) - 1) {
1177         set_fserror("Cannot lseek the device.");
1178         return (BLKSEEK_PROCESSING_ERROR);
1179     }
1180
1181     if (lstatus == (off_t) (BBSIZE / DEV_BSIZE)) {
1182         *cntl_flags = flags | O_BLKSEEK;
1183         return (BLKSEEK_ENABLED);       /* Successfully enabled O_BLKSEEK */
1184     }
1185     *cntl_flags = flags & (~O_BLKSEEK); /* Turn off O_BLKSEEK bit */
1186     return (BLKSEEK_NOT_ENABLED);       /* O_BLKSEEK not enabled */
1187 }
1188
1189 setup_all_block_seek()
1190 {
1191     int opt = 0;
1192     seek_options = setup_block_seek(fsreadfd);
1193     switch (seek_options) {
1194     case BLKSEEK_ENABLED:
1195     case BLKSEEK_NOT_ENABLED:
1196         break;
1197     default:
1198         errexit("setup_block_seek on fsreadfd");
1199         break;
1200     }
1201     if (fswritefd == -1)
1202         goto done;
1203     switch (opt = setup_block_seek(fswritefd)) {
1204     case BLKSEEK_FILE_WRITEONLY:        /* WO block or char device. */
1205     case BLKSEEK_NOT_ENABLED:   /* regular file.            */
1206         if (seek_options != opt)
1207             printf
1208                 ("seek_options on fsreadfd (%d) and fswritefd (%d) do not match",
1209                  seek_options, opt);
1210         break;
1211     default:
1212         errexit("setup_block_seek on fswritefd");
1213         break;
1214     }
1215   done:
1216     if (debug)
1217         printf("read option = %d write option = %d\n", seek_options, opt);
1218 }
1219
1220
1221
1222 #endif /* AFS_HPUX101_ENV */