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