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