/* * Copyright (c) 1980, 1986 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #include #include #ifdef AFS_HPUX_ENV /* We need the old directory type headers (included below), so don't include * the normal dirent.h, or it will conflict. */ # undef HAVE_DIRENT_H # include # define LONGFILENAMES 1 # include # include # include # define DIRSIZ_MACRO # ifdef HAVE_USR_OLD_USR_INCLUDE_NDIR_H # include # else # include # endif #endif #include #include #define VICE /* allow us to put our changes in at will */ #ifdef AFS_VFSINCL_ENV #include #ifdef AFS_SUN5_ENV #include #include #define _KERNEL #include #undef _KERNEL #include #else #include #include #include #endif #else /* AFS_VFSINCL_ENV */ #include #ifndef AFS_HPUX_ENV #include #endif #include #endif /* AFS_VFSINCL_ENV */ #include "fsck.h" #if defined(AFS_SUN_ENV) #define AFS_NEWCG_ENV #else #undef AFS_NEWCG_ENV #endif long diskreads, totalreads; /* Disk cache statistics */ #if !defined(AFS_HPUX101_ENV) long lseek(); #endif #if defined(AFS_SUN_ENV) extern int iscorrupt; #endif #ifdef AFS_SUN_ENV extern int isdirty; #endif #ifdef AFS_SUN5_ENV #include #include #include offset_t llseek(); #endif ftypeok(dp) struct dinode *dp; { switch (dp->di_mode & IFMT) { case IFDIR: case IFREG: case IFBLK: case IFCHR: case IFLNK: case IFSOCK: #ifdef AFS_HPUX_ENV case IFNWK: #endif #ifdef IFIFO case IFIFO: #else #ifdef IFPORT case IFPORT: #endif #endif /* IFIFO */ return (1); default: if (debug) printf("bad file type 0%o\n", dp->di_mode); return (0); } } #ifdef AFS_HPUX_ENV extern int fixed; #endif reply(question) char *question; { int persevere; char c; if (preen) pfatal("INTERNAL ERROR: GOT TO reply()"); persevere = !strcmp(question, "CONTINUE"); printf("\n"); if (!persevere && (nflag || fswritefd < 0)) { printf("%s? no\n\n", question); #if defined(AFS_SUN_ENV) iscorrupt = 1; /* known to be corrupt */ #endif return (0); } if (yflag || (persevere && nflag)) { printf("%s? yes\n\n", question); return (1); } do { printf("%s? [yn] ", question); (void)fflush(stdout); c = getc(stdin); while (c != '\n' && getc(stdin) != '\n') if (feof(stdin)) return (0); } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N'); printf("\n"); if (c == 'y' || c == 'Y') return (1); #ifdef AFS_HPUX_ENV fixed = 0; #endif #if defined(AFS_SUN_ENV) iscorrupt = 1; /* known to be corrupt */ #endif return (0); } /* * Malloc buffers and set up cache. */ bufinit() { struct bufarea *bp; long bufcnt, i; char *bufp; bufp = malloc((unsigned int)sblock.fs_bsize); if (bufp == 0) errexit("cannot allocate buffer pool\n"); cgblk.b_un.b_buf = bufp; initbarea(&cgblk); bufhead.b_next = bufhead.b_prev = &bufhead; bufcnt = MAXBUFSPACE / sblock.fs_bsize; if (bufcnt < MINBUFS) bufcnt = MINBUFS; for (i = 0; i < bufcnt; i++) { bp = malloc(sizeof(struct bufarea)); bufp = malloc((unsigned int)sblock.fs_bsize); if (bp == NULL || bufp == NULL) { if (i >= MINBUFS) break; errexit("cannot allocate buffer pool\n"); } bp->b_un.b_buf = bufp; bp->b_prev = &bufhead; bp->b_next = bufhead.b_next; bufhead.b_next->b_prev = bp; bufhead.b_next = bp; initbarea(bp); } bufhead.b_size = i; /* save number of buffers */ #ifdef AFS_SUN5_ENVX pbp = pdirbp = NULL; #endif } /* * Manage a cache of directory blocks. */ struct bufarea * getdatablk(blkno, size) daddr_t blkno; long size; { struct bufarea *bp; for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next) if (bp->b_bno == fsbtodb(&sblock, blkno)) goto foundit; for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev) if ((bp->b_flags & B_INUSE) == 0) break; if (bp == &bufhead) errexit("deadlocked buffer pool\n"); getblk(bp, blkno, size); /* fall through */ foundit: totalreads++; bp->b_prev->b_next = bp->b_next; bp->b_next->b_prev = bp->b_prev; bp->b_prev = &bufhead; bp->b_next = bufhead.b_next; bufhead.b_next->b_prev = bp; bufhead.b_next = bp; bp->b_flags |= B_INUSE; return (bp); } struct bufarea * getblk(bp, blk, size) struct bufarea *bp; daddr_t blk; long size; { daddr_t dblk; dblk = fsbtodb(&sblock, blk); if (bp->b_bno == dblk) return (bp); flush(fswritefd, bp); diskreads++; bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size); bp->b_bno = dblk; bp->b_size = size; return (bp); } flush(fd, bp) int fd; struct bufarea *bp; { int i, j; caddr_t sip; long size; if (!bp->b_dirty) return; if (bp->b_errs != 0) { pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n", (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ", bp->b_bno); } bp->b_dirty = 0; bp->b_errs = 0; bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); if (bp != &sblk) return; #if defined(AFS_HPUX101_ENV) #if defined(AFS_HPUX110_ENV) /* jpm: Need a fix here */ if (0) #else /* AFS_HPUX110_ENV */ if (bwrite (fswritefd, (char *)sblock.fs_csp[0], fsbtodb(&sblock, sblock.fs_csaddr), fragroundup(&sblock, sblock.fs_cssize)) == 1) #endif /* else AFS_HPUX110_ENV */ { printf ("\nUnable to write to cylinder group summary area (fs_csaddr)\n"); printf("\tDisk write error at block %u\n", fsbtodb(&sblock, sblock.fs_csaddr)); } #else #if defined(AFS_SUN5_ENV) sip = (caddr_t) sblock.fs_u.fs_csp; for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { size = sblock.fs_cssize - i < sblock.fs_bsize ? sblock.fs_cssize - i : sblock.fs_bsize; bwrite(fswritefd, sip, fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), size); sip += size; } #else for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { bwrite(fswritefd, (char *)sblock.fs_csp[j], fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), sblock.fs_cssize - i < sblock.fs_bsize ? sblock.fs_cssize - i : sblock.fs_bsize); } #endif /* AFS_SUN5_ENV */ #endif /* AFS_HPUX101_ENV */ } rwerror(mesg, blk) char *mesg; daddr_t blk; { if (preen == 0) printf("\n"); pfatal("CANNOT %s: BLK %ld", mesg, blk); if (reply("CONTINUE") == 0) errexit("Program terminated\n"); } ckfini() { struct bufarea *bp, *nbp; int cnt = 0; flush(fswritefd, &sblk); #ifdef AFS_NEWCG_ENV if (havesb && sblk.b_bno != SBOFF / dev_bsize && !preen && reply("UPDATE STANDARD SUPERBLOCK")) { sblk.b_bno = SBOFF / dev_bsize; #else /* AFS_NEWCG_ENV */ if (havesb && sblk.b_bno != SBLOCK && !preen && reply("UPDATE STANDARD SUPERBLOCK")) { sblk.b_bno = SBLOCK; #endif /* AFS_NEWCG_ENV */ sbdirty(); flush(fswritefd, &sblk); } flush(fswritefd, &cgblk); if (cgblk.b_un.b_buf) { free(cgblk.b_un.b_buf); cgblk.b_un.b_buf = NULL; } for (bp = bufhead.b_prev; bp != &bufhead; bp = nbp) { cnt++; flush(fswritefd, bp); nbp = bp->b_prev; free(bp->b_un.b_buf); free(bp); } #ifdef AFS_SUN5_ENVX pbp = pdirbp = NULL; #endif if (bufhead.b_size != cnt) errexit("Panic: lost %d buffers\n", bufhead.b_size - cnt); if (debug) printf("cache missed %d of %d (%d%%)\n", diskreads, totalreads, diskreads * 100 / totalreads); (void)close(fsreadfd); (void)close(fswritefd); } #if !defined(AFS_HPUX101_ENV) bread(fd, buf, blk, size) int fd; char *buf; #ifdef AFS_SUN59_ENV diskaddr_t blk; #else daddr_t blk; #endif long size; { char *cp; int i, errs; #ifdef AFS_SUN5_ENV offset_t offset = (offset_t) blk << DEV_BSHIFT; offset_t addr; #endif #ifdef AFS_HPUX_ENV /* To fix a stripping related bug?? */ if (lseek(fd, blk * dev_bsize, 0) == -1) #else #ifdef AFS_SUN5_ENV if (llseek(fd, offset, 0) < 0) #else if (lseek(fd, blk * dev_bsize, 0) < 0) #endif #endif rwerror("SEEK", blk); else if (read(fd, buf, (int)size) == size) return (0); rwerror("READ", blk); #ifdef AFS_HPUX_ENV /* To fix a stripping related bug?? */ if (lseek(fd, blk * dev_bsize, 0) == -1) #else #ifdef AFS_SUN5_ENV if (llseek(fd, offset, 0) < 0) #else if (lseek(fd, blk * dev_bsize, 0) < 0) #endif #endif rwerror("SEEK", blk); errs = 0; memset(buf, 0, (int)size); printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:"); #ifdef AFS_SUN5_ENV for (cp = buf, i = 0; i < btodb(size); i++, cp += DEV_BSIZE) { addr = (offset_t) (blk + i) << DEV_BSHIFT; if (llseek(fd, addr, SEEK_CUR) < 0 || read(fd, cp, (int)secsize) < 0) { printf(" %d", blk + i); #else for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) { if (read(fd, cp, (int)secsize) < 0) { lseek(fd, blk * dev_bsize + i + secsize, 0); if (secsize != dev_bsize && dev_bsize != 1) printf(" %d (%d),", (blk * dev_bsize + i) / secsize, blk + i / dev_bsize); else printf(" %d,", blk + i / dev_bsize); #endif errs++; } } printf("\n"); return (errs); } bwrite(fd, buf, blk, size) int fd; char *buf; #ifdef AFS_SUN59_ENV diskaddr_t blk; #else daddr_t blk; #endif long size; { int i, n; char *cp; #ifdef AFS_SUN5_ENV offset_t offset = (offset_t) blk << DEV_BSHIFT; offset_t addr; if (blk < SBLOCK) { char msg[256]; sprintf(msg, "WARNING: Attempt to write illegal blkno %d on %s\n", blk, devname); if (debug) printf(msg); return; } #endif if (fd < 0) return; #ifdef AFS_HPUX_ENV /* To fix a stripping related bug?? */ if (lseek(fd, blk * dev_bsize, 0) == -1) #else #ifdef AFS_SUN5_ENV if (llseek(fd, offset, 0) < 0) #else if (lseek(fd, blk * dev_bsize, 0) < 0) #endif #endif rwerror("SEEK", blk); else if (write(fd, buf, (int)size) == size) { fsmodified = 1; return; } rwerror("WRITE", blk); #ifdef AFS_HPUX_ENV /* To fix a stripping related bug?? */ if (lseek(fd, blk * dev_bsize, 0) == -1) #else #ifdef AFS_SUN5_ENV if (llseek(fd, offset, 0) < 0) #else if (lseek(fd, blk * dev_bsize, 0) < 0) #endif #endif rwerror("SEEK", blk); printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); #ifdef AFS_SUN5_ENV for (cp = buf, i = 0; i < btodb(size); i++, cp += DEV_BSIZE) { n = 0; addr = (offset_t) (blk + i) << DEV_BSHIFT; if (llseek(fd, addr, SEEK_CUR) < 0 || (n = write(fd, cp, DEV_BSIZE)) < 0) { printf(" %d", blk + i); } else if (n > 0) { fsmodified = 1; } } #else for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize) if (write(fd, cp, (int)dev_bsize) < 0) { lseek(fd, blk * dev_bsize + i + dev_bsize, 0); printf(" %d,", blk + i / dev_bsize); } #endif printf("\n"); return; } #endif /* AFS_HPUX101_ENV */ /* * allocate a data block with the specified number of fragments */ allocblk(frags) long frags; { int i, j, k; if (frags <= 0 || frags > sblock.fs_frag) return (0); for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) { for (j = 0; j <= sblock.fs_frag - frags; j++) { if (testbmap(i + j)) continue; for (k = 1; k < frags; k++) if (testbmap(i + j + k)) break; if (k < frags) { j += k; continue; } for (k = 0; k < frags; k++) setbmap(i + j + k); n_blks += frags; return (i + j); } } return (0); } /* * Free a previously allocated block */ freeblk(blkno, frags) daddr_t blkno; long frags; { struct inodesc idesc; idesc.id_blkno = blkno; idesc.id_numfrags = frags; pass4check(&idesc); } /* * Find a pathname */ getpathname(namebuf, curdir, ino) char *namebuf; ino_t curdir, ino; { int len; char *cp; struct inodesc idesc; extern int findname(); if (statemap[ino] != DSTATE && statemap[ino] != DFOUND) { strcpy(namebuf, "?"); return; } memset(&idesc, 0, sizeof(struct inodesc)); idesc.id_type = DATA; cp = &namebuf[BUFSIZ - 1]; *cp = '\0'; if (curdir != ino) { idesc.id_parent = curdir; goto namelookup; } while (ino != ROOTINO) { idesc.id_number = ino; idesc.id_func = findino; idesc.id_name = ".."; #ifdef AFS_SUN5_ENV idesc.id_fix = NOFIX; #endif if ((ckinode(ginode(ino), &idesc) & FOUND) == 0) break; namelookup: idesc.id_number = idesc.id_parent; idesc.id_parent = ino; idesc.id_func = findname; idesc.id_name = namebuf; #ifdef AFS_SUN5_ENV idesc.id_fix = NOFIX; #endif if ((ckinode(ginode(idesc.id_number), &idesc) & FOUND) == 0) break; len = strlen(namebuf); cp -= len; if (cp < &namebuf[MAXNAMLEN]) break; memcpy(cp, namebuf, len); *--cp = '/'; ino = idesc.id_number; } if (ino != ROOTINO) { strcpy(namebuf, "?"); return; } memcpy(namebuf, cp, &namebuf[BUFSIZ] - cp); } void catch() { ckfini(); #ifdef AFS_SUN5_ENV exit(37); #else exit(12); #endif } /* * When preening, allow a single quit to signal * a special exit after filesystem checks complete * so that reboot sequence may be interrupted. */ void catchquit() { extern returntosingle; printf("returning to single-user after filesystem check\n"); returntosingle = 1; (void)signal(SIGQUIT, SIG_DFL); } /* * Ignore a single quit signal; wait and flush just in case. * Used by child processes in preen. */ void voidquit() { sleep(1); (void)signal(SIGQUIT, SIG_IGN); (void)signal(SIGQUIT, SIG_DFL); } /* * determine whether an inode should be fixed. */ dofix(idesc, msg) struct inodesc *idesc; char *msg; { switch (idesc->id_fix) { case DONTKNOW: if (idesc->id_type == DATA) direrror(idesc->id_number, msg); else pwarn(msg); if (preen) { printf(" (SALVAGED)\n"); idesc->id_fix = FIX; return (ALTERED); } if (reply("SALVAGE") == 0) { idesc->id_fix = NOFIX; return (0); } idesc->id_fix = FIX; return (ALTERED); case FIX: return (ALTERED); case NOFIX: return (0); default: errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix); } /* NOTREACHED */ } /* VARARGS1 */ errexit(s1, s2, s3, s4) char *s1; long s2, s3, s4; { printf(s1, s2, s3, s4); #ifdef AFS_SUN5_ENV exit(39); #else exit(8); #endif } /* * An unexpected inconsistency occured. * Die if preening, otherwise just print message and continue. */ /* VARARGS1 */ pfatal(s, a1, a2, a3) char *s; long a1, a2, a3; { if (preen) { printf("%s: ", devname); printf(s, a1, a2, a3); printf("\n"); printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", devname); #ifdef AFS_SUN5_ENV exit(36); #else exit(8); #endif } printf(s, a1, a2, a3); } /* * Pwarn just prints a message when not preening, * or a warning (preceded by filename) when preening. */ /* VARARGS1 */ pwarn(s, a1, a2, a3, a4, a5, a6) char *s; long a1, a2, a3, a4, a5, a6; { if (preen) printf("%s: ", devname); printf(s, a1, a2, a3, a4, a5, a6); } /* * Pwarn just prints a message when not preening, * or a warning (preceded by filename) when preening. */ /* VARARGS1 */ pinfo(s, a1, a2, a3, a4, a5, a6) char *s; long a1, a2, a3, a4, a5, a6; { if (preen) printf("%s: ", devname); printf(s, a1, a2, a3, a4, a5, a6); } #ifndef lint /* * Stub for routines from kernel. */ panic(s) char *s; { pfatal("INTERNAL INCONSISTENCY:"); errexit(s); } #endif #if defined(AFS_SUN_ENV) && !defined(AFS_SUN3_ENV) debugclean() { char s[256]; if (debug == 0) return; if ((iscorrupt == 0) && (isdirty == 0)) return; if ((sblock.fs_clean != FSSTABLE) && (sblock.fs_clean != FSCLEAN)) return; #ifdef AFS_SUN5_ENV if (FSOKAY != (sblock.fs_state + sblock.fs_time)) #else if (FSOKAY != (fs_get_state(&sblock) + sblock.fs_time)) #endif return; sprintf(s, "WARNING: inconsistencies detected on `%s' filesystem %s", sblock.fs_clean == FSSTABLE ? "stable" : "clean", devname); printf("%s\n", s); } updateclean() { struct bufarea cleanbuf; unsigned int size; unsigned int bno; unsigned int fsclean; #if defined(AFS_SUN5_ENV) offset_t sblkoff; #endif debugclean(); /* set fsclean to its appropriate value */ fsclean = sblock.fs_clean; #ifdef AFS_SUN5_ENV if (FSOKAY != (sblock.fs_state + sblock.fs_time)) #else if (FSOKAY != (fs_get_state(&sblock) + sblock.fs_time)) #endif fsclean = FSACTIVE; /* if necessary, update fs_clean and fs_state */ switch (fsclean) { case FSACTIVE: if (iscorrupt == 0) fsclean = FSSTABLE; break; case FSCLEAN: case FSSTABLE: if (iscorrupt) fsclean = FSACTIVE; break; default: if (iscorrupt) fsclean = FSACTIVE; else fsclean = FSSTABLE; } /* if fs_clean and fs_state are ok, do nothing */ if ((sblock.fs_clean == fsclean) && #ifdef AFS_SUN5_ENV (FSOKAY == (sblock.fs_state + sblock.fs_time))) #else (FSOKAY == (fs_get_state(&sblock) + sblock.fs_time))) #endif return; sblock.fs_clean = fsclean; #ifdef AFS_SUN5_ENV sblock.fs_state = sblock.fs_time; #else fs_set_state(&sblock, sblock.fs_time); #endif /* if superblock can't be written, return */ if (fswritefd < 0) return; /* read private copy of superblock, update clean flag, and write it */ bno = sblk.b_bno; size = sblk.b_size; #if defined(AFS_SUN5_ENV) sblkoff = (OFF_T) (bno) << DEV_BSHIFT; if (llseek(fsreadfd, sblkoff, 0) == -1) return; #else if (lseek(fsreadfd, (off_t) dbtob(bno), 0) == -1) return; #endif if ((cleanbuf.b_un.b_buf = malloc(size)) == NULL) errexit("out of memory"); if (read(fsreadfd, cleanbuf.b_un.b_buf, (int)size) != size) return; cleanbuf.b_un.b_fs->fs_clean = sblock.fs_clean; #ifdef AFS_SUN5_ENV cleanbuf.b_un.b_fs->fs_state = sblock.fs_state; #else fs_set_state(cleanbuf.b_un.b_fs, fs_get_state(&sblock)); #endif cleanbuf.b_un.b_fs->fs_time = sblock.fs_time; #if defined(AFS_SUN5_ENV) if (llseek(fswritefd, sblkoff, 0) == -1) return; #else if (lseek(fswritefd, (off_t) dbtob(bno), 0) == -1) return; #endif if (write(fswritefd, cleanbuf.b_un.b_buf, (int)size) != size) return; } printclean() { char *s; #ifdef AFS_SUN5_ENV if (FSOKAY != (sblock.fs_state + sblock.fs_time)) #else if (FSOKAY != (fs_get_state(&sblock) + sblock.fs_time)) #endif s = "unknown"; else switch (sblock.fs_clean) { case FSACTIVE: s = "active"; break; case FSCLEAN: s = "clean"; break; case FSSTABLE: s = "stable"; break; default: s = "unknown"; } if (preen) pwarn("is %s.\n", s); else printf("** %s is %s.\n", devname, s); } #endif #ifdef AFS_SUN5_ENV char * hasvfsopt(vfs, opt) struct vfstab *vfs; char *opt; { char *f, *opts; static char *tmpopts; if (vfs->vfs_mntopts == NULL) return (NULL); if (tmpopts == 0) { tmpopts = calloc(256, sizeof(char)); if (tmpopts == 0) return (0); } strncpy(tmpopts, vfs->vfs_mntopts, (sizeof(tmpopts) - 1)); opts = tmpopts; f = mntopt(&opts); for (; *f; f = mntopt(&opts)) { if (strncmp(opt, f, strlen(opt)) == 0) return (f - tmpopts + vfs->vfs_mntopts); } return (NULL); } writable(name) char *name; { int rw = 1; struct vfstab vfsbuf; FILE *vfstab; char *blkname, *unrawname(); vfstab = fopen(VFSTAB, "r"); if (vfstab == NULL) { printf("can't open %s\n", VFSTAB); return (1); } blkname = unrawname(name); if ((getvfsspec(vfstab, &vfsbuf, blkname) == 0) && (vfsbuf.vfs_fstype != NULL) && (strcmp(vfsbuf.vfs_fstype, MNTTYPE_UFS) == 0) && (hasvfsopt(&vfsbuf, MNTOPT_RO))) { rw = 0; } fclose(vfstab); return (rw); } mounted(name) char *name; { int found = 0; struct mnttab mnt; FILE *mnttab; struct stat device_stat, mount_stat; char *blkname, *unrawname(); mnttab = fopen(MNTTAB, "r"); if (mnttab == NULL) { printf("can't open %s\n", MNTTAB); return (0); } blkname = unrawname(name); while ((getmntent(mnttab, &mnt)) == NULL) { if (strcmp(mnt.mnt_fstype, MNTTYPE_UFS) != 0) { continue; } if (strcmp(blkname, mnt.mnt_special) == 0) { stat(mnt.mnt_mountp, &mount_stat); stat(mnt.mnt_special, &device_stat); if (device_stat.st_rdev == mount_stat.st_dev) { if (hasmntopt(&mnt, MNTOPT_RO) != 0) found = 2; /* mounted as RO */ else found = 1; /* mounted as R/W */ } break; } } fclose(mnttab); return (found); } #endif #if defined(AFS_HPUX101_ENV) #include "libfs.h" #include int seek_options; bread(fd, buf, blk, size) int fd; char *buf; daddr_t blk; long size; { int i = 0; off_t lseek_offset; switch (seek_options) { case BLKSEEK_ENABLED: lseek_offset = blk; break; case BLKSEEK_NOT_ENABLED: /* File */ #if defined(AFS_HPUX102_ENV) lseek_offset = dbtoo(blk); #else lseek_offset = dbtob(blk); #endif break; default: rwerror("BLKSEEK", blk); } if (lseek(fd, (off_t) lseek_offset, 0) == (off_t) - 1) rwerror("SEEK", blk); else if (read(fd, buf, (int)size) == size) return 0; rwerror("READ", blk); return 1; } bwrite(fd, buf, blk, size) int fd; char *buf; daddr_t blk; long size; { off_t lseek_offset; if (fd < 0) return 1; switch (seek_options) { case BLKSEEK_ENABLED: lseek_offset = blk; break; case BLKSEEK_NOT_ENABLED: /* File */ #if defined(AFS_HPUX102_ENV) lseek_offset = dbtoo(blk); #else lseek_offset = dbtob(blk); #endif break; default: rwerror("BLKSEEK", blk); } if (lseek(fd, (off_t) lseek_offset, 0) == (off_t) - 1) rwerror("SEEK", blk); else if (write(fd, buf, (int)size) == size) { fsmodified = 1; return 0; } rwerror("WRITE", blk); return 1; } int setup_block_seek(fd) int fd; /* File descriptor */ { int flags = 0; /* Flags to/from fcntl() */ return setup_block_seek_2(fd, &flags); } #define set_fserror printf int setup_block_seek_2(fd, cntl_flags) int fd; /* Input. File descriptor */ int *cntl_flags; /* Returned. Flags from fcntl() */ { int flags = 0; /* Flags to/from fcntl() */ off_t lstatus; /* Status from lseek() */ struct stat statarea; char dummy[MAXBSIZE]; *cntl_flags = 0; /* * Get control Flags */ if ((flags = fcntl(fd, F_GETFL)) == -1) { set_fserror("Cannot get file control flags."); return (BLKSEEK_PROCESSING_ERROR); } /* * Check if fd is a non-device file */ if (fstat(fd, &statarea) == -1) { set_fserror("Cannot get status information on file descriptor."); return (BLKSEEK_PROCESSING_ERROR); } if (((statarea.st_mode & S_IFMT) != S_IFCHR) && ((statarea.st_mode & S_IFMT) != S_IFBLK)) { /* Not a device file -- BLKSEEK only works on device files */ *cntl_flags = flags; /* O_BLKSEEK bit never set */ return (BLKSEEK_NOT_ENABLED); } /* * Set the fd to O_BLKSEEK */ if (fcntl(fd, F_SETFL, flags | O_BLKSEEK) == -1) { set_fserror("Cannot set file control flags."); return (BLKSEEK_PROCESSING_ERROR); } if (flags & O_WRONLY) { /* Set lseek to location 0 before returning */ if (lseek(fd, (off_t) 0, SEEK_SET) == (off_t) - 1) { set_fserror("Cannot lseek the device."); return (BLKSEEK_PROCESSING_ERROR); } if (debug) set_fserror ("File is write only. Cannot Verify O_BLKSEEK mode set."); *cntl_flags = flags | O_BLKSEEK; return (BLKSEEK_FILE_WRITEONLY); } /* * Verify that kernel knows how to do O_BLKSEEK */ if (lseek(fd, (off_t) 0, SEEK_SET) == (off_t) - 1) { set_fserror("Cannot lseek the device."); return (BLKSEEK_PROCESSING_ERROR); } if (read(fd, &dummy[0], BBSIZE) != BBSIZE) { /* BBSIZE = 8192 */ set_fserror("Cannot read from the device"); return (BLKSEEK_PROCESSING_ERROR); } if ((lstatus = lseek(fd, (off_t) 0, SEEK_CUR)) == (off_t) - 1) { set_fserror("Cannot lseek the device."); return (BLKSEEK_PROCESSING_ERROR); } /* * Set lseek to location 0 */ if (lseek(fd, (off_t) 0, SEEK_SET) == (off_t) - 1) { set_fserror("Cannot lseek the device."); return (BLKSEEK_PROCESSING_ERROR); } if (lstatus == (off_t) (BBSIZE / DEV_BSIZE)) { *cntl_flags = flags | O_BLKSEEK; return (BLKSEEK_ENABLED); /* Successfully enabled O_BLKSEEK */ } *cntl_flags = flags & (~O_BLKSEEK); /* Turn off O_BLKSEEK bit */ return (BLKSEEK_NOT_ENABLED); /* O_BLKSEEK not enabled */ } setup_all_block_seek() { int opt = 0; seek_options = setup_block_seek(fsreadfd); switch (seek_options) { case BLKSEEK_ENABLED: case BLKSEEK_NOT_ENABLED: break; default: errexit("setup_block_seek on fsreadfd"); break; } if (fswritefd == -1) goto done; switch (opt = setup_block_seek(fswritefd)) { case BLKSEEK_FILE_WRITEONLY: /* WO block or char device. */ case BLKSEEK_NOT_ENABLED: /* regular file. */ if (seek_options != opt) printf ("seek_options on fsreadfd (%d) and fswritefd (%d) do not match", seek_options, opt); break; default: errexit("setup_block_seek on fswritefd"); break; } done: if (debug) printf("read option = %d write option = %d\n", seek_options, opt); } #endif /* AFS_HPUX101_ENV */