openafs-kill-dead-code-20050403
[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)
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) 
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)
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     }
286     bp->b_dirty = 0;
287     bp->b_errs = 0;
288     bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
289     if (bp != &sblk)
290         return;
291 #if     defined(AFS_HPUX101_ENV)
292 #if     defined(AFS_HPUX110_ENV)
293     /* jpm: Need a fix here */
294     if (0)
295 #else /* AFS_HPUX110_ENV */
296     if (bwrite
297         (fswritefd, (char *)sblock.fs_csp[0],
298          fsbtodb(&sblock, sblock.fs_csaddr), fragroundup(&sblock,
299                                                          sblock.fs_cssize)) ==
300         1)
301 #endif /* else AFS_HPUX110_ENV */
302     {
303         printf
304             ("\nUnable to write to cylinder group summary area (fs_csaddr)\n");
305         printf("\tDisk write error at block %u\n",
306                fsbtodb(&sblock, sblock.fs_csaddr));
307     }
308 #else
309 #if     defined(AFS_SUN56_ENV)
310     sip = (caddr_t) sblock.fs_u.fs_csp;
311     for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
312         size =
313             sblock.fs_cssize - i <
314             sblock.fs_bsize ? sblock.fs_cssize - i : sblock.fs_bsize;
315         bwrite(fswritefd, sip,
316                fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), size);
317         sip += size;
318     }
319 #else
320     for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
321         bwrite(fswritefd, (char *)sblock.fs_csp[j],
322                fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
323                sblock.fs_cssize - i <
324                sblock.fs_bsize ? sblock.fs_cssize - i : sblock.fs_bsize);
325     }
326 #endif /* AFS_SUN56_ENV */
327 #endif /* AFS_HPUX101_ENV */
328 }
329
330 rwerror(mesg, blk)
331      char *mesg;
332      daddr_t blk;
333 {
334
335     if (preen == 0)
336         printf("\n");
337     pfatal("CANNOT %s: BLK %ld", mesg, blk);
338     if (reply("CONTINUE") == 0)
339         errexit("Program terminated\n");
340 }
341
342 ckfini()
343 {
344     register struct bufarea *bp, *nbp;
345     int cnt = 0;
346
347     flush(fswritefd, &sblk);
348 #ifdef AFS_NEWCG_ENV
349     if (havesb && sblk.b_bno != SBOFF / dev_bsize && !preen
350         && reply("UPDATE STANDARD SUPERBLOCK")) {
351         sblk.b_bno = SBOFF / dev_bsize;
352 #else /* AFS_NEWCG_ENV */
353     if (havesb && sblk.b_bno != SBLOCK && !preen
354         && reply("UPDATE STANDARD SUPERBLOCK")) {
355         sblk.b_bno = SBLOCK;
356 #endif /* AFS_NEWCG_ENV */
357         sbdirty();
358         flush(fswritefd, &sblk);
359     }
360     flush(fswritefd, &cgblk);
361     if (cgblk.b_un.b_buf) {
362         free(cgblk.b_un.b_buf);
363         cgblk.b_un.b_buf = NULL;
364     }
365     for (bp = bufhead.b_prev; bp != &bufhead; bp = nbp) {
366         cnt++;
367         flush(fswritefd, bp);
368         nbp = bp->b_prev;
369         free(bp->b_un.b_buf);
370         free((char *)bp);
371     }
372 #ifdef  AFS_SUN5_ENVX
373     pbp = pdirbp = NULL;
374 #endif
375     if (bufhead.b_size != cnt)
376         errexit("Panic: lost %d buffers\n", bufhead.b_size - cnt);
377     if (debug)
378         printf("cache missed %d of %d (%d%%)\n", diskreads, totalreads,
379                diskreads * 100 / totalreads);
380     (void)close(fsreadfd);
381     (void)close(fswritefd);
382 }
383
384 #if     !defined(AFS_HPUX101_ENV)
385 bread(fd, buf, blk, size)
386      int fd;
387      char *buf;
388 #ifdef AFS_SUN59_ENV
389      diskaddr_t blk;
390 #else
391      daddr_t blk;
392 #endif
393      long size;
394 {
395     char *cp;
396     int i, errs;
397 #ifdef  AFS_SUN5_ENV
398     offset_t offset = (offset_t) blk << DEV_BSHIFT;
399     offset_t addr;
400 #endif
401
402 #ifdef  AFS_HPUX_ENV
403     /* To fix a stripping related bug?? */
404     if (lseek(fd, blk * dev_bsize, 0) == -1)
405 #else
406 #ifdef  AFS_SUN5_ENV
407     if (llseek(fd, offset, 0) < 0)
408 #else
409     if (lseek(fd, blk * dev_bsize, 0) < 0)
410 #endif
411 #endif
412         rwerror("SEEK", blk);
413     else if (read(fd, buf, (int)size) == size)
414         return (0);
415     rwerror("READ", blk);
416 #ifdef  AFS_HPUX_ENV
417     /* To fix a stripping related bug?? */
418     if (lseek(fd, blk * dev_bsize, 0) == -1)
419 #else
420 #ifdef  AFS_SUN5_ENV
421     if (llseek(fd, offset, 0) < 0)
422 #else
423     if (lseek(fd, blk * dev_bsize, 0) < 0)
424 #endif
425 #endif
426         rwerror("SEEK", blk);
427     errs = 0;
428     memset(buf, 0, (int)size);
429     printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:");
430 #ifdef  AFS_SUN5_ENV
431     for (cp = buf, i = 0; i < btodb(size); i++, cp += DEV_BSIZE) {
432         addr = (offset_t) (blk + i) << DEV_BSHIFT;
433         if (llseek(fd, addr, SEEK_CUR) < 0 || read(fd, cp, (int)secsize) < 0) {
434             printf(" %d", blk + i);
435 #else
436     for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) {
437         if (read(fd, cp, (int)secsize) < 0) {
438             lseek(fd, blk * dev_bsize + i + secsize, 0);
439             if (secsize != dev_bsize && dev_bsize != 1)
440                 printf(" %d (%d),", (blk * dev_bsize + i) / secsize,
441                        blk + i / dev_bsize);
442             else
443                 printf(" %d,", blk + i / dev_bsize);
444 #endif
445             errs++;
446         }
447     }
448     printf("\n");
449     return (errs);
450 }
451
452 bwrite(fd, buf, blk, size)
453      int fd;
454      char *buf;
455 #ifdef AFS_SUN59_ENV
456      diskaddr_t blk;
457 #else
458      daddr_t blk;
459 #endif
460      long size;
461 {
462     int i, n;
463     char *cp;
464 #ifdef  AFS_SUN5_ENV
465     offset_t offset = (offset_t) blk << DEV_BSHIFT;
466     offset_t addr;
467
468     if (blk < SBLOCK) {
469         char msg[256];
470         sprintf(msg, "WARNING: Attempt to write illegal blkno %d on %s\n",
471                 blk, devname);
472         if (debug)
473             printf(msg);
474         return;
475     }
476 #endif
477
478     if (fd < 0)
479         return;
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     else if (write(fd, buf, (int)size) == size) {
492         fsmodified = 1;
493         return;
494     }
495     rwerror("WRITE", blk);
496 #ifdef  AFS_HPUX_ENV
497     /* To fix a stripping related bug?? */
498     if (lseek(fd, blk * dev_bsize, 0) == -1)
499 #else
500 #ifdef  AFS_SUN5_ENV
501     if (llseek(fd, offset, 0) < 0)
502 #else
503     if (lseek(fd, blk * dev_bsize, 0) < 0)
504 #endif
505 #endif
506         rwerror("SEEK", blk);
507     printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
508 #ifdef  AFS_SUN5_ENV
509     for (cp = buf, i = 0; i < btodb(size); i++, cp += DEV_BSIZE) {
510         n = 0;
511         addr = (offset_t) (blk + i) << DEV_BSHIFT;
512         if (llseek(fd, addr, SEEK_CUR) < 0
513             || (n = write(fd, cp, DEV_BSIZE)) < 0) {
514             printf(" %d", blk + i);
515         } else if (n > 0) {
516             fsmodified = 1;
517         }
518
519     }
520 #else
521     for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize)
522         if (write(fd, cp, (int)dev_bsize) < 0) {
523             lseek(fd, blk * dev_bsize + i + dev_bsize, 0);
524             printf(" %d,", blk + i / dev_bsize);
525         }
526 #endif
527     printf("\n");
528     return;
529 }
530 #endif /* AFS_HPUX101_ENV */
531 /*
532  * allocate a data block with the specified number of fragments
533  */
534 allocblk(frags)
535      long frags;
536 {
537     register int i, j, k;
538
539     if (frags <= 0 || frags > sblock.fs_frag)
540         return (0);
541     for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) {
542         for (j = 0; j <= sblock.fs_frag - frags; j++) {
543             if (testbmap(i + j))
544                 continue;
545             for (k = 1; k < frags; k++)
546                 if (testbmap(i + j + k))
547                     break;
548             if (k < frags) {
549                 j += k;
550                 continue;
551             }
552             for (k = 0; k < frags; k++)
553                 setbmap(i + j + k);
554             n_blks += frags;
555             return (i + j);
556         }
557     }
558     return (0);
559 }
560
561 /*
562  * Free a previously allocated block
563  */
564 freeblk(blkno, frags)
565      daddr_t blkno;
566      long frags;
567 {
568     struct inodesc idesc;
569
570     idesc.id_blkno = blkno;
571     idesc.id_numfrags = frags;
572     pass4check(&idesc);
573 }
574
575 /*
576  * Find a pathname
577  */
578 getpathname(namebuf, curdir, ino)
579      char *namebuf;
580      ino_t curdir, ino;
581 {
582     int len;
583     register char *cp;
584     struct inodesc idesc;
585     extern int findname();
586
587     if (statemap[ino] != DSTATE && statemap[ino] != DFOUND) {
588         strcpy(namebuf, "?");
589         return;
590     }
591     memset((char *)&idesc, 0, sizeof(struct inodesc));
592     idesc.id_type = DATA;
593     cp = &namebuf[BUFSIZ - 1];
594     *cp = '\0';
595     if (curdir != ino) {
596         idesc.id_parent = curdir;
597         goto namelookup;
598     }
599     while (ino != ROOTINO) {
600         idesc.id_number = ino;
601         idesc.id_func = findino;
602         idesc.id_name = "..";
603 #ifdef  AFS_SUN5_ENV
604         idesc.id_fix = NOFIX;
605 #endif
606         if ((ckinode(ginode(ino), &idesc) & FOUND) == 0)
607             break;
608       namelookup:
609         idesc.id_number = idesc.id_parent;
610         idesc.id_parent = ino;
611         idesc.id_func = findname;
612         idesc.id_name = namebuf;
613 #ifdef  AFS_SUN5_ENV
614         idesc.id_fix = NOFIX;
615 #endif
616         if ((ckinode(ginode(idesc.id_number), &idesc) & FOUND) == 0)
617             break;
618         len = strlen(namebuf);
619         cp -= len;
620         if (cp < &namebuf[MAXNAMLEN])
621             break;
622         memcpy(cp, namebuf, len);
623         *--cp = '/';
624         ino = idesc.id_number;
625     }
626     if (ino != ROOTINO) {
627         strcpy(namebuf, "?");
628         return;
629     }
630     memcpy(namebuf, cp, &namebuf[BUFSIZ] - cp);
631 }
632
633 void
634 catch()
635 {
636     ckfini();
637 #ifdef  AFS_SUN5_ENV
638     exit(37);
639 #else
640     exit(12);
641 #endif
642 }
643
644 /*
645  * When preening, allow a single quit to signal
646  * a special exit after filesystem checks complete
647  * so that reboot sequence may be interrupted.
648  */
649 void
650 catchquit()
651 {
652     extern returntosingle;
653
654     printf("returning to single-user after filesystem check\n");
655     returntosingle = 1;
656     (void)signal(SIGQUIT, SIG_DFL);
657 }
658
659 /*
660  * Ignore a single quit signal; wait and flush just in case.
661  * Used by child processes in preen.
662  */
663 void
664 voidquit()
665 {
666
667     sleep(1);
668     (void)signal(SIGQUIT, SIG_IGN);
669     (void)signal(SIGQUIT, SIG_DFL);
670 }
671
672 /*
673  * determine whether an inode should be fixed.
674  */
675 dofix(idesc, msg)
676      register struct inodesc *idesc;
677      char *msg;
678 {
679
680     switch (idesc->id_fix) {
681
682     case DONTKNOW:
683         if (idesc->id_type == DATA)
684             direrror(idesc->id_number, msg);
685         else
686             pwarn(msg);
687         if (preen) {
688             printf(" (SALVAGED)\n");
689             idesc->id_fix = FIX;
690             return (ALTERED);
691         }
692         if (reply("SALVAGE") == 0) {
693             idesc->id_fix = NOFIX;
694             return (0);
695         }
696         idesc->id_fix = FIX;
697         return (ALTERED);
698
699     case FIX:
700         return (ALTERED);
701
702     case NOFIX:
703         return (0);
704
705     default:
706         errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix);
707     }
708     /* NOTREACHED */
709 }
710
711 /* VARARGS1 */
712 errexit(s1, s2, s3, s4)
713      char *s1;
714      long s2, s3, s4;
715 {
716     printf(s1, s2, s3, s4);
717 #ifdef  AFS_SUN5_ENV
718     exit(39);
719 #else
720     exit(8);
721 #endif
722 }
723
724 /*
725  * An unexpected inconsistency occured.
726  * Die if preening, otherwise just print message and continue.
727  */
728 /* VARARGS1 */
729 pfatal(s, a1, a2, a3)
730      char *s;
731      long a1, a2, a3;
732 {
733     if (preen) {
734         printf("%s: ", devname);
735         printf(s, a1, a2, a3);
736         printf("\n");
737         printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", devname);
738 #ifdef  AFS_SUN5_ENV
739         exit(36);
740 #else
741         exit(8);
742 #endif
743     }
744     printf(s, a1, a2, a3);
745 }
746
747 /*
748  * Pwarn just prints a message when not preening,
749  * or a warning (preceded by filename) when preening.
750  */
751 /* VARARGS1 */
752 pwarn(s, a1, a2, a3, a4, a5, a6)
753      char *s;
754      long a1, a2, a3, a4, a5, a6;
755 {
756     if (preen)
757         printf("%s: ", devname);
758     printf(s, a1, a2, a3, a4, a5, a6);
759 }
760
761 /*
762  * Pwarn just prints a message when not preening,
763  * or a warning (preceded by filename) when preening.
764  */
765 /* VARARGS1 */
766 pinfo(s, a1, a2, a3, a4, a5, a6)
767      char *s;
768      long a1, a2, a3, a4, a5, a6;
769 {
770     if (preen)
771         printf("%s: ", devname);
772     printf(s, a1, a2, a3, a4, a5, a6);
773 }
774
775 #ifndef lint
776 /*
777  * Stub for routines from kernel.
778  */
779 panic(s)
780      char *s;
781 {
782
783     pfatal("INTERNAL INCONSISTENCY:");
784     errexit(s);
785 }
786 #endif
787
788 #if     defined(AFS_SUN_ENV) && !defined(AFS_SUN3_ENV)
789 debugclean()
790 {
791     char s[256];
792
793     if (debug == 0)
794         return;
795     if ((iscorrupt == 0) && (isdirty == 0))
796         return;
797     if ((sblock.fs_clean != FSSTABLE) && (sblock.fs_clean != FSCLEAN))
798         return;
799 #ifdef  AFS_SUN5_ENV
800     if (FSOKAY != (sblock.fs_state + sblock.fs_time))
801 #else
802     if (FSOKAY != (fs_get_state(&sblock) + sblock.fs_time))
803 #endif
804         return;
805
806     sprintf(s, "WARNING: inconsistencies detected on `%s' filesystem %s",
807             sblock.fs_clean == FSSTABLE ? "stable" : "clean", devname);
808     printf("%s\n", s);
809 }
810
811 updateclean()
812 {
813     struct bufarea cleanbuf;
814     unsigned int size;
815     unsigned int bno;
816     unsigned int fsclean;
817 #if     defined(AFS_SUN56_ENV)
818     offset_t sblkoff;
819 #endif
820
821     debugclean();
822     /* set fsclean to its appropriate value */
823     fsclean = sblock.fs_clean;
824 #ifdef  AFS_SUN5_ENV
825     if (FSOKAY != (sblock.fs_state + sblock.fs_time))
826 #else
827     if (FSOKAY != (fs_get_state(&sblock) + sblock.fs_time))
828 #endif
829         fsclean = FSACTIVE;
830
831     /* if necessary, update fs_clean and fs_state */
832     switch (fsclean) {
833     case FSACTIVE:
834         if (iscorrupt == 0)
835             fsclean = FSSTABLE;
836         break;
837     case FSCLEAN:
838     case FSSTABLE:
839         if (iscorrupt)
840             fsclean = FSACTIVE;
841         break;
842     default:
843         if (iscorrupt)
844             fsclean = FSACTIVE;
845         else
846             fsclean = FSSTABLE;
847     }
848     /* if fs_clean and fs_state are ok, do nothing */
849     if ((sblock.fs_clean == fsclean) &&
850 #ifdef  AFS_SUN5_ENV
851         (FSOKAY == (sblock.fs_state + sblock.fs_time)))
852 #else
853         (FSOKAY == (fs_get_state(&sblock) + sblock.fs_time)))
854 #endif
855         return;
856     sblock.fs_clean = fsclean;
857 #ifdef  AFS_SUN5_ENV
858     sblock.fs_state = sblock.fs_time;
859 #else
860     fs_set_state(&sblock, sblock.fs_time);
861 #endif
862     /* if superblock can't be written, return */
863     if (fswritefd < 0)
864         return;
865     /* read private copy of superblock, update clean flag, and write it */
866     bno = sblk.b_bno;
867     size = sblk.b_size;
868 #if     defined(AFS_SUN56_ENV)
869     sblkoff = (OFF_T) (bno) << DEV_BSHIFT;
870     if (llseek(fsreadfd, sblkoff, 0) == -1)
871         return;
872 #else
873     if (lseek(fsreadfd, (off_t) dbtob(bno), 0) == -1)
874         return;
875 #endif
876     if ((cleanbuf.b_un.b_buf = malloc(size)) == NULL)
877         errexit("out of memory");
878     if (read(fsreadfd, cleanbuf.b_un.b_buf, (int)size) != size)
879         return;
880     cleanbuf.b_un.b_fs->fs_clean = sblock.fs_clean;
881 #ifdef  AFS_SUN5_ENV
882     cleanbuf.b_un.b_fs->fs_state = sblock.fs_state;
883 #else
884     fs_set_state(cleanbuf.b_un.b_fs, fs_get_state(&sblock));
885 #endif
886     cleanbuf.b_un.b_fs->fs_time = sblock.fs_time;
887 #if     defined(AFS_SUN56_ENV)
888     if (llseek(fswritefd, sblkoff, 0) == -1)
889         return;
890 #else
891     if (lseek(fswritefd, (off_t) dbtob(bno), 0) == -1)
892         return;
893 #endif
894     if (write(fswritefd, cleanbuf.b_un.b_buf, (int)size) != size)
895         return;
896 }
897
898 printclean()
899 {
900     char *s;
901
902 #ifdef  AFS_SUN5_ENV
903     if (FSOKAY != (sblock.fs_state + sblock.fs_time))
904 #else
905     if (FSOKAY != (fs_get_state(&sblock) + sblock.fs_time))
906 #endif
907         s = "unknown";
908     else
909
910         switch (sblock.fs_clean) {
911         case FSACTIVE:
912             s = "active";
913             break;
914         case FSCLEAN:
915             s = "clean";
916             break;
917         case FSSTABLE:
918             s = "stable";
919             break;
920         default:
921             s = "unknown";
922         }
923     if (preen)
924         pwarn("is %s.\n", s);
925     else
926         printf("** %s is %s.\n", devname, s);
927 }
928 #endif
929
930 #ifdef  AFS_SUN52_ENV
931 char *
932 hasvfsopt(vfs, opt)
933      register struct vfstab *vfs;
934      register char *opt;
935 {
936     char *f, *opts;
937     static char *tmpopts;
938
939     if (vfs->vfs_mntopts == NULL)
940         return (NULL);
941     if (tmpopts == 0) {
942         tmpopts = (char *)calloc(256, sizeof(char));
943         if (tmpopts == 0)
944             return (0);
945     }
946     strncpy(tmpopts, vfs->vfs_mntopts, (sizeof(tmpopts) - 1));
947     opts = tmpopts;
948     f = mntopt(&opts);
949     for (; *f; f = mntopt(&opts)) {
950         if (strncmp(opt, f, strlen(opt)) == 0)
951             return (f - tmpopts + vfs->vfs_mntopts);
952     }
953     return (NULL);
954 }
955
956
957 writable(name)
958      char *name;
959 {
960     int rw = 1;
961     struct vfstab vfsbuf;
962     FILE *vfstab;
963     char *blkname, *unrawname();
964
965     vfstab = fopen(VFSTAB, "r");
966     if (vfstab == NULL) {
967         printf("can't open %s\n", VFSTAB);
968         return (1);
969     }
970     blkname = unrawname(name);
971     if ((getvfsspec(vfstab, &vfsbuf, blkname) == 0)
972         && (vfsbuf.vfs_fstype != NULL)
973         && (strcmp(vfsbuf.vfs_fstype, MNTTYPE_UFS) == 0)
974         && (hasvfsopt(&vfsbuf, MNTOPT_RO))) {
975         rw = 0;
976     }
977     fclose(vfstab);
978     return (rw);
979 }
980
981 mounted(name)
982      char *name;
983 {
984     int found = 0;
985     struct mnttab mnt;
986     FILE *mnttab;
987     struct stat device_stat, mount_stat;
988     char *blkname, *unrawname();
989
990     mnttab = fopen(MNTTAB, "r");
991     if (mnttab == NULL) {
992         printf("can't open %s\n", MNTTAB);
993         return (0);
994     }
995     blkname = unrawname(name);
996     while ((getmntent(mnttab, &mnt)) == NULL) {
997         if (strcmp(mnt.mnt_fstype, MNTTYPE_UFS) != 0) {
998             continue;
999         }
1000         if (strcmp(blkname, mnt.mnt_special) == 0) {
1001             stat(mnt.mnt_mountp, &mount_stat);
1002             stat(mnt.mnt_special, &device_stat);
1003             if (device_stat.st_rdev == mount_stat.st_dev) {
1004                 if (hasmntopt(&mnt, MNTOPT_RO) != 0)
1005                     found = 2;  /* mounted as RO */
1006                 else
1007                     found = 1;  /* mounted as R/W */
1008             }
1009             break;
1010         }
1011     }
1012     fclose(mnttab);
1013     return (found);
1014 }
1015
1016 #endif
1017
1018 #if     defined(AFS_HPUX101_ENV)
1019
1020 #include "libfs.h"
1021 #include <sys/stat.h>
1022 #include <sys/fcntl.h>
1023
1024 int seek_options;
1025
1026 bread(fd, buf, blk, size)
1027      int fd;
1028      char *buf;
1029      daddr_t blk;
1030      long size;
1031 {
1032     int i = 0;
1033     off_t lseek_offset;
1034
1035     switch (seek_options) {
1036     case BLKSEEK_ENABLED:
1037         lseek_offset = blk;
1038         break;
1039
1040     case BLKSEEK_NOT_ENABLED:   /* File */
1041 #if     defined(AFS_HPUX102_ENV)
1042         lseek_offset = dbtoo(blk);
1043 #else
1044         lseek_offset = dbtob(blk);
1045 #endif
1046         break;
1047
1048     default:
1049         rwerror("BLKSEEK", blk);
1050     }
1051     if (lseek(fd, (off_t) lseek_offset, 0) == (off_t) - 1)
1052         rwerror("SEEK", blk);
1053     else if (read(fd, buf, (int)size) == size)
1054         return 0;
1055     rwerror("READ", blk);
1056     return 1;
1057 }
1058
1059 bwrite(fd, buf, blk, size)
1060      int fd;
1061      char *buf;
1062      daddr_t blk;
1063      long size;
1064 {
1065     off_t lseek_offset;
1066
1067     if (fd < 0)
1068         return 1;
1069
1070     switch (seek_options) {
1071     case BLKSEEK_ENABLED:
1072         lseek_offset = blk;
1073         break;
1074
1075     case BLKSEEK_NOT_ENABLED:   /* File */
1076 #if     defined(AFS_HPUX102_ENV)
1077         lseek_offset = dbtoo(blk);
1078 #else
1079         lseek_offset = dbtob(blk);
1080 #endif
1081         break;
1082
1083     default:
1084         rwerror("BLKSEEK", blk);
1085     }
1086     if (lseek(fd, (off_t) lseek_offset, 0) == (off_t) - 1)
1087         rwerror("SEEK", blk);
1088     else if (write(fd, buf, (int)size) == size) {
1089         fsmodified = 1;
1090         return 0;
1091     }
1092     rwerror("WRITE", blk);
1093     return 1;
1094 }
1095
1096 int
1097 setup_block_seek(fd)
1098      int fd;                    /* File descriptor */
1099 {
1100     int flags = 0;              /* Flags to/from fcntl() */
1101
1102     return setup_block_seek_2(fd, &flags);
1103 }
1104
1105 #define set_fserror printf
1106
1107 int
1108 setup_block_seek_2(fd, cntl_flags)
1109      int fd;                    /* Input.     File descriptor    */
1110      int *cntl_flags;           /* Returned.  Flags from fcntl() */
1111 {
1112     int flags = 0;              /* Flags to/from fcntl() */
1113     off_t lstatus;              /* Status from lseek()   */
1114     struct stat statarea;
1115     char dummy[MAXBSIZE];
1116
1117     *cntl_flags = 0;
1118     /*
1119      *  Get control Flags
1120      */
1121     if ((flags = fcntl(fd, F_GETFL)) == -1) {
1122         set_fserror("Cannot get file control flags.");
1123         return (BLKSEEK_PROCESSING_ERROR);
1124     }
1125
1126     /*
1127      *  Check if fd is a non-device file
1128      */
1129
1130     if (fstat(fd, &statarea) == -1) {
1131         set_fserror("Cannot get status information on file descriptor.");
1132         return (BLKSEEK_PROCESSING_ERROR);
1133     }
1134     if (((statarea.st_mode & S_IFMT) != S_IFCHR)
1135         && ((statarea.st_mode & S_IFMT) != S_IFBLK)) {
1136         /* Not a device file -- BLKSEEK only works on device files */
1137         *cntl_flags = flags;    /* O_BLKSEEK bit never set */
1138         return (BLKSEEK_NOT_ENABLED);
1139     }
1140
1141     /*
1142      *  Set the fd to O_BLKSEEK
1143      */
1144     if (fcntl(fd, F_SETFL, flags | O_BLKSEEK) == -1) {
1145         set_fserror("Cannot set file control flags.");
1146         return (BLKSEEK_PROCESSING_ERROR);
1147     }
1148     if (flags & O_WRONLY) {
1149         /* Set lseek to location 0 before returning */
1150         if (lseek(fd, (off_t) 0, SEEK_SET) == (off_t) - 1) {
1151             set_fserror("Cannot lseek the device.");
1152             return (BLKSEEK_PROCESSING_ERROR);
1153         }
1154         if (debug)
1155             set_fserror
1156                 ("File is write only.  Cannot Verify O_BLKSEEK mode set.");
1157         *cntl_flags = flags | O_BLKSEEK;
1158         return (BLKSEEK_FILE_WRITEONLY);
1159     }
1160
1161     /*
1162      *  Verify that kernel knows how to do O_BLKSEEK
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     if (read(fd, &dummy[0], BBSIZE) != BBSIZE) {        /* BBSIZE = 8192 */
1169         set_fserror("Cannot read from the device");
1170         return (BLKSEEK_PROCESSING_ERROR);
1171     }
1172
1173     if ((lstatus = lseek(fd, (off_t) 0, SEEK_CUR)) == (off_t) - 1) {
1174         set_fserror("Cannot lseek the device.");
1175         return (BLKSEEK_PROCESSING_ERROR);
1176     }
1177
1178     /*
1179      *  Set lseek to location 0
1180      */
1181     if (lseek(fd, (off_t) 0, SEEK_SET) == (off_t) - 1) {
1182         set_fserror("Cannot lseek the device.");
1183         return (BLKSEEK_PROCESSING_ERROR);
1184     }
1185
1186     if (lstatus == (off_t) (BBSIZE / DEV_BSIZE)) {
1187         *cntl_flags = flags | O_BLKSEEK;
1188         return (BLKSEEK_ENABLED);       /* Successfully enabled O_BLKSEEK */
1189     }
1190     *cntl_flags = flags & (~O_BLKSEEK); /* Turn off O_BLKSEEK bit */
1191     return (BLKSEEK_NOT_ENABLED);       /* O_BLKSEEK not enabled */
1192 }
1193
1194 setup_all_block_seek()
1195 {
1196     int opt = 0;
1197     seek_options = setup_block_seek(fsreadfd);
1198     switch (seek_options) {
1199     case BLKSEEK_ENABLED:
1200     case BLKSEEK_NOT_ENABLED:
1201         break;
1202     default:
1203         errexit("setup_block_seek on fsreadfd");
1204         break;
1205     }
1206     if (fswritefd == -1)
1207         goto done;
1208     switch (opt = setup_block_seek(fswritefd)) {
1209     case BLKSEEK_FILE_WRITEONLY:        /* WO block or char device. */
1210     case BLKSEEK_NOT_ENABLED:   /* regular file.            */
1211         if (seek_options != opt)
1212             printf
1213                 ("seek_options on fsreadfd (%d) and fswritefd (%d) do not match",
1214                  seek_options, opt);
1215         break;
1216     default:
1217         errexit("setup_block_seek on fswritefd");
1218         break;
1219     }
1220   done:
1221     if (debug)
1222         printf("read option = %d write option = %d\n", seek_options, opt);
1223 }
1224
1225
1226
1227 #endif /* AFS_HPUX101_ENV */