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