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