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