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