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