1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright 1999 Sun Microsystems, Inc. All rights reserved. 3*0Sstevel@tonic-gate * Use is subject to license terms. 4*0Sstevel@tonic-gate */ 5*0Sstevel@tonic-gate 6*0Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 7*0Sstevel@tonic-gate /* All Rights Reserved */ 8*0Sstevel@tonic-gate 9*0Sstevel@tonic-gate /* 10*0Sstevel@tonic-gate * Copyright (c) 1980, 1986, 1990 The Regents of the University of California. 11*0Sstevel@tonic-gate * All rights reserved. 12*0Sstevel@tonic-gate * 13*0Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted 14*0Sstevel@tonic-gate * provided that: (1) source distributions retain this entire copyright 15*0Sstevel@tonic-gate * notice and comment, and (2) distributions including binaries display 16*0Sstevel@tonic-gate * the following acknowledgement: ``This product includes software 17*0Sstevel@tonic-gate * developed by the University of California, Berkeley and its contributors'' 18*0Sstevel@tonic-gate * in the documentation or other materials provided with the distribution 19*0Sstevel@tonic-gate * and in all advertising materials mentioning features or use of this 20*0Sstevel@tonic-gate * software. Neither the name of the University nor the names of its 21*0Sstevel@tonic-gate * contributors may be used to endorse or promote products derived 22*0Sstevel@tonic-gate * from this software without specific prior written permission. 23*0Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 24*0Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 25*0Sstevel@tonic-gate * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 26*0Sstevel@tonic-gate */ 27*0Sstevel@tonic-gate 28*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate #include <stdio.h> 31*0Sstevel@tonic-gate #include <fcntl.h> 32*0Sstevel@tonic-gate #include <errno.h> 33*0Sstevel@tonic-gate #include <unistd.h> 34*0Sstevel@tonic-gate #include <stdlib.h> 35*0Sstevel@tonic-gate #include <fcntl.h> 36*0Sstevel@tonic-gate #include <string.h> 37*0Sstevel@tonic-gate #include <strings.h> 38*0Sstevel@tonic-gate #include <ctype.h> 39*0Sstevel@tonic-gate #include <malloc.h> 40*0Sstevel@tonic-gate #include <signal.h> 41*0Sstevel@tonic-gate #include <sys/param.h> 42*0Sstevel@tonic-gate #include <sys/types.h> 43*0Sstevel@tonic-gate #include <sys/mntent.h> 44*0Sstevel@tonic-gate #include <sys/filio.h> 45*0Sstevel@tonic-gate #include <sys/vnode.h> 46*0Sstevel@tonic-gate #include <sys/mnttab.h> 47*0Sstevel@tonic-gate #include <sys/types.h> 48*0Sstevel@tonic-gate #include <sys/stat.h> 49*0Sstevel@tonic-gate #include <sys/vfstab.h> 50*0Sstevel@tonic-gate #include <sys/sysmacros.h> 51*0Sstevel@tonic-gate #include <sys/fs/udf_volume.h> 52*0Sstevel@tonic-gate #include "fsck.h" 53*0Sstevel@tonic-gate #include <sys/lockfs.h> 54*0Sstevel@tonic-gate #include <locale.h> 55*0Sstevel@tonic-gate 56*0Sstevel@tonic-gate extern int32_t verifytag(struct tag *, uint32_t, struct tag *, int); 57*0Sstevel@tonic-gate extern char *tagerrs[]; 58*0Sstevel@tonic-gate extern void maketag(struct tag *, struct tag *); 59*0Sstevel@tonic-gate extern char *hasvfsopt(struct vfstab *, char *); 60*0Sstevel@tonic-gate static struct bufarea *getdatablk(daddr_t, long); 61*0Sstevel@tonic-gate static struct bufarea *getblk(struct bufarea *, daddr_t, long); 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate void flush(int32_t, struct bufarea *); 64*0Sstevel@tonic-gate int32_t bread(int32_t, char *, daddr_t, long); 65*0Sstevel@tonic-gate void bwrite(int, char *, daddr_t, long); 66*0Sstevel@tonic-gate static int32_t getline(FILE *, char *, int32_t); 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate static long diskreads, totalreads; /* Disk cache statistics */ 69*0Sstevel@tonic-gate offset_t llseek(); 70*0Sstevel@tonic-gate extern unsigned int largefile_count; 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gate /* 73*0Sstevel@tonic-gate * An unexpected inconsistency occured. 74*0Sstevel@tonic-gate * Die if preening, otherwise just print message and continue. 75*0Sstevel@tonic-gate */ 76*0Sstevel@tonic-gate /* VARARGS1 */ 77*0Sstevel@tonic-gate void 78*0Sstevel@tonic-gate pfatal(s, a1, a2, a3) 79*0Sstevel@tonic-gate char *s; 80*0Sstevel@tonic-gate { 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate if (preen) { 83*0Sstevel@tonic-gate (void) printf("%s: ", devname); 84*0Sstevel@tonic-gate (void) printf(s, a1, a2, a3); 85*0Sstevel@tonic-gate (void) printf("\n"); 86*0Sstevel@tonic-gate (void) printf( 87*0Sstevel@tonic-gate gettext("%s: UNEXPECTED INCONSISTENCY; RUN fsck " 88*0Sstevel@tonic-gate "MANUALLY.\n"), devname); 89*0Sstevel@tonic-gate exit(36); 90*0Sstevel@tonic-gate } 91*0Sstevel@tonic-gate (void) printf(s, a1, a2, a3); 92*0Sstevel@tonic-gate } 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate /* 95*0Sstevel@tonic-gate * Pwarn just prints a message when not preening, 96*0Sstevel@tonic-gate * or a warning (preceded by filename) when preening. 97*0Sstevel@tonic-gate */ 98*0Sstevel@tonic-gate /* VARARGS1 */ 99*0Sstevel@tonic-gate void 100*0Sstevel@tonic-gate pwarn(s, a1, a2, a3, a4, a5, a6) 101*0Sstevel@tonic-gate char *s; 102*0Sstevel@tonic-gate { 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate if (preen) 105*0Sstevel@tonic-gate (void) printf("%s: ", devname); 106*0Sstevel@tonic-gate (void) printf(s, a1, a2, a3, a4, a5, a6); 107*0Sstevel@tonic-gate } 108*0Sstevel@tonic-gate 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate /* VARARGS1 */ 111*0Sstevel@tonic-gate void 112*0Sstevel@tonic-gate errexit(s1, s2, s3, s4) 113*0Sstevel@tonic-gate char *s1; 114*0Sstevel@tonic-gate { 115*0Sstevel@tonic-gate (void) printf(s1, s2, s3, s4); 116*0Sstevel@tonic-gate exit(39); 117*0Sstevel@tonic-gate } 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate void 120*0Sstevel@tonic-gate markbusy(daddr_t block, long count) 121*0Sstevel@tonic-gate { 122*0Sstevel@tonic-gate register int i; 123*0Sstevel@tonic-gate 124*0Sstevel@tonic-gate count = roundup(count, secsize) / secsize; 125*0Sstevel@tonic-gate for (i = 0; i < count; i++, block++) { 126*0Sstevel@tonic-gate if ((unsigned)block > part_len) { 127*0Sstevel@tonic-gate pwarn(gettext("Block %lx out of range\n"), block); 128*0Sstevel@tonic-gate break; 129*0Sstevel@tonic-gate } 130*0Sstevel@tonic-gate if (testbusy(block)) 131*0Sstevel@tonic-gate pwarn(gettext("Dup block %lx\n"), block); 132*0Sstevel@tonic-gate else { 133*0Sstevel@tonic-gate n_blks++; 134*0Sstevel@tonic-gate setbusy(block); 135*0Sstevel@tonic-gate } 136*0Sstevel@tonic-gate } 137*0Sstevel@tonic-gate } 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gate void 140*0Sstevel@tonic-gate printfree() 141*0Sstevel@tonic-gate { 142*0Sstevel@tonic-gate int i, startfree, endfree; 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate startfree = -1; 145*0Sstevel@tonic-gate for (i = 0; i < part_len; i++) { 146*0Sstevel@tonic-gate if (!testbusy(i)) { 147*0Sstevel@tonic-gate if (startfree <= 0) 148*0Sstevel@tonic-gate startfree = i; 149*0Sstevel@tonic-gate endfree = i; 150*0Sstevel@tonic-gate } else if (startfree >= 0) { 151*0Sstevel@tonic-gate (void) printf("free: %x-%x\n", startfree, endfree - 1); 152*0Sstevel@tonic-gate startfree = -1; 153*0Sstevel@tonic-gate } 154*0Sstevel@tonic-gate } 155*0Sstevel@tonic-gate if (startfree >= 0) { 156*0Sstevel@tonic-gate (void) printf("free: %x-%x\n", startfree, endfree); 157*0Sstevel@tonic-gate } 158*0Sstevel@tonic-gate } 159*0Sstevel@tonic-gate 160*0Sstevel@tonic-gate struct bufarea * 161*0Sstevel@tonic-gate getfilentry(uint32_t block, int len) 162*0Sstevel@tonic-gate { 163*0Sstevel@tonic-gate struct bufarea *bp; 164*0Sstevel@tonic-gate struct file_entry *fp; 165*0Sstevel@tonic-gate int err; 166*0Sstevel@tonic-gate 167*0Sstevel@tonic-gate if (len > fsbsize) { 168*0Sstevel@tonic-gate (void) printf(gettext("File entry at %x is too long " 169*0Sstevel@tonic-gate "(%d bytes)\n"), block, len); 170*0Sstevel@tonic-gate len = fsbsize; 171*0Sstevel@tonic-gate } 172*0Sstevel@tonic-gate bp = getdatablk((daddr_t)(block + part_start), fsbsize); 173*0Sstevel@tonic-gate if (bp->b_errs) { 174*0Sstevel@tonic-gate bp->b_flags &= ~B_INUSE; 175*0Sstevel@tonic-gate return (NULL); 176*0Sstevel@tonic-gate } 177*0Sstevel@tonic-gate /* LINTED */ 178*0Sstevel@tonic-gate fp = (struct file_entry *)bp->b_un.b_buf; 179*0Sstevel@tonic-gate err = verifytag(&fp->fe_tag, block, &fp->fe_tag, UD_FILE_ENTRY); 180*0Sstevel@tonic-gate if (err) { 181*0Sstevel@tonic-gate (void) printf(gettext("Tag error %s or bad file entry, " 182*0Sstevel@tonic-gate "tag=%d\n"), tagerrs[err], fp->fe_tag.tag_id); 183*0Sstevel@tonic-gate bp->b_flags &= ~B_INUSE; 184*0Sstevel@tonic-gate return (NULL); 185*0Sstevel@tonic-gate } 186*0Sstevel@tonic-gate return (bp); 187*0Sstevel@tonic-gate } 188*0Sstevel@tonic-gate 189*0Sstevel@tonic-gate void 190*0Sstevel@tonic-gate putfilentry(struct bufarea *bp) 191*0Sstevel@tonic-gate { 192*0Sstevel@tonic-gate struct file_entry *fp; 193*0Sstevel@tonic-gate 194*0Sstevel@tonic-gate /* LINTED */ 195*0Sstevel@tonic-gate fp = (struct file_entry *)bp->b_un.b_buf; 196*0Sstevel@tonic-gate maketag(&fp->fe_tag, &fp->fe_tag); 197*0Sstevel@tonic-gate } 198*0Sstevel@tonic-gate 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate int32_t 201*0Sstevel@tonic-gate reply(char *question) 202*0Sstevel@tonic-gate { 203*0Sstevel@tonic-gate char line[80]; 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate if (preen) 206*0Sstevel@tonic-gate pfatal(gettext("INTERNAL ERROR: GOT TO reply()")); 207*0Sstevel@tonic-gate (void) printf("\n%s? ", question); 208*0Sstevel@tonic-gate if (nflag || fswritefd < 0) { 209*0Sstevel@tonic-gate (void) printf(gettext(" no\n\n")); 210*0Sstevel@tonic-gate iscorrupt = 1; /* known to be corrupt */ 211*0Sstevel@tonic-gate return (0); 212*0Sstevel@tonic-gate } 213*0Sstevel@tonic-gate if (yflag) { 214*0Sstevel@tonic-gate (void) printf(gettext(" yes\n\n")); 215*0Sstevel@tonic-gate return (1); 216*0Sstevel@tonic-gate } 217*0Sstevel@tonic-gate if (getline(stdin, line, sizeof (line)) == EOF) 218*0Sstevel@tonic-gate errexit("\n"); 219*0Sstevel@tonic-gate (void) printf("\n"); 220*0Sstevel@tonic-gate if (line[0] == 'y' || line[0] == 'Y') 221*0Sstevel@tonic-gate return (1); 222*0Sstevel@tonic-gate else { 223*0Sstevel@tonic-gate iscorrupt = 1; /* known to be corrupt */ 224*0Sstevel@tonic-gate return (0); 225*0Sstevel@tonic-gate } 226*0Sstevel@tonic-gate } 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate int32_t 229*0Sstevel@tonic-gate getline(FILE *fp, char *loc, int32_t maxlen) 230*0Sstevel@tonic-gate { 231*0Sstevel@tonic-gate register n; 232*0Sstevel@tonic-gate register char *p, *lastloc; 233*0Sstevel@tonic-gate 234*0Sstevel@tonic-gate p = loc; 235*0Sstevel@tonic-gate lastloc = &p[maxlen-1]; 236*0Sstevel@tonic-gate while ((n = getc(fp)) != '\n') { 237*0Sstevel@tonic-gate if (n == EOF) 238*0Sstevel@tonic-gate return (EOF); 239*0Sstevel@tonic-gate if (!isspace(n) && p < lastloc) 240*0Sstevel@tonic-gate *p++ = n; 241*0Sstevel@tonic-gate } 242*0Sstevel@tonic-gate *p = 0; 243*0Sstevel@tonic-gate return (p - loc); 244*0Sstevel@tonic-gate } 245*0Sstevel@tonic-gate /* 246*0Sstevel@tonic-gate * Malloc buffers and set up cache. 247*0Sstevel@tonic-gate */ 248*0Sstevel@tonic-gate void 249*0Sstevel@tonic-gate bufinit() 250*0Sstevel@tonic-gate { 251*0Sstevel@tonic-gate register struct bufarea *bp; 252*0Sstevel@tonic-gate long bufcnt, i; 253*0Sstevel@tonic-gate char *bufp; 254*0Sstevel@tonic-gate 255*0Sstevel@tonic-gate bufp = malloc((unsigned int)fsbsize); 256*0Sstevel@tonic-gate if (bufp == 0) 257*0Sstevel@tonic-gate errexit(gettext("cannot allocate buffer pool\n")); 258*0Sstevel@tonic-gate bufhead.b_next = bufhead.b_prev = &bufhead; 259*0Sstevel@tonic-gate bufcnt = MAXBUFSPACE / fsbsize; 260*0Sstevel@tonic-gate if (bufcnt < MINBUFS) 261*0Sstevel@tonic-gate bufcnt = MINBUFS; 262*0Sstevel@tonic-gate for (i = 0; i < bufcnt; i++) { 263*0Sstevel@tonic-gate bp = (struct bufarea *)malloc(sizeof (struct bufarea)); 264*0Sstevel@tonic-gate bufp = malloc((unsigned int)fsbsize); 265*0Sstevel@tonic-gate if (bp == NULL || bufp == NULL) { 266*0Sstevel@tonic-gate if (i >= MINBUFS) 267*0Sstevel@tonic-gate break; 268*0Sstevel@tonic-gate errexit(gettext("cannot allocate buffer pool\n")); 269*0Sstevel@tonic-gate } 270*0Sstevel@tonic-gate bp->b_un.b_buf = bufp; 271*0Sstevel@tonic-gate bp->b_prev = &bufhead; 272*0Sstevel@tonic-gate bp->b_next = bufhead.b_next; 273*0Sstevel@tonic-gate bufhead.b_next->b_prev = bp; 274*0Sstevel@tonic-gate bufhead.b_next = bp; 275*0Sstevel@tonic-gate initbarea(bp); 276*0Sstevel@tonic-gate } 277*0Sstevel@tonic-gate bufhead.b_size = i; /* save number of buffers */ 278*0Sstevel@tonic-gate pbp = pdirbp = NULL; 279*0Sstevel@tonic-gate } 280*0Sstevel@tonic-gate 281*0Sstevel@tonic-gate /* 282*0Sstevel@tonic-gate * Manage a cache of directory blocks. 283*0Sstevel@tonic-gate */ 284*0Sstevel@tonic-gate static struct bufarea * 285*0Sstevel@tonic-gate getdatablk(daddr_t blkno, long size) 286*0Sstevel@tonic-gate { 287*0Sstevel@tonic-gate register struct bufarea *bp; 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next) 290*0Sstevel@tonic-gate if (bp->b_bno == fsbtodb(blkno)) 291*0Sstevel@tonic-gate goto foundit; 292*0Sstevel@tonic-gate for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev) 293*0Sstevel@tonic-gate if ((bp->b_flags & B_INUSE) == 0) 294*0Sstevel@tonic-gate break; 295*0Sstevel@tonic-gate if (bp == &bufhead) 296*0Sstevel@tonic-gate errexit(gettext("deadlocked buffer pool\n")); 297*0Sstevel@tonic-gate (void) getblk(bp, blkno, size); 298*0Sstevel@tonic-gate /* fall through */ 299*0Sstevel@tonic-gate foundit: 300*0Sstevel@tonic-gate totalreads++; 301*0Sstevel@tonic-gate bp->b_prev->b_next = bp->b_next; 302*0Sstevel@tonic-gate bp->b_next->b_prev = bp->b_prev; 303*0Sstevel@tonic-gate bp->b_prev = &bufhead; 304*0Sstevel@tonic-gate bp->b_next = bufhead.b_next; 305*0Sstevel@tonic-gate bufhead.b_next->b_prev = bp; 306*0Sstevel@tonic-gate bufhead.b_next = bp; 307*0Sstevel@tonic-gate bp->b_flags |= B_INUSE; 308*0Sstevel@tonic-gate return (bp); 309*0Sstevel@tonic-gate } 310*0Sstevel@tonic-gate 311*0Sstevel@tonic-gate static struct bufarea * 312*0Sstevel@tonic-gate getblk(struct bufarea *bp, daddr_t blk, long size) 313*0Sstevel@tonic-gate { 314*0Sstevel@tonic-gate daddr_t dblk; 315*0Sstevel@tonic-gate 316*0Sstevel@tonic-gate dblk = fsbtodb(blk); 317*0Sstevel@tonic-gate if (bp->b_bno == dblk) 318*0Sstevel@tonic-gate return (bp); 319*0Sstevel@tonic-gate flush(fswritefd, bp); 320*0Sstevel@tonic-gate diskreads++; 321*0Sstevel@tonic-gate bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size); 322*0Sstevel@tonic-gate bp->b_bno = dblk; 323*0Sstevel@tonic-gate bp->b_size = size; 324*0Sstevel@tonic-gate return (bp); 325*0Sstevel@tonic-gate } 326*0Sstevel@tonic-gate 327*0Sstevel@tonic-gate void 328*0Sstevel@tonic-gate flush(int32_t fd, struct bufarea *bp) 329*0Sstevel@tonic-gate { 330*0Sstevel@tonic-gate if (!bp->b_dirty) 331*0Sstevel@tonic-gate return; 332*0Sstevel@tonic-gate if (bp->b_errs != 0) 333*0Sstevel@tonic-gate pfatal(gettext("WRITING ZERO'ED BLOCK %d TO DISK\n"), 334*0Sstevel@tonic-gate bp->b_bno); 335*0Sstevel@tonic-gate bp->b_dirty = 0; 336*0Sstevel@tonic-gate bp->b_errs = 0; 337*0Sstevel@tonic-gate bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); 338*0Sstevel@tonic-gate } 339*0Sstevel@tonic-gate 340*0Sstevel@tonic-gate static void 341*0Sstevel@tonic-gate rwerror(char *mesg, daddr_t blk) 342*0Sstevel@tonic-gate { 343*0Sstevel@tonic-gate 344*0Sstevel@tonic-gate if (preen == 0) 345*0Sstevel@tonic-gate (void) printf("\n"); 346*0Sstevel@tonic-gate pfatal(gettext("CANNOT %s: BLK %ld"), mesg, blk); 347*0Sstevel@tonic-gate if (reply(gettext("CONTINUE")) == 0) 348*0Sstevel@tonic-gate errexit(gettext("Program terminated\n")); 349*0Sstevel@tonic-gate } 350*0Sstevel@tonic-gate 351*0Sstevel@tonic-gate void 352*0Sstevel@tonic-gate ckfini() 353*0Sstevel@tonic-gate { 354*0Sstevel@tonic-gate struct bufarea *bp, *nbp; 355*0Sstevel@tonic-gate int cnt = 0; 356*0Sstevel@tonic-gate 357*0Sstevel@tonic-gate for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) { 358*0Sstevel@tonic-gate cnt++; 359*0Sstevel@tonic-gate flush(fswritefd, bp); 360*0Sstevel@tonic-gate nbp = bp->b_prev; 361*0Sstevel@tonic-gate free(bp->b_un.b_buf); 362*0Sstevel@tonic-gate free((char *)bp); 363*0Sstevel@tonic-gate } 364*0Sstevel@tonic-gate pbp = pdirbp = NULL; 365*0Sstevel@tonic-gate if (bufhead.b_size != cnt) 366*0Sstevel@tonic-gate errexit(gettext("Panic: lost %d buffers\n"), 367*0Sstevel@tonic-gate bufhead.b_size - cnt); 368*0Sstevel@tonic-gate if (debug) 369*0Sstevel@tonic-gate (void) printf("cache missed %ld of %ld (%ld%%)\n", 370*0Sstevel@tonic-gate diskreads, totalreads, 371*0Sstevel@tonic-gate totalreads ? diskreads * 100 / totalreads : 0); 372*0Sstevel@tonic-gate (void) close(fsreadfd); 373*0Sstevel@tonic-gate (void) close(fswritefd); 374*0Sstevel@tonic-gate } 375*0Sstevel@tonic-gate 376*0Sstevel@tonic-gate int32_t 377*0Sstevel@tonic-gate bread(int fd, char *buf, daddr_t blk, long size) 378*0Sstevel@tonic-gate { 379*0Sstevel@tonic-gate char *cp; 380*0Sstevel@tonic-gate int i, errs; 381*0Sstevel@tonic-gate offset_t offset = ldbtob(blk); 382*0Sstevel@tonic-gate offset_t addr; 383*0Sstevel@tonic-gate 384*0Sstevel@tonic-gate if (llseek(fd, offset, 0) < 0) 385*0Sstevel@tonic-gate rwerror(gettext("SEEK"), blk); 386*0Sstevel@tonic-gate else if (read(fd, buf, (int)size) == size) 387*0Sstevel@tonic-gate return (0); 388*0Sstevel@tonic-gate rwerror(gettext("READ"), blk); 389*0Sstevel@tonic-gate if (llseek(fd, offset, 0) < 0) 390*0Sstevel@tonic-gate rwerror(gettext("SEEK"), blk); 391*0Sstevel@tonic-gate errs = 0; 392*0Sstevel@tonic-gate bzero(buf, (int)size); 393*0Sstevel@tonic-gate pwarn(gettext("THE FOLLOWING SECTORS COULD NOT BE READ:")); 394*0Sstevel@tonic-gate for (cp = buf, i = 0; i < btodb(size); i++, cp += DEV_BSIZE) { 395*0Sstevel@tonic-gate addr = ldbtob(blk + i); 396*0Sstevel@tonic-gate if (llseek(fd, addr, SEEK_CUR) < 0 || 397*0Sstevel@tonic-gate read(fd, cp, (int)secsize) < 0) { 398*0Sstevel@tonic-gate (void) printf(" %ld", blk + i); 399*0Sstevel@tonic-gate errs++; 400*0Sstevel@tonic-gate } 401*0Sstevel@tonic-gate } 402*0Sstevel@tonic-gate (void) printf("\n"); 403*0Sstevel@tonic-gate return (errs); 404*0Sstevel@tonic-gate } 405*0Sstevel@tonic-gate 406*0Sstevel@tonic-gate void 407*0Sstevel@tonic-gate bwrite(int fd, char *buf, daddr_t blk, long size) 408*0Sstevel@tonic-gate { 409*0Sstevel@tonic-gate int i, n; 410*0Sstevel@tonic-gate char *cp; 411*0Sstevel@tonic-gate offset_t offset = ldbtob(blk); 412*0Sstevel@tonic-gate offset_t addr; 413*0Sstevel@tonic-gate 414*0Sstevel@tonic-gate if (fd < 0) 415*0Sstevel@tonic-gate return; 416*0Sstevel@tonic-gate if (llseek(fd, offset, 0) < 0) 417*0Sstevel@tonic-gate rwerror(gettext("SEEK"), blk); 418*0Sstevel@tonic-gate else if (write(fd, buf, (int)size) == size) { 419*0Sstevel@tonic-gate fsmodified = 1; 420*0Sstevel@tonic-gate return; 421*0Sstevel@tonic-gate } 422*0Sstevel@tonic-gate rwerror(gettext("WRITE"), blk); 423*0Sstevel@tonic-gate if (llseek(fd, offset, 0) < 0) 424*0Sstevel@tonic-gate rwerror(gettext("SEEK"), blk); 425*0Sstevel@tonic-gate pwarn(gettext("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:")); 426*0Sstevel@tonic-gate for (cp = buf, i = 0; i < btodb(size); i++, cp += DEV_BSIZE) { 427*0Sstevel@tonic-gate n = 0; 428*0Sstevel@tonic-gate addr = ldbtob(blk + i); 429*0Sstevel@tonic-gate if (llseek(fd, addr, SEEK_CUR) < 0 || 430*0Sstevel@tonic-gate (n = write(fd, cp, DEV_BSIZE)) < 0) { 431*0Sstevel@tonic-gate (void) printf(" %ld", blk + i); 432*0Sstevel@tonic-gate } else if (n > 0) { 433*0Sstevel@tonic-gate fsmodified = 1; 434*0Sstevel@tonic-gate } 435*0Sstevel@tonic-gate 436*0Sstevel@tonic-gate } 437*0Sstevel@tonic-gate (void) printf("\n"); 438*0Sstevel@tonic-gate } 439*0Sstevel@tonic-gate 440*0Sstevel@tonic-gate void 441*0Sstevel@tonic-gate catch() 442*0Sstevel@tonic-gate { 443*0Sstevel@tonic-gate ckfini(); 444*0Sstevel@tonic-gate exit(37); 445*0Sstevel@tonic-gate } 446*0Sstevel@tonic-gate 447*0Sstevel@tonic-gate /* 448*0Sstevel@tonic-gate * When preening, allow a single quit to signal 449*0Sstevel@tonic-gate * a special exit after filesystem checks complete 450*0Sstevel@tonic-gate * so that reboot sequence may be interrupted. 451*0Sstevel@tonic-gate */ 452*0Sstevel@tonic-gate void 453*0Sstevel@tonic-gate catchquit() 454*0Sstevel@tonic-gate { 455*0Sstevel@tonic-gate extern returntosingle; 456*0Sstevel@tonic-gate 457*0Sstevel@tonic-gate (void) printf(gettext("returning to single-user after filesystem " 458*0Sstevel@tonic-gate "check\n")); 459*0Sstevel@tonic-gate returntosingle = 1; 460*0Sstevel@tonic-gate (void) signal(SIGQUIT, SIG_DFL); 461*0Sstevel@tonic-gate } 462*0Sstevel@tonic-gate 463*0Sstevel@tonic-gate /* 464*0Sstevel@tonic-gate * determine whether an inode should be fixed. 465*0Sstevel@tonic-gate */ 466*0Sstevel@tonic-gate /* ARGSUSED1 */ 467*0Sstevel@tonic-gate int32_t 468*0Sstevel@tonic-gate dofix(struct inodesc *idesc, char *msg) 469*0Sstevel@tonic-gate { 470*0Sstevel@tonic-gate 471*0Sstevel@tonic-gate switch (idesc->id_fix) { 472*0Sstevel@tonic-gate 473*0Sstevel@tonic-gate case DONTKNOW: 474*0Sstevel@tonic-gate pwarn(msg); 475*0Sstevel@tonic-gate if (preen) { 476*0Sstevel@tonic-gate (void) printf(gettext(" (SALVAGED)\n")); 477*0Sstevel@tonic-gate idesc->id_fix = FIX; 478*0Sstevel@tonic-gate return (ALTERED); 479*0Sstevel@tonic-gate } 480*0Sstevel@tonic-gate if (reply(gettext("SALVAGE")) == 0) { 481*0Sstevel@tonic-gate idesc->id_fix = NOFIX; 482*0Sstevel@tonic-gate return (0); 483*0Sstevel@tonic-gate } 484*0Sstevel@tonic-gate idesc->id_fix = FIX; 485*0Sstevel@tonic-gate return (ALTERED); 486*0Sstevel@tonic-gate 487*0Sstevel@tonic-gate case FIX: 488*0Sstevel@tonic-gate return (ALTERED); 489*0Sstevel@tonic-gate 490*0Sstevel@tonic-gate case NOFIX: 491*0Sstevel@tonic-gate return (0); 492*0Sstevel@tonic-gate 493*0Sstevel@tonic-gate default: 494*0Sstevel@tonic-gate errexit(gettext("UNKNOWN INODESC FIX MODE %d\n"), 495*0Sstevel@tonic-gate idesc->id_fix); 496*0Sstevel@tonic-gate } 497*0Sstevel@tonic-gate /* NOTREACHED */ 498*0Sstevel@tonic-gate } 499*0Sstevel@tonic-gate 500*0Sstevel@tonic-gate /* 501*0Sstevel@tonic-gate * Check to see if unraw version of name is already mounted. 502*0Sstevel@tonic-gate * Since we do not believe /etc/mnttab, we stat the mount point 503*0Sstevel@tonic-gate * to see if it is really looks mounted. 504*0Sstevel@tonic-gate */ 505*0Sstevel@tonic-gate mounted(char *name) 506*0Sstevel@tonic-gate { 507*0Sstevel@tonic-gate int found = 0; 508*0Sstevel@tonic-gate struct mnttab mnt; 509*0Sstevel@tonic-gate FILE *mnttab; 510*0Sstevel@tonic-gate struct stat device_stat, mount_stat; 511*0Sstevel@tonic-gate char *blkname, *unrawname(); 512*0Sstevel@tonic-gate int err; 513*0Sstevel@tonic-gate 514*0Sstevel@tonic-gate mnttab = fopen(MNTTAB, "r"); 515*0Sstevel@tonic-gate if (mnttab == NULL) { 516*0Sstevel@tonic-gate (void) printf(gettext("can't open %s\n"), MNTTAB); 517*0Sstevel@tonic-gate return (0); 518*0Sstevel@tonic-gate } 519*0Sstevel@tonic-gate blkname = unrawname(name); 520*0Sstevel@tonic-gate while ((getmntent(mnttab, &mnt)) == NULL) { 521*0Sstevel@tonic-gate if (strcmp(mnt.mnt_fstype, MNTTYPE_UDFS) != 0) { 522*0Sstevel@tonic-gate continue; 523*0Sstevel@tonic-gate } 524*0Sstevel@tonic-gate if (strcmp(blkname, mnt.mnt_special) == 0) { 525*0Sstevel@tonic-gate err = stat(mnt.mnt_mountp, &mount_stat); 526*0Sstevel@tonic-gate err |= stat(mnt.mnt_special, &device_stat); 527*0Sstevel@tonic-gate if (err < 0) 528*0Sstevel@tonic-gate continue; 529*0Sstevel@tonic-gate if (device_stat.st_rdev == mount_stat.st_dev) { 530*0Sstevel@tonic-gate (void) strncpy(mnt.mnt_mountp, mountpoint, 531*0Sstevel@tonic-gate sizeof (mountpoint)); 532*0Sstevel@tonic-gate if (hasmntopt(&mnt, MNTOPT_RO) != 0) 533*0Sstevel@tonic-gate found = 2; /* mounted as RO */ 534*0Sstevel@tonic-gate else 535*0Sstevel@tonic-gate found = 1; /* mounted as R/W */ 536*0Sstevel@tonic-gate } 537*0Sstevel@tonic-gate break; 538*0Sstevel@tonic-gate } 539*0Sstevel@tonic-gate } 540*0Sstevel@tonic-gate (void) fclose(mnttab); 541*0Sstevel@tonic-gate return (found); 542*0Sstevel@tonic-gate } 543*0Sstevel@tonic-gate 544*0Sstevel@tonic-gate /* 545*0Sstevel@tonic-gate * Check to see if name corresponds to an entry in vfstab, and that the entry 546*0Sstevel@tonic-gate * does not have option ro. 547*0Sstevel@tonic-gate */ 548*0Sstevel@tonic-gate writable(char *name) 549*0Sstevel@tonic-gate { 550*0Sstevel@tonic-gate int rw = 1; 551*0Sstevel@tonic-gate struct vfstab vfsbuf; 552*0Sstevel@tonic-gate FILE *vfstab; 553*0Sstevel@tonic-gate char *blkname, *unrawname(); 554*0Sstevel@tonic-gate 555*0Sstevel@tonic-gate vfstab = fopen(VFSTAB, "r"); 556*0Sstevel@tonic-gate if (vfstab == NULL) { 557*0Sstevel@tonic-gate (void) printf(gettext("can't open %s\n"), VFSTAB); 558*0Sstevel@tonic-gate return (1); 559*0Sstevel@tonic-gate } 560*0Sstevel@tonic-gate blkname = unrawname(name); 561*0Sstevel@tonic-gate if ((getvfsspec(vfstab, &vfsbuf, blkname) == 0) && 562*0Sstevel@tonic-gate (vfsbuf.vfs_fstype != NULL) && 563*0Sstevel@tonic-gate (strcmp(vfsbuf.vfs_fstype, MNTTYPE_UDFS) == 0) && 564*0Sstevel@tonic-gate (hasvfsopt(&vfsbuf, MNTOPT_RO))) { 565*0Sstevel@tonic-gate rw = 0; 566*0Sstevel@tonic-gate } 567*0Sstevel@tonic-gate (void) fclose(vfstab); 568*0Sstevel@tonic-gate return (rw); 569*0Sstevel@tonic-gate } 570*0Sstevel@tonic-gate 571*0Sstevel@tonic-gate /* 572*0Sstevel@tonic-gate * print out clean info 573*0Sstevel@tonic-gate */ 574*0Sstevel@tonic-gate void 575*0Sstevel@tonic-gate printclean() 576*0Sstevel@tonic-gate { 577*0Sstevel@tonic-gate char *s; 578*0Sstevel@tonic-gate 579*0Sstevel@tonic-gate switch (lvintp->lvid_int_type) { 580*0Sstevel@tonic-gate 581*0Sstevel@tonic-gate case LVI_CLOSE: 582*0Sstevel@tonic-gate s = gettext("clean"); 583*0Sstevel@tonic-gate break; 584*0Sstevel@tonic-gate 585*0Sstevel@tonic-gate case LVI_OPEN: 586*0Sstevel@tonic-gate s = gettext("active"); 587*0Sstevel@tonic-gate break; 588*0Sstevel@tonic-gate 589*0Sstevel@tonic-gate default: 590*0Sstevel@tonic-gate s = gettext("unknown"); 591*0Sstevel@tonic-gate } 592*0Sstevel@tonic-gate 593*0Sstevel@tonic-gate if (preen) 594*0Sstevel@tonic-gate pwarn(gettext("is %s.\n"), s); 595*0Sstevel@tonic-gate else 596*0Sstevel@tonic-gate (void) printf("** %s is %s.\n", devname, s); 597*0Sstevel@tonic-gate } 598