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