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