10Sstevel@tonic-gate /* 2*1053Smaheshvs * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 30Sstevel@tonic-gate * Use is subject to license terms. 40Sstevel@tonic-gate */ 50Sstevel@tonic-gate 60Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 70Sstevel@tonic-gate /* All Rights Reserved */ 80Sstevel@tonic-gate 90Sstevel@tonic-gate /* 100Sstevel@tonic-gate * Copyright (c) 1980, 1986, 1990 The Regents of the University of California. 110Sstevel@tonic-gate * All rights reserved. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted 140Sstevel@tonic-gate * provided that: (1) source distributions retain this entire copyright 150Sstevel@tonic-gate * notice and comment, and (2) distributions including binaries display 160Sstevel@tonic-gate * the following acknowledgement: ``This product includes software 170Sstevel@tonic-gate * developed by the University of California, Berkeley and its contributors'' 180Sstevel@tonic-gate * in the documentation or other materials provided with the distribution 190Sstevel@tonic-gate * and in all advertising materials mentioning features or use of this 200Sstevel@tonic-gate * software. Neither the name of the University nor the names of its 210Sstevel@tonic-gate * contributors may be used to endorse or promote products derived 220Sstevel@tonic-gate * from this software without specific prior written permission. 230Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 240Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 250Sstevel@tonic-gate * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 260Sstevel@tonic-gate */ 270Sstevel@tonic-gate 280Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 290Sstevel@tonic-gate 300Sstevel@tonic-gate #include <stdio.h> 310Sstevel@tonic-gate #include <fcntl.h> 320Sstevel@tonic-gate #include <errno.h> 330Sstevel@tonic-gate #include <unistd.h> 340Sstevel@tonic-gate #include <stdlib.h> 35*1053Smaheshvs #include <stdarg.h> 360Sstevel@tonic-gate #include <fcntl.h> 370Sstevel@tonic-gate #include <string.h> 380Sstevel@tonic-gate #include <strings.h> 390Sstevel@tonic-gate #include <ctype.h> 400Sstevel@tonic-gate #include <malloc.h> 410Sstevel@tonic-gate #include <signal.h> 420Sstevel@tonic-gate #include <sys/param.h> 430Sstevel@tonic-gate #include <sys/types.h> 440Sstevel@tonic-gate #include <sys/mntent.h> 450Sstevel@tonic-gate #include <sys/filio.h> 460Sstevel@tonic-gate #include <sys/vnode.h> 470Sstevel@tonic-gate #include <sys/mnttab.h> 480Sstevel@tonic-gate #include <sys/types.h> 490Sstevel@tonic-gate #include <sys/stat.h> 500Sstevel@tonic-gate #include <sys/vfstab.h> 510Sstevel@tonic-gate #include <sys/sysmacros.h> 520Sstevel@tonic-gate #include <sys/fs/udf_volume.h> 530Sstevel@tonic-gate #include "fsck.h" 540Sstevel@tonic-gate #include <sys/lockfs.h> 550Sstevel@tonic-gate #include <locale.h> 560Sstevel@tonic-gate 570Sstevel@tonic-gate extern int32_t verifytag(struct tag *, uint32_t, struct tag *, int); 580Sstevel@tonic-gate extern char *tagerrs[]; 590Sstevel@tonic-gate extern void maketag(struct tag *, struct tag *); 600Sstevel@tonic-gate extern char *hasvfsopt(struct vfstab *, char *); 610Sstevel@tonic-gate static struct bufarea *getdatablk(daddr_t, long); 620Sstevel@tonic-gate static struct bufarea *getblk(struct bufarea *, daddr_t, long); 630Sstevel@tonic-gate 640Sstevel@tonic-gate void flush(int32_t, struct bufarea *); 650Sstevel@tonic-gate int32_t bread(int32_t, char *, daddr_t, long); 660Sstevel@tonic-gate void bwrite(int, char *, daddr_t, long); 670Sstevel@tonic-gate static int32_t getline(FILE *, char *, int32_t); 68*1053Smaheshvs void errexit(char *, ...) __NORETURN; 690Sstevel@tonic-gate static long diskreads, totalreads; /* Disk cache statistics */ 700Sstevel@tonic-gate offset_t llseek(); 710Sstevel@tonic-gate extern unsigned int largefile_count; 720Sstevel@tonic-gate 730Sstevel@tonic-gate /* 740Sstevel@tonic-gate * An unexpected inconsistency occured. 750Sstevel@tonic-gate * Die if preening, otherwise just print message and continue. 760Sstevel@tonic-gate */ 770Sstevel@tonic-gate /* VARARGS1 */ 780Sstevel@tonic-gate void 79*1053Smaheshvs pfatal(char *fmt, ...) 800Sstevel@tonic-gate { 81*1053Smaheshvs va_list args; 82*1053Smaheshvs va_start(args, fmt); 830Sstevel@tonic-gate if (preen) { 840Sstevel@tonic-gate (void) printf("%s: ", devname); 85*1053Smaheshvs (void) vprintf(fmt, args); 860Sstevel@tonic-gate (void) printf("\n"); 870Sstevel@tonic-gate (void) printf( 880Sstevel@tonic-gate gettext("%s: UNEXPECTED INCONSISTENCY; RUN fsck " 890Sstevel@tonic-gate "MANUALLY.\n"), devname); 90*1053Smaheshvs va_end(args); 910Sstevel@tonic-gate exit(36); 920Sstevel@tonic-gate } 93*1053Smaheshvs (void) vprintf(fmt, args); 94*1053Smaheshvs va_end(args); 950Sstevel@tonic-gate } 960Sstevel@tonic-gate 970Sstevel@tonic-gate /* 980Sstevel@tonic-gate * Pwarn just prints a message when not preening, 990Sstevel@tonic-gate * or a warning (preceded by filename) when preening. 1000Sstevel@tonic-gate */ 1010Sstevel@tonic-gate /* VARARGS1 */ 1020Sstevel@tonic-gate void 103*1053Smaheshvs pwarn(char *fmt, ...) 1040Sstevel@tonic-gate { 105*1053Smaheshvs va_list args; 106*1053Smaheshvs va_start(args, fmt); 1070Sstevel@tonic-gate if (preen) 1080Sstevel@tonic-gate (void) printf("%s: ", devname); 109*1053Smaheshvs (void) vprintf(fmt, args); 110*1053Smaheshvs va_end(args); 1110Sstevel@tonic-gate } 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate /* VARARGS1 */ 1150Sstevel@tonic-gate void 116*1053Smaheshvs errexit(char *fmt, ...) 1170Sstevel@tonic-gate { 118*1053Smaheshvs va_list args; 119*1053Smaheshvs va_start(args, fmt); 120*1053Smaheshvs (void) vprintf(fmt, args); 121*1053Smaheshvs va_end(args); 1220Sstevel@tonic-gate exit(39); 1230Sstevel@tonic-gate } 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate void 1260Sstevel@tonic-gate markbusy(daddr_t block, long count) 1270Sstevel@tonic-gate { 1280Sstevel@tonic-gate register int i; 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate count = roundup(count, secsize) / secsize; 1310Sstevel@tonic-gate for (i = 0; i < count; i++, block++) { 1320Sstevel@tonic-gate if ((unsigned)block > part_len) { 1330Sstevel@tonic-gate pwarn(gettext("Block %lx out of range\n"), block); 1340Sstevel@tonic-gate break; 1350Sstevel@tonic-gate } 1360Sstevel@tonic-gate if (testbusy(block)) 1370Sstevel@tonic-gate pwarn(gettext("Dup block %lx\n"), block); 1380Sstevel@tonic-gate else { 1390Sstevel@tonic-gate n_blks++; 1400Sstevel@tonic-gate setbusy(block); 1410Sstevel@tonic-gate } 1420Sstevel@tonic-gate } 1430Sstevel@tonic-gate } 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate void 1460Sstevel@tonic-gate printfree() 1470Sstevel@tonic-gate { 1480Sstevel@tonic-gate int i, startfree, endfree; 1490Sstevel@tonic-gate 1500Sstevel@tonic-gate startfree = -1; 1510Sstevel@tonic-gate for (i = 0; i < part_len; i++) { 1520Sstevel@tonic-gate if (!testbusy(i)) { 1530Sstevel@tonic-gate if (startfree <= 0) 1540Sstevel@tonic-gate startfree = i; 1550Sstevel@tonic-gate endfree = i; 1560Sstevel@tonic-gate } else if (startfree >= 0) { 1570Sstevel@tonic-gate (void) printf("free: %x-%x\n", startfree, endfree - 1); 1580Sstevel@tonic-gate startfree = -1; 1590Sstevel@tonic-gate } 1600Sstevel@tonic-gate } 1610Sstevel@tonic-gate if (startfree >= 0) { 1620Sstevel@tonic-gate (void) printf("free: %x-%x\n", startfree, endfree); 1630Sstevel@tonic-gate } 1640Sstevel@tonic-gate } 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate struct bufarea * 1670Sstevel@tonic-gate getfilentry(uint32_t block, int len) 1680Sstevel@tonic-gate { 1690Sstevel@tonic-gate struct bufarea *bp; 1700Sstevel@tonic-gate struct file_entry *fp; 1710Sstevel@tonic-gate int err; 1720Sstevel@tonic-gate 1730Sstevel@tonic-gate if (len > fsbsize) { 1740Sstevel@tonic-gate (void) printf(gettext("File entry at %x is too long " 1750Sstevel@tonic-gate "(%d bytes)\n"), block, len); 1760Sstevel@tonic-gate len = fsbsize; 1770Sstevel@tonic-gate } 1780Sstevel@tonic-gate bp = getdatablk((daddr_t)(block + part_start), fsbsize); 1790Sstevel@tonic-gate if (bp->b_errs) { 1800Sstevel@tonic-gate bp->b_flags &= ~B_INUSE; 1810Sstevel@tonic-gate return (NULL); 1820Sstevel@tonic-gate } 1830Sstevel@tonic-gate /* LINTED */ 1840Sstevel@tonic-gate fp = (struct file_entry *)bp->b_un.b_buf; 1850Sstevel@tonic-gate err = verifytag(&fp->fe_tag, block, &fp->fe_tag, UD_FILE_ENTRY); 1860Sstevel@tonic-gate if (err) { 1870Sstevel@tonic-gate (void) printf(gettext("Tag error %s or bad file entry, " 1880Sstevel@tonic-gate "tag=%d\n"), tagerrs[err], fp->fe_tag.tag_id); 1890Sstevel@tonic-gate bp->b_flags &= ~B_INUSE; 1900Sstevel@tonic-gate return (NULL); 1910Sstevel@tonic-gate } 1920Sstevel@tonic-gate return (bp); 1930Sstevel@tonic-gate } 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate void 1960Sstevel@tonic-gate putfilentry(struct bufarea *bp) 1970Sstevel@tonic-gate { 1980Sstevel@tonic-gate struct file_entry *fp; 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate /* LINTED */ 2010Sstevel@tonic-gate fp = (struct file_entry *)bp->b_un.b_buf; 2020Sstevel@tonic-gate maketag(&fp->fe_tag, &fp->fe_tag); 2030Sstevel@tonic-gate } 2040Sstevel@tonic-gate 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate int32_t 2070Sstevel@tonic-gate reply(char *question) 2080Sstevel@tonic-gate { 2090Sstevel@tonic-gate char line[80]; 2100Sstevel@tonic-gate 2110Sstevel@tonic-gate if (preen) 2120Sstevel@tonic-gate pfatal(gettext("INTERNAL ERROR: GOT TO reply()")); 2130Sstevel@tonic-gate (void) printf("\n%s? ", question); 2140Sstevel@tonic-gate if (nflag || fswritefd < 0) { 2150Sstevel@tonic-gate (void) printf(gettext(" no\n\n")); 2160Sstevel@tonic-gate iscorrupt = 1; /* known to be corrupt */ 2170Sstevel@tonic-gate return (0); 2180Sstevel@tonic-gate } 2190Sstevel@tonic-gate if (yflag) { 2200Sstevel@tonic-gate (void) printf(gettext(" yes\n\n")); 2210Sstevel@tonic-gate return (1); 2220Sstevel@tonic-gate } 2230Sstevel@tonic-gate if (getline(stdin, line, sizeof (line)) == EOF) 2240Sstevel@tonic-gate errexit("\n"); 2250Sstevel@tonic-gate (void) printf("\n"); 2260Sstevel@tonic-gate if (line[0] == 'y' || line[0] == 'Y') 2270Sstevel@tonic-gate return (1); 2280Sstevel@tonic-gate else { 2290Sstevel@tonic-gate iscorrupt = 1; /* known to be corrupt */ 2300Sstevel@tonic-gate return (0); 2310Sstevel@tonic-gate } 2320Sstevel@tonic-gate } 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate int32_t 2350Sstevel@tonic-gate getline(FILE *fp, char *loc, int32_t maxlen) 2360Sstevel@tonic-gate { 237*1053Smaheshvs int n; 2380Sstevel@tonic-gate register char *p, *lastloc; 2390Sstevel@tonic-gate 2400Sstevel@tonic-gate p = loc; 2410Sstevel@tonic-gate lastloc = &p[maxlen-1]; 2420Sstevel@tonic-gate while ((n = getc(fp)) != '\n') { 2430Sstevel@tonic-gate if (n == EOF) 2440Sstevel@tonic-gate return (EOF); 2450Sstevel@tonic-gate if (!isspace(n) && p < lastloc) 2460Sstevel@tonic-gate *p++ = n; 2470Sstevel@tonic-gate } 2480Sstevel@tonic-gate *p = 0; 2490Sstevel@tonic-gate return (p - loc); 2500Sstevel@tonic-gate } 2510Sstevel@tonic-gate /* 2520Sstevel@tonic-gate * Malloc buffers and set up cache. 2530Sstevel@tonic-gate */ 2540Sstevel@tonic-gate void 2550Sstevel@tonic-gate bufinit() 2560Sstevel@tonic-gate { 2570Sstevel@tonic-gate register struct bufarea *bp; 2580Sstevel@tonic-gate long bufcnt, i; 2590Sstevel@tonic-gate char *bufp; 2600Sstevel@tonic-gate 2610Sstevel@tonic-gate bufp = malloc((unsigned int)fsbsize); 2620Sstevel@tonic-gate if (bufp == 0) 2630Sstevel@tonic-gate errexit(gettext("cannot allocate buffer pool\n")); 2640Sstevel@tonic-gate bufhead.b_next = bufhead.b_prev = &bufhead; 2650Sstevel@tonic-gate bufcnt = MAXBUFSPACE / fsbsize; 2660Sstevel@tonic-gate if (bufcnt < MINBUFS) 2670Sstevel@tonic-gate bufcnt = MINBUFS; 2680Sstevel@tonic-gate for (i = 0; i < bufcnt; i++) { 2690Sstevel@tonic-gate bp = (struct bufarea *)malloc(sizeof (struct bufarea)); 2700Sstevel@tonic-gate bufp = malloc((unsigned int)fsbsize); 2710Sstevel@tonic-gate if (bp == NULL || bufp == NULL) { 2720Sstevel@tonic-gate if (i >= MINBUFS) 2730Sstevel@tonic-gate break; 2740Sstevel@tonic-gate errexit(gettext("cannot allocate buffer pool\n")); 2750Sstevel@tonic-gate } 2760Sstevel@tonic-gate bp->b_un.b_buf = bufp; 2770Sstevel@tonic-gate bp->b_prev = &bufhead; 2780Sstevel@tonic-gate bp->b_next = bufhead.b_next; 2790Sstevel@tonic-gate bufhead.b_next->b_prev = bp; 2800Sstevel@tonic-gate bufhead.b_next = bp; 2810Sstevel@tonic-gate initbarea(bp); 2820Sstevel@tonic-gate } 2830Sstevel@tonic-gate bufhead.b_size = i; /* save number of buffers */ 2840Sstevel@tonic-gate pbp = pdirbp = NULL; 2850Sstevel@tonic-gate } 2860Sstevel@tonic-gate 2870Sstevel@tonic-gate /* 2880Sstevel@tonic-gate * Manage a cache of directory blocks. 2890Sstevel@tonic-gate */ 2900Sstevel@tonic-gate static struct bufarea * 2910Sstevel@tonic-gate getdatablk(daddr_t blkno, long size) 2920Sstevel@tonic-gate { 2930Sstevel@tonic-gate register struct bufarea *bp; 2940Sstevel@tonic-gate 2950Sstevel@tonic-gate for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next) 2960Sstevel@tonic-gate if (bp->b_bno == fsbtodb(blkno)) 2970Sstevel@tonic-gate goto foundit; 2980Sstevel@tonic-gate for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev) 2990Sstevel@tonic-gate if ((bp->b_flags & B_INUSE) == 0) 3000Sstevel@tonic-gate break; 3010Sstevel@tonic-gate if (bp == &bufhead) 3020Sstevel@tonic-gate errexit(gettext("deadlocked buffer pool\n")); 3030Sstevel@tonic-gate (void) getblk(bp, blkno, size); 3040Sstevel@tonic-gate /* fall through */ 3050Sstevel@tonic-gate foundit: 3060Sstevel@tonic-gate totalreads++; 3070Sstevel@tonic-gate bp->b_prev->b_next = bp->b_next; 3080Sstevel@tonic-gate bp->b_next->b_prev = bp->b_prev; 3090Sstevel@tonic-gate bp->b_prev = &bufhead; 3100Sstevel@tonic-gate bp->b_next = bufhead.b_next; 3110Sstevel@tonic-gate bufhead.b_next->b_prev = bp; 3120Sstevel@tonic-gate bufhead.b_next = bp; 3130Sstevel@tonic-gate bp->b_flags |= B_INUSE; 3140Sstevel@tonic-gate return (bp); 3150Sstevel@tonic-gate } 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate static struct bufarea * 3180Sstevel@tonic-gate getblk(struct bufarea *bp, daddr_t blk, long size) 3190Sstevel@tonic-gate { 3200Sstevel@tonic-gate daddr_t dblk; 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate dblk = fsbtodb(blk); 3230Sstevel@tonic-gate if (bp->b_bno == dblk) 3240Sstevel@tonic-gate return (bp); 3250Sstevel@tonic-gate flush(fswritefd, bp); 3260Sstevel@tonic-gate diskreads++; 3270Sstevel@tonic-gate bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size); 3280Sstevel@tonic-gate bp->b_bno = dblk; 3290Sstevel@tonic-gate bp->b_size = size; 3300Sstevel@tonic-gate return (bp); 3310Sstevel@tonic-gate } 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate void 3340Sstevel@tonic-gate flush(int32_t fd, struct bufarea *bp) 3350Sstevel@tonic-gate { 3360Sstevel@tonic-gate if (!bp->b_dirty) 3370Sstevel@tonic-gate return; 3380Sstevel@tonic-gate if (bp->b_errs != 0) 3390Sstevel@tonic-gate pfatal(gettext("WRITING ZERO'ED BLOCK %d TO DISK\n"), 3400Sstevel@tonic-gate bp->b_bno); 3410Sstevel@tonic-gate bp->b_dirty = 0; 3420Sstevel@tonic-gate bp->b_errs = 0; 3430Sstevel@tonic-gate bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); 3440Sstevel@tonic-gate } 3450Sstevel@tonic-gate 3460Sstevel@tonic-gate static void 3470Sstevel@tonic-gate rwerror(char *mesg, daddr_t blk) 3480Sstevel@tonic-gate { 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate if (preen == 0) 3510Sstevel@tonic-gate (void) printf("\n"); 3520Sstevel@tonic-gate pfatal(gettext("CANNOT %s: BLK %ld"), mesg, blk); 3530Sstevel@tonic-gate if (reply(gettext("CONTINUE")) == 0) 3540Sstevel@tonic-gate errexit(gettext("Program terminated\n")); 3550Sstevel@tonic-gate } 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate void 3580Sstevel@tonic-gate ckfini() 3590Sstevel@tonic-gate { 3600Sstevel@tonic-gate struct bufarea *bp, *nbp; 3610Sstevel@tonic-gate int cnt = 0; 3620Sstevel@tonic-gate 3630Sstevel@tonic-gate for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) { 3640Sstevel@tonic-gate cnt++; 3650Sstevel@tonic-gate flush(fswritefd, bp); 3660Sstevel@tonic-gate nbp = bp->b_prev; 3670Sstevel@tonic-gate free(bp->b_un.b_buf); 3680Sstevel@tonic-gate free((char *)bp); 3690Sstevel@tonic-gate } 3700Sstevel@tonic-gate pbp = pdirbp = NULL; 3710Sstevel@tonic-gate if (bufhead.b_size != cnt) 3720Sstevel@tonic-gate errexit(gettext("Panic: lost %d buffers\n"), 3730Sstevel@tonic-gate bufhead.b_size - cnt); 3740Sstevel@tonic-gate if (debug) 3750Sstevel@tonic-gate (void) printf("cache missed %ld of %ld (%ld%%)\n", 3760Sstevel@tonic-gate diskreads, totalreads, 3770Sstevel@tonic-gate totalreads ? diskreads * 100 / totalreads : 0); 3780Sstevel@tonic-gate (void) close(fsreadfd); 3790Sstevel@tonic-gate (void) close(fswritefd); 3800Sstevel@tonic-gate } 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate int32_t 3830Sstevel@tonic-gate bread(int fd, char *buf, daddr_t blk, long size) 3840Sstevel@tonic-gate { 3850Sstevel@tonic-gate char *cp; 3860Sstevel@tonic-gate int i, errs; 3870Sstevel@tonic-gate offset_t offset = ldbtob(blk); 3880Sstevel@tonic-gate offset_t addr; 3890Sstevel@tonic-gate 3900Sstevel@tonic-gate if (llseek(fd, offset, 0) < 0) 3910Sstevel@tonic-gate rwerror(gettext("SEEK"), blk); 3920Sstevel@tonic-gate else if (read(fd, buf, (int)size) == size) 3930Sstevel@tonic-gate return (0); 3940Sstevel@tonic-gate rwerror(gettext("READ"), blk); 3950Sstevel@tonic-gate if (llseek(fd, offset, 0) < 0) 3960Sstevel@tonic-gate rwerror(gettext("SEEK"), blk); 3970Sstevel@tonic-gate errs = 0; 3980Sstevel@tonic-gate bzero(buf, (int)size); 3990Sstevel@tonic-gate pwarn(gettext("THE FOLLOWING SECTORS COULD NOT BE READ:")); 4000Sstevel@tonic-gate for (cp = buf, i = 0; i < btodb(size); i++, cp += DEV_BSIZE) { 4010Sstevel@tonic-gate addr = ldbtob(blk + i); 4020Sstevel@tonic-gate if (llseek(fd, addr, SEEK_CUR) < 0 || 4030Sstevel@tonic-gate read(fd, cp, (int)secsize) < 0) { 4040Sstevel@tonic-gate (void) printf(" %ld", blk + i); 4050Sstevel@tonic-gate errs++; 4060Sstevel@tonic-gate } 4070Sstevel@tonic-gate } 4080Sstevel@tonic-gate (void) printf("\n"); 4090Sstevel@tonic-gate return (errs); 4100Sstevel@tonic-gate } 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate void 4130Sstevel@tonic-gate bwrite(int fd, char *buf, daddr_t blk, long size) 4140Sstevel@tonic-gate { 4150Sstevel@tonic-gate int i, n; 4160Sstevel@tonic-gate char *cp; 4170Sstevel@tonic-gate offset_t offset = ldbtob(blk); 4180Sstevel@tonic-gate offset_t addr; 4190Sstevel@tonic-gate 4200Sstevel@tonic-gate if (fd < 0) 4210Sstevel@tonic-gate return; 4220Sstevel@tonic-gate if (llseek(fd, offset, 0) < 0) 4230Sstevel@tonic-gate rwerror(gettext("SEEK"), blk); 4240Sstevel@tonic-gate else if (write(fd, buf, (int)size) == size) { 4250Sstevel@tonic-gate fsmodified = 1; 4260Sstevel@tonic-gate return; 4270Sstevel@tonic-gate } 4280Sstevel@tonic-gate rwerror(gettext("WRITE"), blk); 4290Sstevel@tonic-gate if (llseek(fd, offset, 0) < 0) 4300Sstevel@tonic-gate rwerror(gettext("SEEK"), blk); 4310Sstevel@tonic-gate pwarn(gettext("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:")); 4320Sstevel@tonic-gate for (cp = buf, i = 0; i < btodb(size); i++, cp += DEV_BSIZE) { 4330Sstevel@tonic-gate n = 0; 4340Sstevel@tonic-gate addr = ldbtob(blk + i); 4350Sstevel@tonic-gate if (llseek(fd, addr, SEEK_CUR) < 0 || 4360Sstevel@tonic-gate (n = write(fd, cp, DEV_BSIZE)) < 0) { 4370Sstevel@tonic-gate (void) printf(" %ld", blk + i); 4380Sstevel@tonic-gate } else if (n > 0) { 4390Sstevel@tonic-gate fsmodified = 1; 4400Sstevel@tonic-gate } 4410Sstevel@tonic-gate 4420Sstevel@tonic-gate } 4430Sstevel@tonic-gate (void) printf("\n"); 4440Sstevel@tonic-gate } 4450Sstevel@tonic-gate 4460Sstevel@tonic-gate void 4470Sstevel@tonic-gate catch() 4480Sstevel@tonic-gate { 4490Sstevel@tonic-gate ckfini(); 4500Sstevel@tonic-gate exit(37); 4510Sstevel@tonic-gate } 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate /* 4540Sstevel@tonic-gate * When preening, allow a single quit to signal 4550Sstevel@tonic-gate * a special exit after filesystem checks complete 4560Sstevel@tonic-gate * so that reboot sequence may be interrupted. 4570Sstevel@tonic-gate */ 4580Sstevel@tonic-gate void 4590Sstevel@tonic-gate catchquit() 4600Sstevel@tonic-gate { 461*1053Smaheshvs extern int returntosingle; 4620Sstevel@tonic-gate 4630Sstevel@tonic-gate (void) printf(gettext("returning to single-user after filesystem " 4640Sstevel@tonic-gate "check\n")); 4650Sstevel@tonic-gate returntosingle = 1; 4660Sstevel@tonic-gate (void) signal(SIGQUIT, SIG_DFL); 4670Sstevel@tonic-gate } 4680Sstevel@tonic-gate 4690Sstevel@tonic-gate /* 4700Sstevel@tonic-gate * determine whether an inode should be fixed. 4710Sstevel@tonic-gate */ 4720Sstevel@tonic-gate /* ARGSUSED1 */ 4730Sstevel@tonic-gate int32_t 4740Sstevel@tonic-gate dofix(struct inodesc *idesc, char *msg) 4750Sstevel@tonic-gate { 4760Sstevel@tonic-gate 4770Sstevel@tonic-gate switch (idesc->id_fix) { 4780Sstevel@tonic-gate 4790Sstevel@tonic-gate case DONTKNOW: 4800Sstevel@tonic-gate pwarn(msg); 4810Sstevel@tonic-gate if (preen) { 4820Sstevel@tonic-gate (void) printf(gettext(" (SALVAGED)\n")); 4830Sstevel@tonic-gate idesc->id_fix = FIX; 4840Sstevel@tonic-gate return (ALTERED); 4850Sstevel@tonic-gate } 4860Sstevel@tonic-gate if (reply(gettext("SALVAGE")) == 0) { 4870Sstevel@tonic-gate idesc->id_fix = NOFIX; 4880Sstevel@tonic-gate return (0); 4890Sstevel@tonic-gate } 4900Sstevel@tonic-gate idesc->id_fix = FIX; 4910Sstevel@tonic-gate return (ALTERED); 4920Sstevel@tonic-gate 4930Sstevel@tonic-gate case FIX: 4940Sstevel@tonic-gate return (ALTERED); 4950Sstevel@tonic-gate 4960Sstevel@tonic-gate case NOFIX: 4970Sstevel@tonic-gate return (0); 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate default: 5000Sstevel@tonic-gate errexit(gettext("UNKNOWN INODESC FIX MODE %d\n"), 5010Sstevel@tonic-gate idesc->id_fix); 5020Sstevel@tonic-gate } 5030Sstevel@tonic-gate /* NOTREACHED */ 5040Sstevel@tonic-gate } 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate /* 5070Sstevel@tonic-gate * Check to see if unraw version of name is already mounted. 5080Sstevel@tonic-gate * Since we do not believe /etc/mnttab, we stat the mount point 5090Sstevel@tonic-gate * to see if it is really looks mounted. 5100Sstevel@tonic-gate */ 511*1053Smaheshvs int 5120Sstevel@tonic-gate mounted(char *name) 5130Sstevel@tonic-gate { 5140Sstevel@tonic-gate int found = 0; 5150Sstevel@tonic-gate struct mnttab mnt; 5160Sstevel@tonic-gate FILE *mnttab; 5170Sstevel@tonic-gate struct stat device_stat, mount_stat; 5180Sstevel@tonic-gate char *blkname, *unrawname(); 5190Sstevel@tonic-gate int err; 5200Sstevel@tonic-gate 5210Sstevel@tonic-gate mnttab = fopen(MNTTAB, "r"); 5220Sstevel@tonic-gate if (mnttab == NULL) { 5230Sstevel@tonic-gate (void) printf(gettext("can't open %s\n"), MNTTAB); 5240Sstevel@tonic-gate return (0); 5250Sstevel@tonic-gate } 5260Sstevel@tonic-gate blkname = unrawname(name); 5270Sstevel@tonic-gate while ((getmntent(mnttab, &mnt)) == NULL) { 5280Sstevel@tonic-gate if (strcmp(mnt.mnt_fstype, MNTTYPE_UDFS) != 0) { 5290Sstevel@tonic-gate continue; 5300Sstevel@tonic-gate } 5310Sstevel@tonic-gate if (strcmp(blkname, mnt.mnt_special) == 0) { 5320Sstevel@tonic-gate err = stat(mnt.mnt_mountp, &mount_stat); 5330Sstevel@tonic-gate err |= stat(mnt.mnt_special, &device_stat); 5340Sstevel@tonic-gate if (err < 0) 5350Sstevel@tonic-gate continue; 5360Sstevel@tonic-gate if (device_stat.st_rdev == mount_stat.st_dev) { 5370Sstevel@tonic-gate (void) strncpy(mnt.mnt_mountp, mountpoint, 5380Sstevel@tonic-gate sizeof (mountpoint)); 5390Sstevel@tonic-gate if (hasmntopt(&mnt, MNTOPT_RO) != 0) 5400Sstevel@tonic-gate found = 2; /* mounted as RO */ 5410Sstevel@tonic-gate else 5420Sstevel@tonic-gate found = 1; /* mounted as R/W */ 5430Sstevel@tonic-gate } 5440Sstevel@tonic-gate break; 5450Sstevel@tonic-gate } 5460Sstevel@tonic-gate } 5470Sstevel@tonic-gate (void) fclose(mnttab); 5480Sstevel@tonic-gate return (found); 5490Sstevel@tonic-gate } 5500Sstevel@tonic-gate 5510Sstevel@tonic-gate /* 5520Sstevel@tonic-gate * Check to see if name corresponds to an entry in vfstab, and that the entry 5530Sstevel@tonic-gate * does not have option ro. 5540Sstevel@tonic-gate */ 555*1053Smaheshvs int 5560Sstevel@tonic-gate writable(char *name) 5570Sstevel@tonic-gate { 5580Sstevel@tonic-gate int rw = 1; 5590Sstevel@tonic-gate struct vfstab vfsbuf; 5600Sstevel@tonic-gate FILE *vfstab; 5610Sstevel@tonic-gate char *blkname, *unrawname(); 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate vfstab = fopen(VFSTAB, "r"); 5640Sstevel@tonic-gate if (vfstab == NULL) { 5650Sstevel@tonic-gate (void) printf(gettext("can't open %s\n"), VFSTAB); 5660Sstevel@tonic-gate return (1); 5670Sstevel@tonic-gate } 5680Sstevel@tonic-gate blkname = unrawname(name); 5690Sstevel@tonic-gate if ((getvfsspec(vfstab, &vfsbuf, blkname) == 0) && 5700Sstevel@tonic-gate (vfsbuf.vfs_fstype != NULL) && 5710Sstevel@tonic-gate (strcmp(vfsbuf.vfs_fstype, MNTTYPE_UDFS) == 0) && 5720Sstevel@tonic-gate (hasvfsopt(&vfsbuf, MNTOPT_RO))) { 5730Sstevel@tonic-gate rw = 0; 5740Sstevel@tonic-gate } 5750Sstevel@tonic-gate (void) fclose(vfstab); 5760Sstevel@tonic-gate return (rw); 5770Sstevel@tonic-gate } 5780Sstevel@tonic-gate 5790Sstevel@tonic-gate /* 5800Sstevel@tonic-gate * print out clean info 5810Sstevel@tonic-gate */ 5820Sstevel@tonic-gate void 5830Sstevel@tonic-gate printclean() 5840Sstevel@tonic-gate { 5850Sstevel@tonic-gate char *s; 5860Sstevel@tonic-gate 5870Sstevel@tonic-gate switch (lvintp->lvid_int_type) { 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate case LVI_CLOSE: 5900Sstevel@tonic-gate s = gettext("clean"); 5910Sstevel@tonic-gate break; 5920Sstevel@tonic-gate 5930Sstevel@tonic-gate case LVI_OPEN: 5940Sstevel@tonic-gate s = gettext("active"); 5950Sstevel@tonic-gate break; 5960Sstevel@tonic-gate 5970Sstevel@tonic-gate default: 5980Sstevel@tonic-gate s = gettext("unknown"); 5990Sstevel@tonic-gate } 6000Sstevel@tonic-gate 6010Sstevel@tonic-gate if (preen) 6020Sstevel@tonic-gate pwarn(gettext("is %s.\n"), s); 6030Sstevel@tonic-gate else 6040Sstevel@tonic-gate (void) printf("** %s is %s.\n", devname, s); 6050Sstevel@tonic-gate } 606