17c478bd9Sstevel@tonic-gate /* 2*355d6bb5Sswilcox * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 37c478bd9Sstevel@tonic-gate * Use is subject to license terms. 47c478bd9Sstevel@tonic-gate */ 57c478bd9Sstevel@tonic-gate 67c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 77c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 87c478bd9Sstevel@tonic-gate 97c478bd9Sstevel@tonic-gate /* 107c478bd9Sstevel@tonic-gate * Copyright (c) 1980, 1986, 1990 The Regents of the University of California. 117c478bd9Sstevel@tonic-gate * All rights reserved. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted 147c478bd9Sstevel@tonic-gate * provided that: (1) source distributions retain this entire copyright 157c478bd9Sstevel@tonic-gate * notice and comment, and (2) distributions including binaries display 167c478bd9Sstevel@tonic-gate * the following acknowledgement: ``This product includes software 177c478bd9Sstevel@tonic-gate * developed by the University of California, Berkeley and its contributors'' 187c478bd9Sstevel@tonic-gate * in the documentation or other materials provided with the distribution 197c478bd9Sstevel@tonic-gate * and in all advertising materials mentioning features or use of this 207c478bd9Sstevel@tonic-gate * software. Neither the name of the University nor the names of its 217c478bd9Sstevel@tonic-gate * contributors may be used to endorse or promote products derived 227c478bd9Sstevel@tonic-gate * from this software without specific prior written permission. 237c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 247c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 257c478bd9Sstevel@tonic-gate * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <stdio.h> 31*355d6bb5Sswilcox #include <stdlib.h> 32*355d6bb5Sswilcox #include <unistd.h> 33*355d6bb5Sswilcox #include <stdarg.h> 34*355d6bb5Sswilcox #include <libadm.h> 35*355d6bb5Sswilcox #include <note.h> 367c478bd9Sstevel@tonic-gate #include <sys/param.h> 377c478bd9Sstevel@tonic-gate #include <sys/types.h> 387c478bd9Sstevel@tonic-gate #include <sys/mntent.h> 397c478bd9Sstevel@tonic-gate #include <sys/filio.h> 407c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fs.h> 417c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 427c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_acl.h> 43*355d6bb5Sswilcox #include <sys/fs/ufs_inode.h> 44*355d6bb5Sswilcox #include <sys/fs/ufs_log.h> 457c478bd9Sstevel@tonic-gate #define _KERNEL 467c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fsdir.h> 477c478bd9Sstevel@tonic-gate #undef _KERNEL 487c478bd9Sstevel@tonic-gate #include <sys/mnttab.h> 497c478bd9Sstevel@tonic-gate #include <sys/types.h> 507c478bd9Sstevel@tonic-gate #include <sys/stat.h> 51*355d6bb5Sswilcox #include <fcntl.h> 52*355d6bb5Sswilcox #include <signal.h> 537c478bd9Sstevel@tonic-gate #include <string.h> 547c478bd9Sstevel@tonic-gate #include <ctype.h> 557c478bd9Sstevel@tonic-gate #include <sys/vfstab.h> 567c478bd9Sstevel@tonic-gate #include <sys/lockfs.h> 577c478bd9Sstevel@tonic-gate #include <errno.h> 58*355d6bb5Sswilcox #include <sys/cmn_err.h> 59*355d6bb5Sswilcox #include <sys/dkio.h> 60*355d6bb5Sswilcox #include <sys/vtoc.h> 61*355d6bb5Sswilcox #include <sys/efi_partition.h> 62*355d6bb5Sswilcox #include <fslib.h> 63*355d6bb5Sswilcox #include <inttypes.h> 64*355d6bb5Sswilcox #include "fsck.h" 657c478bd9Sstevel@tonic-gate 66*355d6bb5Sswilcox caddr_t mount_point = NULL; 67*355d6bb5Sswilcox 68*355d6bb5Sswilcox static int64_t diskreads, totalreads; /* Disk cache statistics */ 69*355d6bb5Sswilcox 70*355d6bb5Sswilcox static int log_checksum(int32_t *, int32_t *, int); 71*355d6bb5Sswilcox static void vdirerror(fsck_ino_t, caddr_t, va_list); 72*355d6bb5Sswilcox static struct mnttab *search_mnttab(caddr_t, caddr_t, caddr_t, size_t); 73*355d6bb5Sswilcox static struct vfstab *search_vfstab(caddr_t, caddr_t, caddr_t, size_t); 74*355d6bb5Sswilcox static void vpwarn(caddr_t, va_list); 75*355d6bb5Sswilcox static int getline(FILE *, caddr_t, int); 76*355d6bb5Sswilcox static struct bufarea *alloc_bufarea(void); 77*355d6bb5Sswilcox static void rwerror(caddr_t, diskaddr_t, int rval); 78*355d6bb5Sswilcox static void debugclean(void); 79*355d6bb5Sswilcox static void report_io_prob(caddr_t, diskaddr_t, size_t, ssize_t); 80*355d6bb5Sswilcox static void freelogblk(daddr32_t); 81*355d6bb5Sswilcox static void verrexit(caddr_t, va_list); 82*355d6bb5Sswilcox static void vpfatal(caddr_t, va_list); 83*355d6bb5Sswilcox static diskaddr_t get_device_size(int, caddr_t); 84*355d6bb5Sswilcox static diskaddr_t brute_force_get_device_size(int); 85*355d6bb5Sswilcox static void cg_constants(int, daddr32_t *, daddr32_t *, daddr32_t *, 86*355d6bb5Sswilcox daddr32_t *, daddr32_t *, daddr32_t *); 877c478bd9Sstevel@tonic-gate 88*355d6bb5Sswilcox int 89*355d6bb5Sswilcox ftypeok(struct dinode *dp) 907c478bd9Sstevel@tonic-gate { 917c478bd9Sstevel@tonic-gate switch (dp->di_mode & IFMT) { 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate case IFDIR: 947c478bd9Sstevel@tonic-gate case IFREG: 957c478bd9Sstevel@tonic-gate case IFBLK: 967c478bd9Sstevel@tonic-gate case IFCHR: 977c478bd9Sstevel@tonic-gate case IFLNK: 987c478bd9Sstevel@tonic-gate case IFSOCK: 997c478bd9Sstevel@tonic-gate case IFIFO: 1007c478bd9Sstevel@tonic-gate case IFSHAD: 1017c478bd9Sstevel@tonic-gate case IFATTRDIR: 1027c478bd9Sstevel@tonic-gate return (1); 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate default: 1057c478bd9Sstevel@tonic-gate if (debug) 106*355d6bb5Sswilcox (void) printf("bad file type 0%o\n", dp->di_mode); 1077c478bd9Sstevel@tonic-gate return (0); 1087c478bd9Sstevel@tonic-gate } 1097c478bd9Sstevel@tonic-gate } 1107c478bd9Sstevel@tonic-gate 111*355d6bb5Sswilcox int 112*355d6bb5Sswilcox acltypeok(struct dinode *dp) 1137c478bd9Sstevel@tonic-gate { 1147c478bd9Sstevel@tonic-gate if (CHECK_ACL_ALLOWED(dp->di_mode & IFMT)) 1157c478bd9Sstevel@tonic-gate return (1); 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate if (debug) 118*355d6bb5Sswilcox (void) printf("bad file type for acl I=%d: 0%o\n", 119*355d6bb5Sswilcox dp->di_shadow, dp->di_mode); 1207c478bd9Sstevel@tonic-gate return (0); 1217c478bd9Sstevel@tonic-gate } 1227c478bd9Sstevel@tonic-gate 123*355d6bb5Sswilcox NOTE(PRINTFLIKE(1)) 124*355d6bb5Sswilcox int 125*355d6bb5Sswilcox reply(caddr_t fmt, ...) 1267c478bd9Sstevel@tonic-gate { 127*355d6bb5Sswilcox va_list ap; 1287c478bd9Sstevel@tonic-gate char line[80]; 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate if (preen) 131*355d6bb5Sswilcox pfatal("INTERNAL ERROR: GOT TO reply() in preen mode"); 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate if (mflag) { 134*355d6bb5Sswilcox /* 135*355d6bb5Sswilcox * We don't know what's going on, so don't potentially 136*355d6bb5Sswilcox * make things worse by having errexit() write stuff 137*355d6bb5Sswilcox * out to disk. 138*355d6bb5Sswilcox */ 139*355d6bb5Sswilcox (void) printf( 140*355d6bb5Sswilcox "\n%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", 141*355d6bb5Sswilcox devname); 142*355d6bb5Sswilcox exit(EXERRFATAL); 1437c478bd9Sstevel@tonic-gate } 1447c478bd9Sstevel@tonic-gate 145*355d6bb5Sswilcox va_start(ap, fmt); 146*355d6bb5Sswilcox (void) putchar('\n'); 147*355d6bb5Sswilcox (void) vprintf(fmt, ap); 148*355d6bb5Sswilcox (void) putchar('?'); 149*355d6bb5Sswilcox (void) putchar(' '); 150*355d6bb5Sswilcox va_end(ap); 151*355d6bb5Sswilcox 1527c478bd9Sstevel@tonic-gate if (nflag || fswritefd < 0) { 153*355d6bb5Sswilcox (void) printf(" no\n\n"); 1547c478bd9Sstevel@tonic-gate return (0); 1557c478bd9Sstevel@tonic-gate } 1567c478bd9Sstevel@tonic-gate if (yflag) { 157*355d6bb5Sswilcox (void) printf(" yes\n\n"); 1587c478bd9Sstevel@tonic-gate return (1); 1597c478bd9Sstevel@tonic-gate } 160*355d6bb5Sswilcox (void) fflush(stdout); 1617c478bd9Sstevel@tonic-gate if (getline(stdin, line, sizeof (line)) == EOF) 1627c478bd9Sstevel@tonic-gate errexit("\n"); 163*355d6bb5Sswilcox (void) printf("\n"); 164*355d6bb5Sswilcox if (line[0] == 'y' || line[0] == 'Y') { 1657c478bd9Sstevel@tonic-gate return (1); 166*355d6bb5Sswilcox } else { 1677c478bd9Sstevel@tonic-gate return (0); 1687c478bd9Sstevel@tonic-gate } 1697c478bd9Sstevel@tonic-gate } 1707c478bd9Sstevel@tonic-gate 171*355d6bb5Sswilcox int 172*355d6bb5Sswilcox getline(FILE *fp, caddr_t loc, int maxlen) 1737c478bd9Sstevel@tonic-gate { 1747c478bd9Sstevel@tonic-gate int n; 175*355d6bb5Sswilcox caddr_t p, lastloc; 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate p = loc; 1787c478bd9Sstevel@tonic-gate lastloc = &p[maxlen-1]; 1797c478bd9Sstevel@tonic-gate while ((n = getc(fp)) != '\n') { 1807c478bd9Sstevel@tonic-gate if (n == EOF) 1817c478bd9Sstevel@tonic-gate return (EOF); 1827c478bd9Sstevel@tonic-gate if (!isspace(n) && p < lastloc) 183*355d6bb5Sswilcox *p++ = (char)n; 1847c478bd9Sstevel@tonic-gate } 185*355d6bb5Sswilcox *p = '\0'; 186*355d6bb5Sswilcox /* LINTED pointer difference won't overflow */ 1877c478bd9Sstevel@tonic-gate return (p - loc); 1887c478bd9Sstevel@tonic-gate } 189*355d6bb5Sswilcox 1907c478bd9Sstevel@tonic-gate /* 1917c478bd9Sstevel@tonic-gate * Malloc buffers and set up cache. 1927c478bd9Sstevel@tonic-gate */ 193*355d6bb5Sswilcox void 194*355d6bb5Sswilcox bufinit(void) 1957c478bd9Sstevel@tonic-gate { 1967c478bd9Sstevel@tonic-gate struct bufarea *bp; 1977c478bd9Sstevel@tonic-gate int bufcnt, i; 198*355d6bb5Sswilcox caddr_t bufp; 1997c478bd9Sstevel@tonic-gate 200*355d6bb5Sswilcox bufp = malloc((size_t)sblock.fs_bsize); 201*355d6bb5Sswilcox if (bufp == NULL) 202*355d6bb5Sswilcox goto nomem; 2037c478bd9Sstevel@tonic-gate initbarea(&cgblk); 204*355d6bb5Sswilcox cgblk.b_un.b_buf = bufp; 2057c478bd9Sstevel@tonic-gate bufhead.b_next = bufhead.b_prev = &bufhead; 2067c478bd9Sstevel@tonic-gate bufcnt = MAXBUFSPACE / sblock.fs_bsize; 2077c478bd9Sstevel@tonic-gate if (bufcnt < MINBUFS) 2087c478bd9Sstevel@tonic-gate bufcnt = MINBUFS; 2097c478bd9Sstevel@tonic-gate for (i = 0; i < bufcnt; i++) { 2107c478bd9Sstevel@tonic-gate bp = (struct bufarea *)malloc(sizeof (struct bufarea)); 211*355d6bb5Sswilcox if (bp == NULL) { 2127c478bd9Sstevel@tonic-gate if (i >= MINBUFS) 213*355d6bb5Sswilcox goto noalloc; 214*355d6bb5Sswilcox goto nomem; 215*355d6bb5Sswilcox } 216*355d6bb5Sswilcox 217*355d6bb5Sswilcox bufp = malloc((size_t)sblock.fs_bsize); 218*355d6bb5Sswilcox if (bufp == NULL) { 219*355d6bb5Sswilcox free((void *)bp); 220*355d6bb5Sswilcox if (i >= MINBUFS) 221*355d6bb5Sswilcox goto noalloc; 222*355d6bb5Sswilcox goto nomem; 2237c478bd9Sstevel@tonic-gate } 224*355d6bb5Sswilcox initbarea(bp); 2257c478bd9Sstevel@tonic-gate bp->b_un.b_buf = bufp; 2267c478bd9Sstevel@tonic-gate bp->b_prev = &bufhead; 2277c478bd9Sstevel@tonic-gate bp->b_next = bufhead.b_next; 2287c478bd9Sstevel@tonic-gate bufhead.b_next->b_prev = bp; 2297c478bd9Sstevel@tonic-gate bufhead.b_next = bp; 2307c478bd9Sstevel@tonic-gate } 231*355d6bb5Sswilcox noalloc: 2327c478bd9Sstevel@tonic-gate bufhead.b_size = i; /* save number of buffers */ 2337c478bd9Sstevel@tonic-gate pbp = pdirbp = NULL; 234*355d6bb5Sswilcox return; 235*355d6bb5Sswilcox 236*355d6bb5Sswilcox nomem: 237*355d6bb5Sswilcox errexit("cannot allocate buffer pool\n"); 238*355d6bb5Sswilcox /* NOTREACHED */ 239*355d6bb5Sswilcox } 240*355d6bb5Sswilcox 241*355d6bb5Sswilcox /* 242*355d6bb5Sswilcox * Undo a bufinit(). 243*355d6bb5Sswilcox */ 244*355d6bb5Sswilcox void 245*355d6bb5Sswilcox unbufinit(void) 246*355d6bb5Sswilcox { 247*355d6bb5Sswilcox int cnt; 248*355d6bb5Sswilcox struct bufarea *bp, *nbp; 249*355d6bb5Sswilcox 250*355d6bb5Sswilcox cnt = 0; 251*355d6bb5Sswilcox for (bp = bufhead.b_prev; bp != NULL && bp != &bufhead; bp = nbp) { 252*355d6bb5Sswilcox cnt++; 253*355d6bb5Sswilcox flush(fswritefd, bp); 254*355d6bb5Sswilcox nbp = bp->b_prev; 255*355d6bb5Sswilcox /* 256*355d6bb5Sswilcox * We're discarding the entire chain, so this isn't 257*355d6bb5Sswilcox * technically necessary. However, it doesn't hurt 258*355d6bb5Sswilcox * and lint's data flow analysis is much happier 259*355d6bb5Sswilcox * (this prevents it from thinking there's a chance 260*355d6bb5Sswilcox * of our using memory elsewhere after it's been released). 261*355d6bb5Sswilcox */ 262*355d6bb5Sswilcox nbp->b_next = bp->b_next; 263*355d6bb5Sswilcox bp->b_next->b_prev = nbp; 264*355d6bb5Sswilcox free((void *)bp->b_un.b_buf); 265*355d6bb5Sswilcox free((void *)bp); 266*355d6bb5Sswilcox } 267*355d6bb5Sswilcox 268*355d6bb5Sswilcox if (bufhead.b_size != cnt) 269*355d6bb5Sswilcox errexit("Panic: cache lost %d buffers\n", 270*355d6bb5Sswilcox bufhead.b_size - cnt); 2717c478bd9Sstevel@tonic-gate } 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate /* 2747c478bd9Sstevel@tonic-gate * Manage a cache of directory blocks. 2757c478bd9Sstevel@tonic-gate */ 2767c478bd9Sstevel@tonic-gate struct bufarea * 277*355d6bb5Sswilcox getdatablk(daddr32_t blkno, size_t size) 2787c478bd9Sstevel@tonic-gate { 2797c478bd9Sstevel@tonic-gate struct bufarea *bp; 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next) 282*355d6bb5Sswilcox if (bp->b_bno == fsbtodb(&sblock, blkno)) { 2837c478bd9Sstevel@tonic-gate goto foundit; 284*355d6bb5Sswilcox } 2857c478bd9Sstevel@tonic-gate for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev) 2867c478bd9Sstevel@tonic-gate if ((bp->b_flags & B_INUSE) == 0) 2877c478bd9Sstevel@tonic-gate break; 2887c478bd9Sstevel@tonic-gate if (bp == &bufhead) { 2897c478bd9Sstevel@tonic-gate bp = alloc_bufarea(); 290*355d6bb5Sswilcox if (bp == NULL) { 2917c478bd9Sstevel@tonic-gate errexit("deadlocked buffer pool\n"); 292*355d6bb5Sswilcox /* NOTREACHED */ 293*355d6bb5Sswilcox } 2947c478bd9Sstevel@tonic-gate } 295*355d6bb5Sswilcox /* 296*355d6bb5Sswilcox * We're at the same logical level as getblk(), so if there 297*355d6bb5Sswilcox * are any errors, we'll let our caller handle them. 298*355d6bb5Sswilcox */ 299*355d6bb5Sswilcox diskreads++; 300*355d6bb5Sswilcox (void) getblk(bp, blkno, size); 301*355d6bb5Sswilcox 3027c478bd9Sstevel@tonic-gate foundit: 3037c478bd9Sstevel@tonic-gate totalreads++; 3047c478bd9Sstevel@tonic-gate bp->b_cnt++; 3057c478bd9Sstevel@tonic-gate /* 306*355d6bb5Sswilcox * Move the buffer to head of linked list if it isn't 3077c478bd9Sstevel@tonic-gate * already there. 3087c478bd9Sstevel@tonic-gate */ 3097c478bd9Sstevel@tonic-gate if (bufhead.b_next != bp) { 3107c478bd9Sstevel@tonic-gate bp->b_prev->b_next = bp->b_next; 3117c478bd9Sstevel@tonic-gate bp->b_next->b_prev = bp->b_prev; 3127c478bd9Sstevel@tonic-gate bp->b_prev = &bufhead; 3137c478bd9Sstevel@tonic-gate bp->b_next = bufhead.b_next; 3147c478bd9Sstevel@tonic-gate bufhead.b_next->b_prev = bp; 3157c478bd9Sstevel@tonic-gate bufhead.b_next = bp; 3167c478bd9Sstevel@tonic-gate } 3177c478bd9Sstevel@tonic-gate bp->b_flags |= B_INUSE; 3187c478bd9Sstevel@tonic-gate return (bp); 3197c478bd9Sstevel@tonic-gate } 3207c478bd9Sstevel@tonic-gate 321*355d6bb5Sswilcox void 3227c478bd9Sstevel@tonic-gate brelse(struct bufarea *bp) 3237c478bd9Sstevel@tonic-gate { 3247c478bd9Sstevel@tonic-gate bp->b_cnt--; 3257c478bd9Sstevel@tonic-gate if (bp->b_cnt == 0) { 3267c478bd9Sstevel@tonic-gate bp->b_flags &= ~B_INUSE; 3277c478bd9Sstevel@tonic-gate } 3287c478bd9Sstevel@tonic-gate } 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate struct bufarea * 331*355d6bb5Sswilcox getblk(struct bufarea *bp, daddr32_t blk, size_t size) 3327c478bd9Sstevel@tonic-gate { 3337c478bd9Sstevel@tonic-gate diskaddr_t dblk; 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate dblk = fsbtodb(&sblock, blk); 3367c478bd9Sstevel@tonic-gate if (bp->b_bno == dblk) 3377c478bd9Sstevel@tonic-gate return (bp); 3387c478bd9Sstevel@tonic-gate flush(fswritefd, bp); 339*355d6bb5Sswilcox bp->b_errs = fsck_bread(fsreadfd, bp->b_un.b_buf, dblk, size); 3407c478bd9Sstevel@tonic-gate bp->b_bno = dblk; 3417c478bd9Sstevel@tonic-gate bp->b_size = size; 3427c478bd9Sstevel@tonic-gate return (bp); 3437c478bd9Sstevel@tonic-gate } 3447c478bd9Sstevel@tonic-gate 345*355d6bb5Sswilcox void 346*355d6bb5Sswilcox flush(int fd, struct bufarea *bp) 3477c478bd9Sstevel@tonic-gate { 3487c478bd9Sstevel@tonic-gate int i, j; 3497c478bd9Sstevel@tonic-gate caddr_t sip; 3507c478bd9Sstevel@tonic-gate long size; 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate if (!bp->b_dirty) 3537c478bd9Sstevel@tonic-gate return; 354*355d6bb5Sswilcox 355*355d6bb5Sswilcox /* 356*355d6bb5Sswilcox * It's not our buf, so if there are errors, let whoever 357*355d6bb5Sswilcox * acquired it deal with the actual problem. 358*355d6bb5Sswilcox */ 3597c478bd9Sstevel@tonic-gate if (bp->b_errs != 0) 3607c478bd9Sstevel@tonic-gate pfatal("WRITING ZERO'ED BLOCK %lld TO DISK\n", bp->b_bno); 3617c478bd9Sstevel@tonic-gate bp->b_dirty = 0; 3627c478bd9Sstevel@tonic-gate bp->b_errs = 0; 3637c478bd9Sstevel@tonic-gate bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); 364*355d6bb5Sswilcox if (bp != &sblk) { 3657c478bd9Sstevel@tonic-gate return; 366*355d6bb5Sswilcox } 367*355d6bb5Sswilcox 368*355d6bb5Sswilcox /* 369*355d6bb5Sswilcox * We're flushing the superblock, so make sure all the 370*355d6bb5Sswilcox * ancillary bits go out as well. 371*355d6bb5Sswilcox */ 3727c478bd9Sstevel@tonic-gate sip = (caddr_t)sblock.fs_u.fs_csp; 3737c478bd9Sstevel@tonic-gate for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 3747c478bd9Sstevel@tonic-gate size = sblock.fs_cssize - i < sblock.fs_bsize ? 3757c478bd9Sstevel@tonic-gate sblock.fs_cssize - i : sblock.fs_bsize; 3767c478bd9Sstevel@tonic-gate bwrite(fswritefd, sip, 3777c478bd9Sstevel@tonic-gate fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 3787c478bd9Sstevel@tonic-gate size); 3797c478bd9Sstevel@tonic-gate sip += size; 3807c478bd9Sstevel@tonic-gate } 3817c478bd9Sstevel@tonic-gate } 3827c478bd9Sstevel@tonic-gate 383*355d6bb5Sswilcox static void 384*355d6bb5Sswilcox rwerror(caddr_t mesg, diskaddr_t blk, int rval) 3857c478bd9Sstevel@tonic-gate { 386*355d6bb5Sswilcox int olderr = errno; 387*355d6bb5Sswilcox 388*355d6bb5Sswilcox if (!preen) 389*355d6bb5Sswilcox (void) printf("\n"); 3907c478bd9Sstevel@tonic-gate 391*355d6bb5Sswilcox if (rval == -1) 392*355d6bb5Sswilcox pfatal("CANNOT %s: DISK BLOCK %lld: %s", 393*355d6bb5Sswilcox mesg, blk, strerror(olderr)); 394*355d6bb5Sswilcox else 395*355d6bb5Sswilcox pfatal("CANNOT %s: DISK BLOCK %lld", mesg, blk); 396*355d6bb5Sswilcox 397*355d6bb5Sswilcox if (reply("CONTINUE") == 0) { 398*355d6bb5Sswilcox exitstat = EXERRFATAL; 3997c478bd9Sstevel@tonic-gate errexit("Program terminated\n"); 400*355d6bb5Sswilcox } 4017c478bd9Sstevel@tonic-gate } 4027c478bd9Sstevel@tonic-gate 403*355d6bb5Sswilcox void 404*355d6bb5Sswilcox ckfini(void) 4057c478bd9Sstevel@tonic-gate { 406*355d6bb5Sswilcox int64_t percentage; 407*355d6bb5Sswilcox 408*355d6bb5Sswilcox if (fswritefd < 0) 409*355d6bb5Sswilcox return; 4107c478bd9Sstevel@tonic-gate 411*355d6bb5Sswilcox flush(fswritefd, &sblk); 4127c478bd9Sstevel@tonic-gate /* 413*355d6bb5Sswilcox * Were we using a backup superblock? 4147c478bd9Sstevel@tonic-gate */ 4157c478bd9Sstevel@tonic-gate if (havesb && sblk.b_bno != SBOFF / dev_bsize) { 416*355d6bb5Sswilcox if (preen || reply("UPDATE STANDARD SUPERBLOCK") == 1) { 417*355d6bb5Sswilcox sblk.b_bno = SBOFF / dev_bsize; 418*355d6bb5Sswilcox sbdirty(); 419*355d6bb5Sswilcox flush(fswritefd, &sblk); 420*355d6bb5Sswilcox } 4217c478bd9Sstevel@tonic-gate } 4227c478bd9Sstevel@tonic-gate flush(fswritefd, &cgblk); 423*355d6bb5Sswilcox if (cgblk.b_un.b_buf != NULL) { 424*355d6bb5Sswilcox free((void *)cgblk.b_un.b_buf); 4257c478bd9Sstevel@tonic-gate cgblk.b_un.b_buf = NULL; 4267c478bd9Sstevel@tonic-gate } 427*355d6bb5Sswilcox unbufinit(); 428*355d6bb5Sswilcox pbp = NULL; 429*355d6bb5Sswilcox pdirbp = NULL; 430*355d6bb5Sswilcox if (debug) { 431*355d6bb5Sswilcox /* 432*355d6bb5Sswilcox * Note that we only count cache-related reads. 433*355d6bb5Sswilcox * Anything that called fsck_bread() or getblk() 434*355d6bb5Sswilcox * directly are explicitly not cached, so they're not 435*355d6bb5Sswilcox * included here. 436*355d6bb5Sswilcox */ 437*355d6bb5Sswilcox if (totalreads != 0) 438*355d6bb5Sswilcox percentage = diskreads * 100 / totalreads; 439*355d6bb5Sswilcox else 440*355d6bb5Sswilcox percentage = 0; 441*355d6bb5Sswilcox 442*355d6bb5Sswilcox (void) printf("cache missed %lld of %lld reads (%lld%%)\n", 443*355d6bb5Sswilcox (longlong_t)diskreads, (longlong_t)totalreads, 444*355d6bb5Sswilcox (longlong_t)percentage); 4457c478bd9Sstevel@tonic-gate } 446*355d6bb5Sswilcox 4477c478bd9Sstevel@tonic-gate (void) close(fsreadfd); 4487c478bd9Sstevel@tonic-gate (void) close(fswritefd); 449*355d6bb5Sswilcox fsreadfd = -1; 450*355d6bb5Sswilcox fswritefd = -1; 4517c478bd9Sstevel@tonic-gate } 4527c478bd9Sstevel@tonic-gate 453*355d6bb5Sswilcox int 454*355d6bb5Sswilcox fsck_bread(int fd, caddr_t buf, diskaddr_t blk, size_t size) 4557c478bd9Sstevel@tonic-gate { 456*355d6bb5Sswilcox caddr_t cp; 457*355d6bb5Sswilcox int i; 4587c478bd9Sstevel@tonic-gate int errs; 4597c478bd9Sstevel@tonic-gate offset_t offset = ldbtob(blk); 4607c478bd9Sstevel@tonic-gate offset_t addr; 4617c478bd9Sstevel@tonic-gate 462*355d6bb5Sswilcox /* 463*355d6bb5Sswilcox * In our universe, nothing exists before the superblock, so 464*355d6bb5Sswilcox * just pretend it's always zeros. This is the complement of 465*355d6bb5Sswilcox * bwrite()'s ignoring write requests into that space. 466*355d6bb5Sswilcox */ 467*355d6bb5Sswilcox if (blk < SBLOCK) { 468*355d6bb5Sswilcox if (debug) 469*355d6bb5Sswilcox (void) printf( 470*355d6bb5Sswilcox "WARNING: fsck_bread() passed blkno < %d (%lld)\n", 471*355d6bb5Sswilcox SBLOCK, (longlong_t)blk); 472*355d6bb5Sswilcox (void) memset(buf, 0, (size_t)size); 473*355d6bb5Sswilcox return (1); 4747c478bd9Sstevel@tonic-gate } 475*355d6bb5Sswilcox 4767c478bd9Sstevel@tonic-gate if (llseek(fd, offset, 0) < 0) { 477*355d6bb5Sswilcox rwerror("SEEK", blk, -1); 478*355d6bb5Sswilcox } 479*355d6bb5Sswilcox 480*355d6bb5Sswilcox if ((i = read(fd, buf, size)) == size) { 4817c478bd9Sstevel@tonic-gate return (0); 482*355d6bb5Sswilcox } 483*355d6bb5Sswilcox rwerror("READ", blk, i); 4847c478bd9Sstevel@tonic-gate if (llseek(fd, offset, 0) < 0) { 485*355d6bb5Sswilcox rwerror("SEEK", blk, -1); 4867c478bd9Sstevel@tonic-gate } 4877c478bd9Sstevel@tonic-gate errs = 0; 488*355d6bb5Sswilcox (void) memset(buf, 0, (size_t)size); 4897c478bd9Sstevel@tonic-gate pwarn("THE FOLLOWING SECTORS COULD NOT BE READ:"); 4907c478bd9Sstevel@tonic-gate for (cp = buf, i = 0; i < btodb(size); i++, cp += DEV_BSIZE) { 4917c478bd9Sstevel@tonic-gate addr = ldbtob(blk + i); 4927c478bd9Sstevel@tonic-gate if (llseek(fd, addr, SEEK_CUR) < 0 || 4937c478bd9Sstevel@tonic-gate read(fd, cp, (int)secsize) < 0) { 494*355d6bb5Sswilcox iscorrupt = 1; 495*355d6bb5Sswilcox (void) printf(" %llu", blk + (u_longlong_t)i); 4967c478bd9Sstevel@tonic-gate errs++; 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate } 499*355d6bb5Sswilcox (void) printf("\n"); 5007c478bd9Sstevel@tonic-gate return (errs); 5017c478bd9Sstevel@tonic-gate } 5027c478bd9Sstevel@tonic-gate 503*355d6bb5Sswilcox void 504*355d6bb5Sswilcox bwrite(int fd, caddr_t buf, diskaddr_t blk, int64_t size) 5057c478bd9Sstevel@tonic-gate { 506*355d6bb5Sswilcox int i; 5077c478bd9Sstevel@tonic-gate int n; 508*355d6bb5Sswilcox caddr_t cp; 5097c478bd9Sstevel@tonic-gate offset_t offset = ldbtob(blk); 5107c478bd9Sstevel@tonic-gate offset_t addr; 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate if (fd < 0) 5137c478bd9Sstevel@tonic-gate return; 5147c478bd9Sstevel@tonic-gate if (blk < SBLOCK) { 5157c478bd9Sstevel@tonic-gate if (debug) 516*355d6bb5Sswilcox (void) printf( 517*355d6bb5Sswilcox "WARNING: Attempt to write illegal blkno %lld on %s\n", 518*355d6bb5Sswilcox (longlong_t)blk, devname); 5197c478bd9Sstevel@tonic-gate return; 5207c478bd9Sstevel@tonic-gate } 5217c478bd9Sstevel@tonic-gate if (llseek(fd, offset, 0) < 0) { 522*355d6bb5Sswilcox rwerror("SEEK", blk, -1); 523*355d6bb5Sswilcox } 524*355d6bb5Sswilcox if ((i = write(fd, buf, (int)size)) == size) { 5257c478bd9Sstevel@tonic-gate fsmodified = 1; 5267c478bd9Sstevel@tonic-gate return; 5277c478bd9Sstevel@tonic-gate } 528*355d6bb5Sswilcox rwerror("WRITE", blk, i); 5297c478bd9Sstevel@tonic-gate if (llseek(fd, offset, 0) < 0) { 530*355d6bb5Sswilcox rwerror("SEEK", blk, -1); 5317c478bd9Sstevel@tonic-gate } 5327c478bd9Sstevel@tonic-gate pwarn("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); 5337c478bd9Sstevel@tonic-gate for (cp = buf, i = 0; i < btodb(size); i++, cp += DEV_BSIZE) { 5347c478bd9Sstevel@tonic-gate n = 0; 5357c478bd9Sstevel@tonic-gate addr = ldbtob(blk + i); 5367c478bd9Sstevel@tonic-gate if (llseek(fd, addr, SEEK_CUR) < 0 || 5377c478bd9Sstevel@tonic-gate (n = write(fd, cp, DEV_BSIZE)) < 0) { 538*355d6bb5Sswilcox iscorrupt = 1; 539*355d6bb5Sswilcox (void) printf(" %llu", blk + (u_longlong_t)i); 5407c478bd9Sstevel@tonic-gate } else if (n > 0) { 5417c478bd9Sstevel@tonic-gate fsmodified = 1; 5427c478bd9Sstevel@tonic-gate } 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate } 545*355d6bb5Sswilcox (void) printf("\n"); 5467c478bd9Sstevel@tonic-gate } 5477c478bd9Sstevel@tonic-gate 5487c478bd9Sstevel@tonic-gate /* 549*355d6bb5Sswilcox * Allocates the specified number of contiguous fragments. 5507c478bd9Sstevel@tonic-gate */ 5517c478bd9Sstevel@tonic-gate daddr32_t 552*355d6bb5Sswilcox allocblk(int wantedfrags) 5537c478bd9Sstevel@tonic-gate { 554*355d6bb5Sswilcox int block, leadfrag, tailfrag; 555*355d6bb5Sswilcox daddr32_t selected; 556*355d6bb5Sswilcox size_t size; 557*355d6bb5Sswilcox struct bufarea *bp; 5587c478bd9Sstevel@tonic-gate 559*355d6bb5Sswilcox /* 560*355d6bb5Sswilcox * It's arguable whether we should just fail, or instead 561*355d6bb5Sswilcox * error out here. Since we should only ever be asked for 562*355d6bb5Sswilcox * a single fragment or an entire block (i.e., sblock.fs_frag), 563*355d6bb5Sswilcox * we'll fail out because anything else means somebody 564*355d6bb5Sswilcox * changed code without considering all of the ramifications. 565*355d6bb5Sswilcox */ 566*355d6bb5Sswilcox if (wantedfrags <= 0 || wantedfrags > sblock.fs_frag) { 567*355d6bb5Sswilcox exitstat = EXERRFATAL; 568*355d6bb5Sswilcox errexit("allocblk() asked for %d frags. " 569*355d6bb5Sswilcox "Legal range is 1 to %d", 570*355d6bb5Sswilcox wantedfrags, sblock.fs_frag); 571*355d6bb5Sswilcox } 572*355d6bb5Sswilcox 573*355d6bb5Sswilcox /* 574*355d6bb5Sswilcox * For each filesystem block, look at every possible starting 575*355d6bb5Sswilcox * offset within the block such that we can get the number of 576*355d6bb5Sswilcox * contiguous fragments that we need. This is a drastically 577*355d6bb5Sswilcox * simplified version of the kernel's mapsearch() and alloc*(). 578*355d6bb5Sswilcox * It's also correspondingly slower. 579*355d6bb5Sswilcox */ 580*355d6bb5Sswilcox for (block = 0; block < maxfsblock - sblock.fs_frag; 581*355d6bb5Sswilcox block += sblock.fs_frag) { 582*355d6bb5Sswilcox for (leadfrag = 0; leadfrag <= sblock.fs_frag - wantedfrags; 583*355d6bb5Sswilcox leadfrag++) { 584*355d6bb5Sswilcox /* 585*355d6bb5Sswilcox * Is first fragment of candidate run available? 586*355d6bb5Sswilcox */ 587*355d6bb5Sswilcox if (testbmap(block + leadfrag)) 5887c478bd9Sstevel@tonic-gate continue; 589*355d6bb5Sswilcox /* 590*355d6bb5Sswilcox * Are the rest of them available? 591*355d6bb5Sswilcox */ 592*355d6bb5Sswilcox for (tailfrag = 1; tailfrag < wantedfrags; tailfrag++) 593*355d6bb5Sswilcox if (testbmap(block + leadfrag + tailfrag)) 5947c478bd9Sstevel@tonic-gate break; 595*355d6bb5Sswilcox if (tailfrag < wantedfrags) { 596*355d6bb5Sswilcox /* 597*355d6bb5Sswilcox * No, skip the known-unusable run. 598*355d6bb5Sswilcox */ 599*355d6bb5Sswilcox leadfrag += tailfrag; 6007c478bd9Sstevel@tonic-gate continue; 6017c478bd9Sstevel@tonic-gate } 602*355d6bb5Sswilcox /* 603*355d6bb5Sswilcox * Found what we need, so claim them. 604*355d6bb5Sswilcox */ 605*355d6bb5Sswilcox for (tailfrag = 0; tailfrag < wantedfrags; tailfrag++) 606*355d6bb5Sswilcox setbmap(block + leadfrag + tailfrag); 607*355d6bb5Sswilcox n_blks += wantedfrags; 608*355d6bb5Sswilcox size = wantedfrags * sblock.fs_fsize; 609*355d6bb5Sswilcox selected = block + leadfrag; 610*355d6bb5Sswilcox bp = getdatablk(selected, size); 611*355d6bb5Sswilcox (void) memset((void *)bp->b_un.b_buf, 0, size); 612*355d6bb5Sswilcox dirty(bp); 613*355d6bb5Sswilcox brelse(bp); 614*355d6bb5Sswilcox if (debug) 615*355d6bb5Sswilcox (void) printf( 616*355d6bb5Sswilcox "allocblk: selected %d (in block %d), frags %d, size %d\n", 617*355d6bb5Sswilcox selected, selected % sblock.fs_bsize, 618*355d6bb5Sswilcox wantedfrags, (int)size); 619*355d6bb5Sswilcox return (selected); 6207c478bd9Sstevel@tonic-gate } 6217c478bd9Sstevel@tonic-gate } 6227c478bd9Sstevel@tonic-gate return (0); 6237c478bd9Sstevel@tonic-gate } 6247c478bd9Sstevel@tonic-gate 6257c478bd9Sstevel@tonic-gate /* 6267c478bd9Sstevel@tonic-gate * Free a previously allocated block 6277c478bd9Sstevel@tonic-gate */ 628*355d6bb5Sswilcox void 629*355d6bb5Sswilcox freeblk(fsck_ino_t ino, daddr32_t blkno, int frags) 6307c478bd9Sstevel@tonic-gate { 6317c478bd9Sstevel@tonic-gate struct inodesc idesc; 6327c478bd9Sstevel@tonic-gate 633*355d6bb5Sswilcox if (debug) 634*355d6bb5Sswilcox (void) printf("debug: freeing %d fragments starting at %d\n", 635*355d6bb5Sswilcox frags, blkno); 636*355d6bb5Sswilcox 637*355d6bb5Sswilcox init_inodesc(&idesc); 638*355d6bb5Sswilcox 639*355d6bb5Sswilcox idesc.id_number = ino; 6407c478bd9Sstevel@tonic-gate idesc.id_blkno = blkno; 6417c478bd9Sstevel@tonic-gate idesc.id_numfrags = frags; 642*355d6bb5Sswilcox idesc.id_truncto = -1; 643*355d6bb5Sswilcox 644*355d6bb5Sswilcox /* 645*355d6bb5Sswilcox * Nothing in the return status has any relevance to how 646*355d6bb5Sswilcox * we're using pass4check(), so just ignore it. 647*355d6bb5Sswilcox */ 648*355d6bb5Sswilcox (void) pass4check(&idesc); 6497c478bd9Sstevel@tonic-gate } 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate /* 652*355d6bb5Sswilcox * Fill NAMEBUF with a path starting in CURDIR for INO. Assumes 653*355d6bb5Sswilcox * that the given buffer is at least MAXPATHLEN + 1 characters. 6547c478bd9Sstevel@tonic-gate */ 655*355d6bb5Sswilcox void 656*355d6bb5Sswilcox getpathname(caddr_t namebuf, fsck_ino_t curdir, fsck_ino_t ino) 6577c478bd9Sstevel@tonic-gate { 6587c478bd9Sstevel@tonic-gate int len; 659*355d6bb5Sswilcox caddr_t cp; 660*355d6bb5Sswilcox struct dinode *dp; 6617c478bd9Sstevel@tonic-gate struct inodesc idesc; 6627c478bd9Sstevel@tonic-gate struct inoinfo *inp; 6637c478bd9Sstevel@tonic-gate 664*355d6bb5Sswilcox if (debug) 665*355d6bb5Sswilcox (void) printf("debug: getpathname(curdir %d, ino %d)\n", 666*355d6bb5Sswilcox curdir, ino); 667*355d6bb5Sswilcox 668*355d6bb5Sswilcox if ((curdir == 0) || (!INO_IS_DVALID(curdir))) { 669*355d6bb5Sswilcox (void) strcpy(namebuf, "?"); 670*355d6bb5Sswilcox return; 671*355d6bb5Sswilcox } 672*355d6bb5Sswilcox 673*355d6bb5Sswilcox if ((curdir == UFSROOTINO) && (ino == UFSROOTINO)) { 674*355d6bb5Sswilcox (void) strcpy(namebuf, "/"); 6757c478bd9Sstevel@tonic-gate return; 6767c478bd9Sstevel@tonic-gate } 677*355d6bb5Sswilcox 678*355d6bb5Sswilcox init_inodesc(&idesc); 6797c478bd9Sstevel@tonic-gate idesc.id_type = DATA; 6807c478bd9Sstevel@tonic-gate cp = &namebuf[MAXPATHLEN - 1]; 6817c478bd9Sstevel@tonic-gate *cp = '\0'; 682*355d6bb5Sswilcox 683*355d6bb5Sswilcox /* 684*355d6bb5Sswilcox * In the case of extended attributes, our 685*355d6bb5Sswilcox * parent won't necessarily be a directory, so just 686*355d6bb5Sswilcox * return what we've found with a prefix indicating 687*355d6bb5Sswilcox * that it's an XATTR. Presumably our caller will 688*355d6bb5Sswilcox * know what's going on and do something useful, like 689*355d6bb5Sswilcox * work out the path of the parent and then combine 690*355d6bb5Sswilcox * the two names. 691*355d6bb5Sswilcox * 692*355d6bb5Sswilcox * Can't use strcpy(), etc, because we've probably 693*355d6bb5Sswilcox * already got some name information in the buffer and 694*355d6bb5Sswilcox * the usual trailing \0 would lose it. 695*355d6bb5Sswilcox */ 696*355d6bb5Sswilcox dp = ginode(curdir); 697*355d6bb5Sswilcox if ((dp->di_mode & IFMT) == IFATTRDIR) { 698*355d6bb5Sswilcox idesc.id_number = curdir; 699*355d6bb5Sswilcox idesc.id_parent = ino; 700*355d6bb5Sswilcox idesc.id_func = findname; 701*355d6bb5Sswilcox idesc.id_name = namebuf; 702*355d6bb5Sswilcox idesc.id_fix = NOFIX; 703*355d6bb5Sswilcox if ((ckinode(dp, &idesc, CKI_TRAVERSE) & FOUND) == 0) { 704*355d6bb5Sswilcox *cp-- = '?'; 705*355d6bb5Sswilcox } 706*355d6bb5Sswilcox 707*355d6bb5Sswilcox len = sizeof (XATTR_DIR_NAME) - 1; 708*355d6bb5Sswilcox cp -= len; 709*355d6bb5Sswilcox (void) memmove(cp, XATTR_DIR_NAME, len); 710*355d6bb5Sswilcox goto attrname; 711*355d6bb5Sswilcox } 712*355d6bb5Sswilcox 713*355d6bb5Sswilcox /* 714*355d6bb5Sswilcox * If curdir == ino, need to get a handle on .. so we 715*355d6bb5Sswilcox * can search it for ino's name. Otherwise, just search 716*355d6bb5Sswilcox * the given directory for ino. Repeat until out of space 717*355d6bb5Sswilcox * or a full path has been built. 718*355d6bb5Sswilcox */ 7197c478bd9Sstevel@tonic-gate if (curdir != ino) { 7207c478bd9Sstevel@tonic-gate idesc.id_parent = curdir; 7217c478bd9Sstevel@tonic-gate goto namelookup; 7227c478bd9Sstevel@tonic-gate } 723*355d6bb5Sswilcox while (ino != UFSROOTINO && ino != 0) { 7247c478bd9Sstevel@tonic-gate idesc.id_number = ino; 7257c478bd9Sstevel@tonic-gate idesc.id_func = findino; 7267c478bd9Sstevel@tonic-gate idesc.id_name = ".."; 7277c478bd9Sstevel@tonic-gate idesc.id_fix = NOFIX; 728*355d6bb5Sswilcox if ((ckinode(ginode(ino), &idesc, CKI_TRAVERSE) & FOUND) == 0) { 7297c478bd9Sstevel@tonic-gate inp = getinoinfo(ino); 730*355d6bb5Sswilcox if ((inp == NULL) || (inp->i_parent == 0)) { 7317c478bd9Sstevel@tonic-gate break; 732*355d6bb5Sswilcox } 7337c478bd9Sstevel@tonic-gate idesc.id_parent = inp->i_parent; 7347c478bd9Sstevel@tonic-gate } 735*355d6bb5Sswilcox 736*355d6bb5Sswilcox /* 737*355d6bb5Sswilcox * To get this far, id_parent must have the inode 738*355d6bb5Sswilcox * number for `..' in it. By definition, that's got 739*355d6bb5Sswilcox * to be a directory, so search it for the inode of 740*355d6bb5Sswilcox * interest. 741*355d6bb5Sswilcox */ 742*355d6bb5Sswilcox namelookup: 7437c478bd9Sstevel@tonic-gate idesc.id_number = idesc.id_parent; 7447c478bd9Sstevel@tonic-gate idesc.id_parent = ino; 7457c478bd9Sstevel@tonic-gate idesc.id_func = findname; 7467c478bd9Sstevel@tonic-gate idesc.id_name = namebuf; 7477c478bd9Sstevel@tonic-gate idesc.id_fix = NOFIX; 748*355d6bb5Sswilcox if ((ckinode(ginode(idesc.id_number), 749*355d6bb5Sswilcox &idesc, CKI_TRAVERSE) & FOUND) == 0) { 7507c478bd9Sstevel@tonic-gate break; 751*355d6bb5Sswilcox } 752*355d6bb5Sswilcox /* 753*355d6bb5Sswilcox * Prepend to what we've accumulated so far. If 754*355d6bb5Sswilcox * there's not enough room for even one more path element 755*355d6bb5Sswilcox * (of the worst-case length), then bail out. 756*355d6bb5Sswilcox */ 7577c478bd9Sstevel@tonic-gate len = strlen(namebuf); 7587c478bd9Sstevel@tonic-gate cp -= len; 7597c478bd9Sstevel@tonic-gate if (cp < &namebuf[MAXNAMLEN]) 7607c478bd9Sstevel@tonic-gate break; 761*355d6bb5Sswilcox (void) memmove(cp, namebuf, len); 7627c478bd9Sstevel@tonic-gate *--cp = '/'; 763*355d6bb5Sswilcox 764*355d6bb5Sswilcox /* 765*355d6bb5Sswilcox * Corner case for a looped-to-itself directory. 766*355d6bb5Sswilcox */ 767*355d6bb5Sswilcox if (ino == idesc.id_number) 768*355d6bb5Sswilcox break; 769*355d6bb5Sswilcox 770*355d6bb5Sswilcox /* 771*355d6bb5Sswilcox * Climb one level of the hierarchy. In other words, 772*355d6bb5Sswilcox * the current .. becomes the inode to search for and 773*355d6bb5Sswilcox * its parent becomes the directory to search in. 774*355d6bb5Sswilcox */ 7757c478bd9Sstevel@tonic-gate ino = idesc.id_number; 7767c478bd9Sstevel@tonic-gate } 777*355d6bb5Sswilcox 778*355d6bb5Sswilcox /* 779*355d6bb5Sswilcox * If we hit a discontinuity in the hierarchy, indicate it by 780*355d6bb5Sswilcox * prefixing the path so far with `?'. Otherwise, the first 781*355d6bb5Sswilcox * character will be `/' as a side-effect of the *--cp above. 782*355d6bb5Sswilcox * 783*355d6bb5Sswilcox * The special case is to handle the situation where we're 784*355d6bb5Sswilcox * trying to look something up in UFSROOTINO, but didn't find 785*355d6bb5Sswilcox * it. 786*355d6bb5Sswilcox */ 787*355d6bb5Sswilcox if (ino != UFSROOTINO || cp == &namebuf[MAXPATHLEN - 1]) { 788*355d6bb5Sswilcox if (cp > namebuf) 789*355d6bb5Sswilcox cp--; 790*355d6bb5Sswilcox *cp = '?'; 7917c478bd9Sstevel@tonic-gate } 792*355d6bb5Sswilcox 793*355d6bb5Sswilcox /* 794*355d6bb5Sswilcox * The invariants being used for buffer integrity are: 795*355d6bb5Sswilcox * - namebuf[] is terminated with \0 before anything else 796*355d6bb5Sswilcox * - cp is always <= the last element of namebuf[] 797*355d6bb5Sswilcox * - the new path element is always stored at the 798*355d6bb5Sswilcox * beginning of namebuf[], and is no more than MAXNAMLEN-1 799*355d6bb5Sswilcox * characters 800*355d6bb5Sswilcox * - cp is is decremented by the number of characters in 801*355d6bb5Sswilcox * the new path element 802*355d6bb5Sswilcox * - if, after the above accounting for the new element's 803*355d6bb5Sswilcox * size, there is no longer enough room at the beginning of 804*355d6bb5Sswilcox * namebuf[] for a full-sized path element and a slash, 805*355d6bb5Sswilcox * terminate the loop. cp is in the range 806*355d6bb5Sswilcox * &namebuf[0]..&namebuf[MAXNAMLEN - 1] 807*355d6bb5Sswilcox */ 808*355d6bb5Sswilcox attrname: 809*355d6bb5Sswilcox /* LINTED per the above discussion */ 810*355d6bb5Sswilcox (void) memmove(namebuf, cp, &namebuf[MAXPATHLEN] - cp); 8117c478bd9Sstevel@tonic-gate } 8127c478bd9Sstevel@tonic-gate 813*355d6bb5Sswilcox /* ARGSUSED */ 8147c478bd9Sstevel@tonic-gate void 815*355d6bb5Sswilcox catch(int dummy) 8167c478bd9Sstevel@tonic-gate { 8177c478bd9Sstevel@tonic-gate ckfini(); 818*355d6bb5Sswilcox exit(EXSIGNAL); 8197c478bd9Sstevel@tonic-gate } 8207c478bd9Sstevel@tonic-gate 8217c478bd9Sstevel@tonic-gate /* 8227c478bd9Sstevel@tonic-gate * When preening, allow a single quit to signal 8237c478bd9Sstevel@tonic-gate * a special exit after filesystem checks complete 8247c478bd9Sstevel@tonic-gate * so that reboot sequence may be interrupted. 8257c478bd9Sstevel@tonic-gate */ 826*355d6bb5Sswilcox /* ARGSUSED */ 8277c478bd9Sstevel@tonic-gate void 828*355d6bb5Sswilcox catchquit(int dummy) 8297c478bd9Sstevel@tonic-gate { 830*355d6bb5Sswilcox (void) printf("returning to single-user after filesystem check\n"); 831*355d6bb5Sswilcox interrupted = 1; 8327c478bd9Sstevel@tonic-gate (void) signal(SIGQUIT, SIG_DFL); 8337c478bd9Sstevel@tonic-gate } 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate 8367c478bd9Sstevel@tonic-gate /* 8377c478bd9Sstevel@tonic-gate * determine whether an inode should be fixed. 8387c478bd9Sstevel@tonic-gate */ 839*355d6bb5Sswilcox NOTE(PRINTFLIKE(2)) 840*355d6bb5Sswilcox int 841*355d6bb5Sswilcox dofix(struct inodesc *idesc, caddr_t msg, ...) 8427c478bd9Sstevel@tonic-gate { 843*355d6bb5Sswilcox int rval = 0; 844*355d6bb5Sswilcox va_list ap; 845*355d6bb5Sswilcox 846*355d6bb5Sswilcox va_start(ap, msg); 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate switch (idesc->id_fix) { 8497c478bd9Sstevel@tonic-gate 8507c478bd9Sstevel@tonic-gate case DONTKNOW: 8517c478bd9Sstevel@tonic-gate if (idesc->id_type == DATA) 852*355d6bb5Sswilcox vdirerror(idesc->id_number, msg, ap); 8537c478bd9Sstevel@tonic-gate else 854*355d6bb5Sswilcox vpwarn(msg, ap); 8557c478bd9Sstevel@tonic-gate if (preen) { 8567c478bd9Sstevel@tonic-gate idesc->id_fix = FIX; 857*355d6bb5Sswilcox rval = ALTERED; 858*355d6bb5Sswilcox break; 8597c478bd9Sstevel@tonic-gate } 8607c478bd9Sstevel@tonic-gate if (reply("SALVAGE") == 0) { 8617c478bd9Sstevel@tonic-gate idesc->id_fix = NOFIX; 862*355d6bb5Sswilcox break; 8637c478bd9Sstevel@tonic-gate } 8647c478bd9Sstevel@tonic-gate idesc->id_fix = FIX; 865*355d6bb5Sswilcox rval = ALTERED; 866*355d6bb5Sswilcox break; 8677c478bd9Sstevel@tonic-gate 8687c478bd9Sstevel@tonic-gate case FIX: 869*355d6bb5Sswilcox rval = ALTERED; 870*355d6bb5Sswilcox break; 8717c478bd9Sstevel@tonic-gate 8727c478bd9Sstevel@tonic-gate case NOFIX: 873*355d6bb5Sswilcox break; 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate default: 876*355d6bb5Sswilcox errexit("UNKNOWN INODESC FIX MODE %d\n", (int)idesc->id_fix); 8777c478bd9Sstevel@tonic-gate } 878*355d6bb5Sswilcox 879*355d6bb5Sswilcox va_end(ap); 880*355d6bb5Sswilcox return (rval); 8817c478bd9Sstevel@tonic-gate } 8827c478bd9Sstevel@tonic-gate 883*355d6bb5Sswilcox NOTE(PRINTFLIKE(1)) 884*355d6bb5Sswilcox void 885*355d6bb5Sswilcox errexit(caddr_t fmt, ...) 8867c478bd9Sstevel@tonic-gate { 887*355d6bb5Sswilcox va_list ap; 8887c478bd9Sstevel@tonic-gate 889*355d6bb5Sswilcox va_start(ap, fmt); 890*355d6bb5Sswilcox verrexit(fmt, ap); 891*355d6bb5Sswilcox /* NOTREACHED */ 892*355d6bb5Sswilcox } 893*355d6bb5Sswilcox 894*355d6bb5Sswilcox NOTE(PRINTFLIKE(1)) 895*355d6bb5Sswilcox static void 896*355d6bb5Sswilcox verrexit(caddr_t fmt, va_list ap) 897*355d6bb5Sswilcox { 898*355d6bb5Sswilcox static int recursing = 0; 899*355d6bb5Sswilcox 900*355d6bb5Sswilcox if (!recursing) { 901*355d6bb5Sswilcox recursing = 1; 902*355d6bb5Sswilcox if (errorlocked || iscorrupt) { 903*355d6bb5Sswilcox if (havesb) { 904*355d6bb5Sswilcox sblock.fs_clean = FSBAD; 905*355d6bb5Sswilcox sblock.fs_state = FSOKAY - (long)sblock.fs_time; 906*355d6bb5Sswilcox sblock.fs_state = -sblock.fs_state; 907*355d6bb5Sswilcox sbdirty(); 908*355d6bb5Sswilcox write_altsb(fswritefd); 909*355d6bb5Sswilcox flush(fswritefd, &sblk); 910*355d6bb5Sswilcox } 9117c478bd9Sstevel@tonic-gate } 912*355d6bb5Sswilcox ckfini(); 913*355d6bb5Sswilcox recursing = 0; 9147c478bd9Sstevel@tonic-gate } 915*355d6bb5Sswilcox (void) vprintf(fmt, ap); 916*355d6bb5Sswilcox if (fmt[strlen(fmt) - 1] != '\n') 917*355d6bb5Sswilcox (void) putchar('\n'); 918*355d6bb5Sswilcox exit((exitstat != 0) ? exitstat : EXERRFATAL); 9197c478bd9Sstevel@tonic-gate } 9207c478bd9Sstevel@tonic-gate 9217c478bd9Sstevel@tonic-gate /* 9227c478bd9Sstevel@tonic-gate * An unexpected inconsistency occured. 9237c478bd9Sstevel@tonic-gate * Die if preening, otherwise just print message and continue. 9247c478bd9Sstevel@tonic-gate */ 925*355d6bb5Sswilcox NOTE(PRINTFLIKE(1)) 926*355d6bb5Sswilcox void 927*355d6bb5Sswilcox pfatal(caddr_t fmt, ...) 928*355d6bb5Sswilcox { 929*355d6bb5Sswilcox va_list ap; 930*355d6bb5Sswilcox 931*355d6bb5Sswilcox va_start(ap, fmt); 932*355d6bb5Sswilcox vpfatal(fmt, ap); 933*355d6bb5Sswilcox va_end(ap); 934*355d6bb5Sswilcox } 935*355d6bb5Sswilcox 936*355d6bb5Sswilcox NOTE(PRINTFLIKE(1)) 937*355d6bb5Sswilcox static void 938*355d6bb5Sswilcox vpfatal(caddr_t fmt, va_list ap) 9397c478bd9Sstevel@tonic-gate { 9407c478bd9Sstevel@tonic-gate if (preen) { 941*355d6bb5Sswilcox if (*fmt != '\0') { 942*355d6bb5Sswilcox (void) printf("%s: ", devname); 943*355d6bb5Sswilcox (void) vprintf(fmt, ap); 944*355d6bb5Sswilcox (void) printf("\n"); 945*355d6bb5Sswilcox } 946*355d6bb5Sswilcox (void) printf( 947*355d6bb5Sswilcox "%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", 948*355d6bb5Sswilcox devname); 9497c478bd9Sstevel@tonic-gate if (havesb) { 9507c478bd9Sstevel@tonic-gate sblock.fs_clean = FSBAD; 9517c478bd9Sstevel@tonic-gate sblock.fs_state = -(FSOKAY - (long)sblock.fs_time); 9527c478bd9Sstevel@tonic-gate sbdirty(); 9537c478bd9Sstevel@tonic-gate flush(fswritefd, &sblk); 9547c478bd9Sstevel@tonic-gate } 955*355d6bb5Sswilcox /* 956*355d6bb5Sswilcox * We're exiting, it doesn't really matter that our 957*355d6bb5Sswilcox * caller doesn't get to call va_end(). 958*355d6bb5Sswilcox */ 959*355d6bb5Sswilcox if (exitstat == 0) 960*355d6bb5Sswilcox exitstat = EXFNDERRS; 961*355d6bb5Sswilcox exit(exitstat); 962*355d6bb5Sswilcox } 963*355d6bb5Sswilcox if (*fmt != '\0') { 964*355d6bb5Sswilcox (void) vprintf(fmt, ap); 9657c478bd9Sstevel@tonic-gate } 9667c478bd9Sstevel@tonic-gate } 9677c478bd9Sstevel@tonic-gate 9687c478bd9Sstevel@tonic-gate /* 9697c478bd9Sstevel@tonic-gate * Pwarn just prints a message when not preening, 9707c478bd9Sstevel@tonic-gate * or a warning (preceded by filename) when preening. 9717c478bd9Sstevel@tonic-gate */ 972*355d6bb5Sswilcox NOTE(PRINTFLIKE(1)) 973*355d6bb5Sswilcox void 974*355d6bb5Sswilcox pwarn(caddr_t fmt, ...) 9757c478bd9Sstevel@tonic-gate { 976*355d6bb5Sswilcox va_list ap; 9777c478bd9Sstevel@tonic-gate 978*355d6bb5Sswilcox va_start(ap, fmt); 979*355d6bb5Sswilcox vpwarn(fmt, ap); 980*355d6bb5Sswilcox va_end(ap); 981*355d6bb5Sswilcox } 982*355d6bb5Sswilcox 983*355d6bb5Sswilcox NOTE(PRINTFLIKE(1)) 984*355d6bb5Sswilcox static void 985*355d6bb5Sswilcox vpwarn(caddr_t fmt, va_list ap) 986*355d6bb5Sswilcox { 987*355d6bb5Sswilcox if (*fmt != '\0') { 988*355d6bb5Sswilcox if (preen) 989*355d6bb5Sswilcox (void) printf("%s: ", devname); 990*355d6bb5Sswilcox (void) vprintf(fmt, ap); 991*355d6bb5Sswilcox } 9927c478bd9Sstevel@tonic-gate } 9937c478bd9Sstevel@tonic-gate 9947c478bd9Sstevel@tonic-gate /* 995*355d6bb5Sswilcox * Like sprintf(), except the buffer is dynamically allocated 996*355d6bb5Sswilcox * and returned, instead of being passed in. A pointer to the 997*355d6bb5Sswilcox * buffer is stored in *RET, and FMT is the usual format string. 998*355d6bb5Sswilcox * The number of characters in *RET (excluding the trailing \0, 999*355d6bb5Sswilcox * to be consistent with the other *printf() routines) is returned. 1000*355d6bb5Sswilcox * 1001*355d6bb5Sswilcox * Solaris doesn't have asprintf(3C) yet, unfortunately. 10027c478bd9Sstevel@tonic-gate */ 1003*355d6bb5Sswilcox NOTE(PRINTFLIKE(2)) 1004*355d6bb5Sswilcox int 1005*355d6bb5Sswilcox fsck_asprintf(caddr_t *ret, caddr_t fmt, ...) 10067c478bd9Sstevel@tonic-gate { 1007*355d6bb5Sswilcox int len; 1008*355d6bb5Sswilcox caddr_t buffer; 1009*355d6bb5Sswilcox va_list ap; 10107c478bd9Sstevel@tonic-gate 1011*355d6bb5Sswilcox va_start(ap, fmt); 1012*355d6bb5Sswilcox len = vsnprintf(NULL, 0, fmt, ap); 1013*355d6bb5Sswilcox va_end(ap); 1014*355d6bb5Sswilcox 1015*355d6bb5Sswilcox buffer = malloc((len + 1) * sizeof (char)); 1016*355d6bb5Sswilcox if (buffer == NULL) { 1017*355d6bb5Sswilcox errexit("Out of memory in asprintf\n"); 1018*355d6bb5Sswilcox /* NOTREACHED */ 1019*355d6bb5Sswilcox } 1020*355d6bb5Sswilcox 1021*355d6bb5Sswilcox va_start(ap, fmt); 1022*355d6bb5Sswilcox (void) vsnprintf(buffer, len + 1, fmt, ap); 1023*355d6bb5Sswilcox va_end(ap); 1024*355d6bb5Sswilcox 1025*355d6bb5Sswilcox *ret = buffer; 1026*355d6bb5Sswilcox return (len); 10277c478bd9Sstevel@tonic-gate } 1028*355d6bb5Sswilcox 1029*355d6bb5Sswilcox /* 1030*355d6bb5Sswilcox * So we can take advantage of kernel routines in ufs_subr.c. 1031*355d6bb5Sswilcox */ 1032*355d6bb5Sswilcox /* PRINTFLIKE2 */ 10337c478bd9Sstevel@tonic-gate void 1034*355d6bb5Sswilcox cmn_err(int level, caddr_t fmt, ...) 10357c478bd9Sstevel@tonic-gate { 1036*355d6bb5Sswilcox va_list ap; 10377c478bd9Sstevel@tonic-gate 1038*355d6bb5Sswilcox va_start(ap, fmt); 10397c478bd9Sstevel@tonic-gate if (level == CE_PANIC) { 1040*355d6bb5Sswilcox (void) printf("INTERNAL INCONSISTENCY:"); 1041*355d6bb5Sswilcox verrexit(fmt, ap); 1042*355d6bb5Sswilcox } else { 1043*355d6bb5Sswilcox (void) vprintf(fmt, ap); 10447c478bd9Sstevel@tonic-gate } 1045*355d6bb5Sswilcox va_end(ap); 10467c478bd9Sstevel@tonic-gate } 10477c478bd9Sstevel@tonic-gate 10487c478bd9Sstevel@tonic-gate /* 10497c478bd9Sstevel@tonic-gate * Check to see if unraw version of name is already mounted. 1050*355d6bb5Sswilcox * Updates devstr with the device name if devstr is not NULL 1051*355d6bb5Sswilcox * and str_size is positive. 10527c478bd9Sstevel@tonic-gate */ 1053*355d6bb5Sswilcox int 1054*355d6bb5Sswilcox mounted(caddr_t name, caddr_t devstr, size_t str_size) 10557c478bd9Sstevel@tonic-gate { 1056*355d6bb5Sswilcox int found; 1057*355d6bb5Sswilcox struct mnttab *mntent; 10587c478bd9Sstevel@tonic-gate 1059*355d6bb5Sswilcox mntent = search_mnttab(NULL, unrawname(name), devstr, str_size); 1060*355d6bb5Sswilcox if (mntent == NULL) 1061*355d6bb5Sswilcox return (M_NOMNT); 1062*355d6bb5Sswilcox 1063*355d6bb5Sswilcox /* 1064*355d6bb5Sswilcox * It's mounted. With or without write access? 1065*355d6bb5Sswilcox */ 1066*355d6bb5Sswilcox if (hasmntopt(mntent, MNTOPT_RO) != 0) 1067*355d6bb5Sswilcox found = M_RO; /* mounted as RO */ 1068*355d6bb5Sswilcox else 1069*355d6bb5Sswilcox found = M_RW; /* mounted as R/W */ 1070*355d6bb5Sswilcox 1071*355d6bb5Sswilcox if (mount_point == NULL) { 1072*355d6bb5Sswilcox mount_point = strdup(mntent->mnt_mountp); 1073*355d6bb5Sswilcox if (mount_point == NULL) { 1074*355d6bb5Sswilcox errexit("fsck: memory allocation failure: %s", 1075*355d6bb5Sswilcox strerror(errno)); 1076*355d6bb5Sswilcox /* NOTREACHED */ 10777c478bd9Sstevel@tonic-gate } 1078*355d6bb5Sswilcox 1079*355d6bb5Sswilcox if (devstr != NULL && str_size > 0) 1080*355d6bb5Sswilcox (void) strlcpy(devstr, mntent->mnt_special, str_size); 10817c478bd9Sstevel@tonic-gate } 1082*355d6bb5Sswilcox 10837c478bd9Sstevel@tonic-gate return (found); 10847c478bd9Sstevel@tonic-gate } 10857c478bd9Sstevel@tonic-gate 10867c478bd9Sstevel@tonic-gate /* 10877c478bd9Sstevel@tonic-gate * Check to see if name corresponds to an entry in vfstab, and that the entry 10887c478bd9Sstevel@tonic-gate * does not have option ro. 10897c478bd9Sstevel@tonic-gate */ 1090*355d6bb5Sswilcox int 1091*355d6bb5Sswilcox writable(caddr_t name) 10927c478bd9Sstevel@tonic-gate { 10937c478bd9Sstevel@tonic-gate int rw = 1; 1094*355d6bb5Sswilcox struct vfstab vfsbuf, vfskey; 10957c478bd9Sstevel@tonic-gate FILE *vfstab; 10967c478bd9Sstevel@tonic-gate 10977c478bd9Sstevel@tonic-gate vfstab = fopen(VFSTAB, "r"); 10987c478bd9Sstevel@tonic-gate if (vfstab == NULL) { 1099*355d6bb5Sswilcox (void) printf("can't open %s\n", VFSTAB); 11007c478bd9Sstevel@tonic-gate return (1); 11017c478bd9Sstevel@tonic-gate } 1102*355d6bb5Sswilcox (void) memset((void *)&vfskey, 0, sizeof (vfskey)); 1103*355d6bb5Sswilcox vfsnull(&vfskey); 1104*355d6bb5Sswilcox vfskey.vfs_special = unrawname(name); 1105*355d6bb5Sswilcox vfskey.vfs_fstype = MNTTYPE_UFS; 1106*355d6bb5Sswilcox if ((getvfsany(vfstab, &vfsbuf, &vfskey) == 0) && 11077c478bd9Sstevel@tonic-gate (hasvfsopt(&vfsbuf, MNTOPT_RO))) { 11087c478bd9Sstevel@tonic-gate rw = 0; 11097c478bd9Sstevel@tonic-gate } 1110*355d6bb5Sswilcox (void) fclose(vfstab); 11117c478bd9Sstevel@tonic-gate return (rw); 11127c478bd9Sstevel@tonic-gate } 11137c478bd9Sstevel@tonic-gate 11147c478bd9Sstevel@tonic-gate /* 11157c478bd9Sstevel@tonic-gate * debugclean 11167c478bd9Sstevel@tonic-gate */ 1117*355d6bb5Sswilcox static void 1118*355d6bb5Sswilcox debugclean(void) 11197c478bd9Sstevel@tonic-gate { 1120*355d6bb5Sswilcox if (!debug) 11217c478bd9Sstevel@tonic-gate return; 11227c478bd9Sstevel@tonic-gate 11237c478bd9Sstevel@tonic-gate if ((iscorrupt == 0) && (isdirty == 0)) 11247c478bd9Sstevel@tonic-gate return; 11257c478bd9Sstevel@tonic-gate 1126*355d6bb5Sswilcox if ((sblock.fs_clean == FSSTABLE) || (sblock.fs_clean == FSCLEAN) || 1127*355d6bb5Sswilcox (sblock.fs_clean == FSLOG && islog && islogok) || 1128*355d6bb5Sswilcox ((FSOKAY == (sblock.fs_state + sblock.fs_time)) && !errorlocked)) 11297c478bd9Sstevel@tonic-gate return; 11307c478bd9Sstevel@tonic-gate 1131*355d6bb5Sswilcox (void) printf("WARNING: inconsistencies detected on %s filesystem %s\n", 11327c478bd9Sstevel@tonic-gate sblock.fs_clean == FSSTABLE ? "stable" : 11337c478bd9Sstevel@tonic-gate sblock.fs_clean == FSLOG ? "logging" : 1134*355d6bb5Sswilcox sblock.fs_clean == FSFIX ? "being fixed" : "clean", 1135*355d6bb5Sswilcox devname); 11367c478bd9Sstevel@tonic-gate } 11377c478bd9Sstevel@tonic-gate 11387c478bd9Sstevel@tonic-gate /* 11397c478bd9Sstevel@tonic-gate * updateclean 11407c478bd9Sstevel@tonic-gate * Carefully and transparently update the clean flag. 1141*355d6bb5Sswilcox * 1142*355d6bb5Sswilcox * `iscorrupt' has to be in its final state before this is called. 11437c478bd9Sstevel@tonic-gate */ 1144*355d6bb5Sswilcox int 1145*355d6bb5Sswilcox updateclean(void) 1146*355d6bb5Sswilcox { 1147*355d6bb5Sswilcox int freedlog = 0; 1148*355d6bb5Sswilcox struct bufarea cleanbuf; 1149*355d6bb5Sswilcox size_t size; 1150*355d6bb5Sswilcox ssize_t io_res; 1151*355d6bb5Sswilcox diskaddr_t bno; 1152*355d6bb5Sswilcox char fsclean; 1153*355d6bb5Sswilcox int fsreclaim; 1154*355d6bb5Sswilcox char fsflags; 1155*355d6bb5Sswilcox int flags_ok; 1156*355d6bb5Sswilcox daddr32_t fslogbno; 11577c478bd9Sstevel@tonic-gate offset_t sblkoff; 11587c478bd9Sstevel@tonic-gate time_t t; 11597c478bd9Sstevel@tonic-gate 11607c478bd9Sstevel@tonic-gate /* 11617c478bd9Sstevel@tonic-gate * debug stuff 11627c478bd9Sstevel@tonic-gate */ 11637c478bd9Sstevel@tonic-gate debugclean(); 11647c478bd9Sstevel@tonic-gate 11657c478bd9Sstevel@tonic-gate /* 11667c478bd9Sstevel@tonic-gate * set fsclean to its appropriate value 11677c478bd9Sstevel@tonic-gate */ 11687c478bd9Sstevel@tonic-gate fslogbno = sblock.fs_logbno; 11697c478bd9Sstevel@tonic-gate fsclean = sblock.fs_clean; 11707c478bd9Sstevel@tonic-gate fsreclaim = sblock.fs_reclaim; 11717c478bd9Sstevel@tonic-gate fsflags = sblock.fs_flags; 1172*355d6bb5Sswilcox if (FSOKAY != (sblock.fs_state + sblock.fs_time) && !errorlocked) { 11737c478bd9Sstevel@tonic-gate fsclean = FSACTIVE; 1174*355d6bb5Sswilcox } 1175*355d6bb5Sswilcox /* 1176*355d6bb5Sswilcox * If ufs log is not okay, note that we need to clear it. 1177*355d6bb5Sswilcox */ 1178*355d6bb5Sswilcox examinelog(sblock.fs_logbno, NULL); 11797c478bd9Sstevel@tonic-gate if (fslogbno && !(islog && islogok)) { 11807c478bd9Sstevel@tonic-gate fsclean = FSACTIVE; 11817c478bd9Sstevel@tonic-gate fslogbno = 0; 11827c478bd9Sstevel@tonic-gate } 11837c478bd9Sstevel@tonic-gate 11847c478bd9Sstevel@tonic-gate /* 11857c478bd9Sstevel@tonic-gate * if necessary, update fs_clean and fs_state 11867c478bd9Sstevel@tonic-gate */ 11877c478bd9Sstevel@tonic-gate switch (fsclean) { 11887c478bd9Sstevel@tonic-gate 11897c478bd9Sstevel@tonic-gate case FSACTIVE: 11907c478bd9Sstevel@tonic-gate if (!iscorrupt) { 11917c478bd9Sstevel@tonic-gate fsclean = FSSTABLE; 11927c478bd9Sstevel@tonic-gate fsreclaim = 0; 11937c478bd9Sstevel@tonic-gate } 11947c478bd9Sstevel@tonic-gate break; 11957c478bd9Sstevel@tonic-gate 11967c478bd9Sstevel@tonic-gate case FSCLEAN: 11977c478bd9Sstevel@tonic-gate case FSSTABLE: 1198*355d6bb5Sswilcox if (iscorrupt) { 11997c478bd9Sstevel@tonic-gate fsclean = FSACTIVE; 1200*355d6bb5Sswilcox } else { 12017c478bd9Sstevel@tonic-gate fsreclaim = 0; 1202*355d6bb5Sswilcox } 12037c478bd9Sstevel@tonic-gate break; 12047c478bd9Sstevel@tonic-gate 12057c478bd9Sstevel@tonic-gate case FSLOG: 1206*355d6bb5Sswilcox if (iscorrupt) { 12077c478bd9Sstevel@tonic-gate fsclean = FSACTIVE; 1208*355d6bb5Sswilcox } else if (!islog || fslogbno == 0) { 12097c478bd9Sstevel@tonic-gate fsclean = FSSTABLE; 12107c478bd9Sstevel@tonic-gate fsreclaim = 0; 1211*355d6bb5Sswilcox } else if (fflag) { 1212*355d6bb5Sswilcox fsreclaim = 0; 1213*355d6bb5Sswilcox } 12147c478bd9Sstevel@tonic-gate break; 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate case FSFIX: 12177c478bd9Sstevel@tonic-gate fsclean = FSBAD; 12187c478bd9Sstevel@tonic-gate if (errorlocked && !iscorrupt) { 1219*355d6bb5Sswilcox fsclean = islog ? FSLOG : FSCLEAN; 12207c478bd9Sstevel@tonic-gate } 12217c478bd9Sstevel@tonic-gate break; 12227c478bd9Sstevel@tonic-gate 12237c478bd9Sstevel@tonic-gate default: 1224*355d6bb5Sswilcox if (iscorrupt) { 12257c478bd9Sstevel@tonic-gate fsclean = FSACTIVE; 1226*355d6bb5Sswilcox } else { 12277c478bd9Sstevel@tonic-gate fsclean = FSSTABLE; 12287c478bd9Sstevel@tonic-gate fsreclaim = 0; 12297c478bd9Sstevel@tonic-gate } 12307c478bd9Sstevel@tonic-gate } 12317c478bd9Sstevel@tonic-gate 12327c478bd9Sstevel@tonic-gate if (largefile_count > 0) 12337c478bd9Sstevel@tonic-gate fsflags |= FSLARGEFILES; 12347c478bd9Sstevel@tonic-gate else 12357c478bd9Sstevel@tonic-gate fsflags &= ~FSLARGEFILES; 12367c478bd9Sstevel@tonic-gate 12377c478bd9Sstevel@tonic-gate /* 1238*355d6bb5Sswilcox * If the only flag difference is that the superblock thinks 1239*355d6bb5Sswilcox * there are largefiles, but we didn't find any, then ignore 1240*355d6bb5Sswilcox * the discrepancy. The kernel never clears the flag, it just 1241*355d6bb5Sswilcox * sets it whenever a largefile is created. Since it is harmless 1242*355d6bb5Sswilcox * to have the flag set when it's not actually true, that by 1243*355d6bb5Sswilcox * itself is not grounds for declaring the superblock to be 1244*355d6bb5Sswilcox * in the wrong state. 1245*355d6bb5Sswilcox * 1246*355d6bb5Sswilcox * This could, in theory, prevent a filesystem from being 1247*355d6bb5Sswilcox * mounted, if the existing superblock claims such files are 1248*355d6bb5Sswilcox * out there and the user uses the nolargefiles option. So, 1249*355d6bb5Sswilcox * if we were forced to scan the filesystem, go ahead and 1250*355d6bb5Sswilcox * take FSLARGEFILES into account as well. 12517c478bd9Sstevel@tonic-gate */ 1252*355d6bb5Sswilcox if (fflag) 1253*355d6bb5Sswilcox flags_ok = 0; 1254*355d6bb5Sswilcox else 1255*355d6bb5Sswilcox flags_ok = (sblock.fs_flags & ~FSLARGEFILES) == fsflags; 1256*355d6bb5Sswilcox 12577c478bd9Sstevel@tonic-gate if (debug) 1258*355d6bb5Sswilcox (void) printf( 1259*355d6bb5Sswilcox "** largefile count=%d, fs.fs_flags=%x, flags_ok %d\n", 1260*355d6bb5Sswilcox largefile_count, sblock.fs_flags, flags_ok); 12617c478bd9Sstevel@tonic-gate 1262*355d6bb5Sswilcox /* 1263*355d6bb5Sswilcox * If fs is unchanged, do nothing. 1264*355d6bb5Sswilcox */ 1265*355d6bb5Sswilcox if ((!isdirty) && (flags_ok) && 12667c478bd9Sstevel@tonic-gate (fslogbno == sblock.fs_logbno) && 1267*355d6bb5Sswilcox (sblock.fs_clean == fsclean) && 1268*355d6bb5Sswilcox (sblock.fs_reclaim == fsreclaim) && 12697c478bd9Sstevel@tonic-gate (FSOKAY == (sblock.fs_state + sblock.fs_time))) { 12707c478bd9Sstevel@tonic-gate if (errorlocked) { 12717c478bd9Sstevel@tonic-gate if (!do_errorlock(LOCKFS_ULOCK)) 12727c478bd9Sstevel@tonic-gate pwarn( 12737c478bd9Sstevel@tonic-gate "updateclean(unchanged): unlock(LOCKFS_ULOCK) failed\n"); 12747c478bd9Sstevel@tonic-gate } 1275*355d6bb5Sswilcox return (freedlog); 12767c478bd9Sstevel@tonic-gate } 12777c478bd9Sstevel@tonic-gate 12787c478bd9Sstevel@tonic-gate /* 12797c478bd9Sstevel@tonic-gate * if user allows, update superblock state 12807c478bd9Sstevel@tonic-gate */ 1281*355d6bb5Sswilcox if (debug) { 1282*355d6bb5Sswilcox (void) printf( 1283*355d6bb5Sswilcox "superblock: flags 0x%x logbno %d clean %d reclaim %d state 0x%x\n", 1284*355d6bb5Sswilcox sblock.fs_flags, sblock.fs_logbno, 1285*355d6bb5Sswilcox sblock.fs_clean, sblock.fs_reclaim, 1286*355d6bb5Sswilcox sblock.fs_state + sblock.fs_time); 1287*355d6bb5Sswilcox (void) printf( 1288*355d6bb5Sswilcox "calculated: flags 0x%x logbno %d clean %d reclaim %d state 0x%x\n", 1289*355d6bb5Sswilcox fsflags, fslogbno, fsclean, fsreclaim, FSOKAY); 1290*355d6bb5Sswilcox } 1291*355d6bb5Sswilcox if (!isdirty && !preen && !rerun && 12927c478bd9Sstevel@tonic-gate (reply("FILE SYSTEM STATE IN SUPERBLOCK IS WRONG; FIX") == 0)) 1293*355d6bb5Sswilcox return (freedlog); 12947c478bd9Sstevel@tonic-gate 12957c478bd9Sstevel@tonic-gate (void) time(&t); 12967c478bd9Sstevel@tonic-gate sblock.fs_time = (time32_t)t; 12977c478bd9Sstevel@tonic-gate if (debug) 12987c478bd9Sstevel@tonic-gate printclean(); 1299*355d6bb5Sswilcox 1300*355d6bb5Sswilcox if (sblock.fs_logbno != fslogbno) { 1301*355d6bb5Sswilcox examinelog(sblock.fs_logbno, &freelogblk); 1302*355d6bb5Sswilcox freedlog++; 1303*355d6bb5Sswilcox } 1304*355d6bb5Sswilcox 13057c478bd9Sstevel@tonic-gate sblock.fs_logbno = fslogbno; 13067c478bd9Sstevel@tonic-gate sblock.fs_clean = fsclean; 13077c478bd9Sstevel@tonic-gate sblock.fs_state = FSOKAY - (long)sblock.fs_time; 13087c478bd9Sstevel@tonic-gate sblock.fs_reclaim = fsreclaim; 13097c478bd9Sstevel@tonic-gate sblock.fs_flags = fsflags; 13107c478bd9Sstevel@tonic-gate 13117c478bd9Sstevel@tonic-gate /* 13127c478bd9Sstevel@tonic-gate * if superblock can't be written, return 13137c478bd9Sstevel@tonic-gate */ 13147c478bd9Sstevel@tonic-gate if (fswritefd < 0) 1315*355d6bb5Sswilcox return (freedlog); 13167c478bd9Sstevel@tonic-gate 13177c478bd9Sstevel@tonic-gate /* 1318*355d6bb5Sswilcox * Read private copy of superblock, update clean flag, and write it. 13197c478bd9Sstevel@tonic-gate */ 13207c478bd9Sstevel@tonic-gate bno = sblk.b_bno; 13217c478bd9Sstevel@tonic-gate size = sblk.b_size; 13227c478bd9Sstevel@tonic-gate 13237c478bd9Sstevel@tonic-gate sblkoff = ldbtob(bno); 13247c478bd9Sstevel@tonic-gate 13257c478bd9Sstevel@tonic-gate if ((cleanbuf.b_un.b_buf = malloc(size)) == NULL) 13267c478bd9Sstevel@tonic-gate errexit("out of memory"); 1327*355d6bb5Sswilcox if (llseek(fsreadfd, sblkoff, 0) == -1) { 1328*355d6bb5Sswilcox (void) printf("COULD NOT SEEK TO SUPERBLOCK AT %lld: %s\n", 1329*355d6bb5Sswilcox (longlong_t)bno, strerror(errno)); 1330*355d6bb5Sswilcox goto out; 1331*355d6bb5Sswilcox } 13327c478bd9Sstevel@tonic-gate 1333*355d6bb5Sswilcox if ((io_res = read(fsreadfd, cleanbuf.b_un.b_buf, size)) != size) { 1334*355d6bb5Sswilcox report_io_prob("READ FROM", bno, size, io_res); 1335*355d6bb5Sswilcox goto out; 1336*355d6bb5Sswilcox } 13377c478bd9Sstevel@tonic-gate 13387c478bd9Sstevel@tonic-gate cleanbuf.b_un.b_fs->fs_logbno = sblock.fs_logbno; 13397c478bd9Sstevel@tonic-gate cleanbuf.b_un.b_fs->fs_clean = sblock.fs_clean; 13407c478bd9Sstevel@tonic-gate cleanbuf.b_un.b_fs->fs_state = sblock.fs_state; 13417c478bd9Sstevel@tonic-gate cleanbuf.b_un.b_fs->fs_time = sblock.fs_time; 13427c478bd9Sstevel@tonic-gate cleanbuf.b_un.b_fs->fs_reclaim = sblock.fs_reclaim; 13437c478bd9Sstevel@tonic-gate cleanbuf.b_un.b_fs->fs_flags = sblock.fs_flags; 13447c478bd9Sstevel@tonic-gate 1345*355d6bb5Sswilcox if (llseek(fswritefd, sblkoff, 0) == -1) { 1346*355d6bb5Sswilcox (void) printf("COULD NOT SEEK TO SUPERBLOCK AT %lld: %s\n", 1347*355d6bb5Sswilcox (longlong_t)bno, strerror(errno)); 1348*355d6bb5Sswilcox goto out; 1349*355d6bb5Sswilcox } 1350*355d6bb5Sswilcox 1351*355d6bb5Sswilcox if ((io_res = write(fswritefd, cleanbuf.b_un.b_buf, size)) != size) { 1352*355d6bb5Sswilcox report_io_prob("WRITE TO", bno, size, io_res); 1353*355d6bb5Sswilcox goto out; 1354*355d6bb5Sswilcox } 13557c478bd9Sstevel@tonic-gate 13567c478bd9Sstevel@tonic-gate /* 13577c478bd9Sstevel@tonic-gate * 1208040 13587c478bd9Sstevel@tonic-gate * If we had to use -b to grab an alternate superblock, then we 13597c478bd9Sstevel@tonic-gate * likely had to do so because of unacceptable differences between 1360*355d6bb5Sswilcox * the main and alternate superblocks. So, we had better update 13617c478bd9Sstevel@tonic-gate * the alternate superblock as well, or we'll just fail again 13627c478bd9Sstevel@tonic-gate * the next time we attempt to run fsck! 13637c478bd9Sstevel@tonic-gate */ 1364*355d6bb5Sswilcox if (bflag != 0) { 1365*355d6bb5Sswilcox write_altsb(fswritefd); 13667c478bd9Sstevel@tonic-gate } 13677c478bd9Sstevel@tonic-gate 13687c478bd9Sstevel@tonic-gate if (errorlocked) { 13697c478bd9Sstevel@tonic-gate if (!do_errorlock(LOCKFS_ULOCK)) 13707c478bd9Sstevel@tonic-gate pwarn( 13717c478bd9Sstevel@tonic-gate "updateclean(changed): unlock(LOCKFS_ULOCK) failed\n"); 13727c478bd9Sstevel@tonic-gate } 1373*355d6bb5Sswilcox 1374*355d6bb5Sswilcox out: 1375*355d6bb5Sswilcox if (cleanbuf.b_un.b_buf != NULL) { 1376*355d6bb5Sswilcox free((void *)cleanbuf.b_un.b_buf); 1377*355d6bb5Sswilcox } 1378*355d6bb5Sswilcox 1379*355d6bb5Sswilcox return (freedlog); 1380*355d6bb5Sswilcox } 1381*355d6bb5Sswilcox 1382*355d6bb5Sswilcox static void 1383*355d6bb5Sswilcox report_io_prob(caddr_t what, diskaddr_t bno, size_t expected, ssize_t failure) 1384*355d6bb5Sswilcox { 1385*355d6bb5Sswilcox if (failure < 0) 1386*355d6bb5Sswilcox (void) printf("COULD NOT %s SUPERBLOCK AT %d: %s\n", 1387*355d6bb5Sswilcox what, (int)bno, strerror(errno)); 1388*355d6bb5Sswilcox else if (failure == 0) 1389*355d6bb5Sswilcox (void) printf("COULD NOT %s SUPERBLOCK AT %d: EOF\n", 1390*355d6bb5Sswilcox what, (int)bno); 1391*355d6bb5Sswilcox else 1392*355d6bb5Sswilcox (void) printf("SHORT %s SUPERBLOCK AT %d: %u out of %u bytes\n", 1393*355d6bb5Sswilcox what, (int)bno, (unsigned)failure, (unsigned)expected); 13947c478bd9Sstevel@tonic-gate } 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate /* 13977c478bd9Sstevel@tonic-gate * print out clean info 13987c478bd9Sstevel@tonic-gate */ 1399*355d6bb5Sswilcox void 1400*355d6bb5Sswilcox printclean(void) 14017c478bd9Sstevel@tonic-gate { 1402*355d6bb5Sswilcox caddr_t s; 14037c478bd9Sstevel@tonic-gate 14047c478bd9Sstevel@tonic-gate if (FSOKAY != (sblock.fs_state + sblock.fs_time) && !errorlocked) 14057c478bd9Sstevel@tonic-gate s = "unknown"; 14067c478bd9Sstevel@tonic-gate else 14077c478bd9Sstevel@tonic-gate switch (sblock.fs_clean) { 14087c478bd9Sstevel@tonic-gate 14097c478bd9Sstevel@tonic-gate case FSACTIVE: 14107c478bd9Sstevel@tonic-gate s = "active"; 14117c478bd9Sstevel@tonic-gate break; 14127c478bd9Sstevel@tonic-gate 14137c478bd9Sstevel@tonic-gate case FSCLEAN: 14147c478bd9Sstevel@tonic-gate s = "clean"; 14157c478bd9Sstevel@tonic-gate break; 14167c478bd9Sstevel@tonic-gate 14177c478bd9Sstevel@tonic-gate case FSSTABLE: 14187c478bd9Sstevel@tonic-gate s = "stable"; 14197c478bd9Sstevel@tonic-gate break; 14207c478bd9Sstevel@tonic-gate 14217c478bd9Sstevel@tonic-gate case FSLOG: 14227c478bd9Sstevel@tonic-gate s = "logging"; 14237c478bd9Sstevel@tonic-gate break; 14247c478bd9Sstevel@tonic-gate 14257c478bd9Sstevel@tonic-gate case FSBAD: 14267c478bd9Sstevel@tonic-gate s = "is bad"; 14277c478bd9Sstevel@tonic-gate break; 14287c478bd9Sstevel@tonic-gate 14297c478bd9Sstevel@tonic-gate case FSFIX: 14307c478bd9Sstevel@tonic-gate s = "being fixed"; 14317c478bd9Sstevel@tonic-gate break; 14327c478bd9Sstevel@tonic-gate 14337c478bd9Sstevel@tonic-gate default: 14347c478bd9Sstevel@tonic-gate s = "unknown"; 14357c478bd9Sstevel@tonic-gate } 14367c478bd9Sstevel@tonic-gate 14377c478bd9Sstevel@tonic-gate if (preen) 14387c478bd9Sstevel@tonic-gate pwarn("is %s.\n", s); 14397c478bd9Sstevel@tonic-gate else 1440*355d6bb5Sswilcox (void) printf("** %s is %s.\n", devname, s); 14417c478bd9Sstevel@tonic-gate } 14427c478bd9Sstevel@tonic-gate 1443*355d6bb5Sswilcox int 1444*355d6bb5Sswilcox is_errorlocked(caddr_t fs) 14457c478bd9Sstevel@tonic-gate { 1446*355d6bb5Sswilcox int retval; 1447*355d6bb5Sswilcox struct stat64 statb; 1448*355d6bb5Sswilcox caddr_t mountp; 1449*355d6bb5Sswilcox struct mnttab *mntent; 14507c478bd9Sstevel@tonic-gate 1451*355d6bb5Sswilcox retval = 0; 14527c478bd9Sstevel@tonic-gate 14537c478bd9Sstevel@tonic-gate if (!fs) 14547c478bd9Sstevel@tonic-gate return (0); 14557c478bd9Sstevel@tonic-gate 14567c478bd9Sstevel@tonic-gate if (stat64(fs, &statb) < 0) 14577c478bd9Sstevel@tonic-gate return (0); 14587c478bd9Sstevel@tonic-gate 14597c478bd9Sstevel@tonic-gate if (S_ISDIR(statb.st_mode)) { 14607c478bd9Sstevel@tonic-gate mountp = fs; 14617c478bd9Sstevel@tonic-gate } else if (S_ISBLK(statb.st_mode) || S_ISCHR(statb.st_mode)) { 1462*355d6bb5Sswilcox mntent = search_mnttab(NULL, fs, NULL, 0); 1463*355d6bb5Sswilcox if (mntent == NULL) 1464*355d6bb5Sswilcox return (0); 1465*355d6bb5Sswilcox mountp = mntent->mnt_mountp; 1466*355d6bb5Sswilcox if (mountp == NULL) /* theoretically a can't-happen */ 14677c478bd9Sstevel@tonic-gate return (0); 14687c478bd9Sstevel@tonic-gate } else { 14697c478bd9Sstevel@tonic-gate return (0); 14707c478bd9Sstevel@tonic-gate } 14717c478bd9Sstevel@tonic-gate 1472*355d6bb5Sswilcox /* 1473*355d6bb5Sswilcox * From here on, must `goto out' to avoid memory leakage. 1474*355d6bb5Sswilcox */ 1475*355d6bb5Sswilcox 1476*355d6bb5Sswilcox if (elock_combuf == NULL) 14777c478bd9Sstevel@tonic-gate elock_combuf = 1478*355d6bb5Sswilcox (caddr_t)calloc(LOCKFS_MAXCOMMENTLEN, sizeof (char)); 1479*355d6bb5Sswilcox else 14807c478bd9Sstevel@tonic-gate elock_combuf = 1481*355d6bb5Sswilcox (caddr_t)realloc(elock_combuf, LOCKFS_MAXCOMMENTLEN); 14827c478bd9Sstevel@tonic-gate 14837c478bd9Sstevel@tonic-gate if (elock_combuf == NULL) 1484*355d6bb5Sswilcox goto out; 14857c478bd9Sstevel@tonic-gate 1486*355d6bb5Sswilcox (void) memset((void *)elock_combuf, 0, LOCKFS_MAXCOMMENTLEN); 1487*355d6bb5Sswilcox 1488*355d6bb5Sswilcox if (elock_mountp != NULL) { 1489*355d6bb5Sswilcox free(elock_mountp); 1490*355d6bb5Sswilcox } 14917c478bd9Sstevel@tonic-gate 14927c478bd9Sstevel@tonic-gate elock_mountp = strdup(mountp); 1493*355d6bb5Sswilcox if (elock_mountp == NULL) 1494*355d6bb5Sswilcox goto out; 14957c478bd9Sstevel@tonic-gate 14967c478bd9Sstevel@tonic-gate if (mountfd < 0) { 14977c478bd9Sstevel@tonic-gate if ((mountfd = open64(mountp, O_RDONLY)) == -1) 1498*355d6bb5Sswilcox goto out; 14997c478bd9Sstevel@tonic-gate } 15007c478bd9Sstevel@tonic-gate 1501*355d6bb5Sswilcox if (lfp == NULL) { 15027c478bd9Sstevel@tonic-gate lfp = (struct lockfs *)malloc(sizeof (struct lockfs)); 1503*355d6bb5Sswilcox if (lfp == NULL) 1504*355d6bb5Sswilcox goto out; 1505*355d6bb5Sswilcox (void) memset((void *)lfp, 0, sizeof (struct lockfs)); 15067c478bd9Sstevel@tonic-gate } 15077c478bd9Sstevel@tonic-gate 15087c478bd9Sstevel@tonic-gate lfp->lf_comlen = LOCKFS_MAXCOMMENTLEN; 15097c478bd9Sstevel@tonic-gate lfp->lf_comment = elock_combuf; 15107c478bd9Sstevel@tonic-gate 15117c478bd9Sstevel@tonic-gate if (ioctl(mountfd, _FIOLFSS, lfp) == -1) 1512*355d6bb5Sswilcox goto out; 1513*355d6bb5Sswilcox 1514*355d6bb5Sswilcox /* 1515*355d6bb5Sswilcox * lint believes that the ioctl() (or any other function 1516*355d6bb5Sswilcox * taking lfp as an arg) could free lfp. This is not the 1517*355d6bb5Sswilcox * case, however. 1518*355d6bb5Sswilcox */ 1519*355d6bb5Sswilcox retval = LOCKFS_IS_ELOCK(lfp); 15207c478bd9Sstevel@tonic-gate 1521*355d6bb5Sswilcox out: 1522*355d6bb5Sswilcox return (retval); 15237c478bd9Sstevel@tonic-gate } 15247c478bd9Sstevel@tonic-gate 1525*355d6bb5Sswilcox /* 1526*355d6bb5Sswilcox * Given a name which is known to be a directory, see if it appears 1527*355d6bb5Sswilcox * in the vfstab. If so, return the entry's block (special) device 1528*355d6bb5Sswilcox * field via devstr. 1529*355d6bb5Sswilcox */ 1530*355d6bb5Sswilcox int 1531*355d6bb5Sswilcox check_vfstab(caddr_t name, caddr_t devstr, size_t str_size) 1532*355d6bb5Sswilcox { 1533*355d6bb5Sswilcox return (NULL != search_vfstab(name, NULL, devstr, str_size)); 1534*355d6bb5Sswilcox } 15357c478bd9Sstevel@tonic-gate 1536*355d6bb5Sswilcox /* 1537*355d6bb5Sswilcox * Given a name which is known to be a directory, see if it appears 1538*355d6bb5Sswilcox * in the mnttab. If so, return the entry's block (special) device 1539*355d6bb5Sswilcox * field via devstr. 1540*355d6bb5Sswilcox */ 1541*355d6bb5Sswilcox int 1542*355d6bb5Sswilcox check_mnttab(caddr_t name, caddr_t devstr, size_t str_size) 1543*355d6bb5Sswilcox { 1544*355d6bb5Sswilcox return (NULL != search_mnttab(name, NULL, devstr, str_size)); 15457c478bd9Sstevel@tonic-gate } 15467c478bd9Sstevel@tonic-gate 1547*355d6bb5Sswilcox /* 1548*355d6bb5Sswilcox * Search for mount point and/or special device in the given file. 1549*355d6bb5Sswilcox * The first matching entry is returned. 1550*355d6bb5Sswilcox * 1551*355d6bb5Sswilcox * If an entry is found and str_size is greater than zero, then 1552*355d6bb5Sswilcox * up to size_str bytes of the special device name from the entry 1553*355d6bb5Sswilcox * are copied to devstr. 1554*355d6bb5Sswilcox */ 1555*355d6bb5Sswilcox 1556*355d6bb5Sswilcox #define SEARCH_TAB_BODY(st_type, st_file, st_mount, st_special, \ 1557*355d6bb5Sswilcox st_nuller, st_init, st_searcher) \ 1558*355d6bb5Sswilcox { \ 1559*355d6bb5Sswilcox FILE *fp; \ 1560*355d6bb5Sswilcox struct st_type *retval = NULL; \ 1561*355d6bb5Sswilcox struct st_type key; \ 1562*355d6bb5Sswilcox static struct st_type buffer; \ 1563*355d6bb5Sswilcox \ 1564*355d6bb5Sswilcox /* LINTED ``assigned value never used'' */ \ 1565*355d6bb5Sswilcox st_nuller(&key); \ 1566*355d6bb5Sswilcox key.st_mount = mountp; \ 1567*355d6bb5Sswilcox key.st_special = special; \ 1568*355d6bb5Sswilcox st_init; \ 1569*355d6bb5Sswilcox \ 1570*355d6bb5Sswilcox if ((fp = fopen(st_file, "r")) == NULL) \ 1571*355d6bb5Sswilcox return (NULL); \ 1572*355d6bb5Sswilcox \ 1573*355d6bb5Sswilcox if (st_searcher(fp, &buffer, &key) == 0) { \ 1574*355d6bb5Sswilcox retval = &buffer; \ 1575*355d6bb5Sswilcox if (devstr != NULL && str_size > 0 && \ 1576*355d6bb5Sswilcox buffer.st_special != NULL) { \ 1577*355d6bb5Sswilcox (void) strlcpy(devstr, buffer.st_special, \ 1578*355d6bb5Sswilcox str_size); \ 1579*355d6bb5Sswilcox } \ 1580*355d6bb5Sswilcox } \ 1581*355d6bb5Sswilcox (void) fclose(fp); \ 1582*355d6bb5Sswilcox return (retval); \ 1583*355d6bb5Sswilcox } 1584*355d6bb5Sswilcox 1585*355d6bb5Sswilcox static struct vfstab * 1586*355d6bb5Sswilcox search_vfstab(caddr_t mountp, caddr_t special, caddr_t devstr, size_t str_size) 1587*355d6bb5Sswilcox SEARCH_TAB_BODY(vfstab, VFSTAB, vfs_mountp, vfs_special, vfsnull, 1588*355d6bb5Sswilcox (retval = retval), getvfsany) 1589*355d6bb5Sswilcox 1590*355d6bb5Sswilcox static struct mnttab * 1591*355d6bb5Sswilcox search_mnttab(caddr_t mountp, caddr_t special, caddr_t devstr, size_t str_size) 1592*355d6bb5Sswilcox SEARCH_TAB_BODY(mnttab, MNTTAB, mnt_mountp, mnt_special, mntnull, 1593*355d6bb5Sswilcox (key.mnt_fstype = MNTTYPE_UFS), getmntany) 1594*355d6bb5Sswilcox 1595*355d6bb5Sswilcox int 15967c478bd9Sstevel@tonic-gate do_errorlock(int lock_type) 15977c478bd9Sstevel@tonic-gate { 1598*355d6bb5Sswilcox caddr_t buf; 1599*355d6bb5Sswilcox time_t now; 1600*355d6bb5Sswilcox struct tm *local; 1601*355d6bb5Sswilcox int rc; 16027c478bd9Sstevel@tonic-gate 1603*355d6bb5Sswilcox if (elock_combuf == NULL) 16047c478bd9Sstevel@tonic-gate errexit("do_errorlock(%s, %d): unallocated elock_combuf\n", 1605*355d6bb5Sswilcox elock_mountp ? elock_mountp : "<null>", 1606*355d6bb5Sswilcox lock_type); 16077c478bd9Sstevel@tonic-gate 1608*355d6bb5Sswilcox if ((buf = (caddr_t)calloc(LOCKFS_MAXCOMMENTLEN, sizeof (char))) == 1609*355d6bb5Sswilcox NULL) { 16107c478bd9Sstevel@tonic-gate errexit("Couldn't alloc memory for temp. lock status buffer\n"); 1611*355d6bb5Sswilcox } 1612*355d6bb5Sswilcox if (lfp == NULL) { 16137c478bd9Sstevel@tonic-gate errexit("do_errorlock(%s, %d): lockfs status unallocated\n", 16147c478bd9Sstevel@tonic-gate elock_mountp, lock_type); 16157c478bd9Sstevel@tonic-gate } 16167c478bd9Sstevel@tonic-gate 1617*355d6bb5Sswilcox (void) memmove((void *)buf, (void *)elock_combuf, 1618*355d6bb5Sswilcox LOCKFS_MAXCOMMENTLEN-1); 16197c478bd9Sstevel@tonic-gate 16207c478bd9Sstevel@tonic-gate switch (lock_type) { 16217c478bd9Sstevel@tonic-gate case LOCKFS_ELOCK: 1622*355d6bb5Sswilcox /* 1623*355d6bb5Sswilcox * Note that if it is error-locked, we won't get an 1624*355d6bb5Sswilcox * error back if we try to error-lock it again. 1625*355d6bb5Sswilcox */ 16267c478bd9Sstevel@tonic-gate if (time(&now) != (time_t)-1) { 16277c478bd9Sstevel@tonic-gate if ((local = localtime(&now)) != NULL) 1628*355d6bb5Sswilcox (void) snprintf(buf, LOCKFS_MAXCOMMENTLEN, 16297c478bd9Sstevel@tonic-gate "%s [pid:%d fsck start:%02d/%02d/%02d %02d:%02d:%02d", 1630*355d6bb5Sswilcox elock_combuf, (int)pid, 1631*355d6bb5Sswilcox local->tm_mon + 1, local->tm_mday, 16327c478bd9Sstevel@tonic-gate (local->tm_year % 100), local->tm_hour, 16337c478bd9Sstevel@tonic-gate local->tm_min, local->tm_sec); 16347c478bd9Sstevel@tonic-gate else 1635*355d6bb5Sswilcox (void) snprintf(buf, LOCKFS_MAXCOMMENTLEN, 1636*355d6bb5Sswilcox "%s [fsck pid %d", elock_combuf, pid); 16377c478bd9Sstevel@tonic-gate 16387c478bd9Sstevel@tonic-gate } else { 1639*355d6bb5Sswilcox (void) snprintf(buf, LOCKFS_MAXCOMMENTLEN, 1640*355d6bb5Sswilcox "%s [fsck pid %d", elock_combuf, pid); 16417c478bd9Sstevel@tonic-gate } 16427c478bd9Sstevel@tonic-gate break; 16437c478bd9Sstevel@tonic-gate 16447c478bd9Sstevel@tonic-gate case LOCKFS_ULOCK: 16457c478bd9Sstevel@tonic-gate if (time(&now) != (time_t)-1) { 16467c478bd9Sstevel@tonic-gate if ((local = localtime(&now)) != NULL) { 1647*355d6bb5Sswilcox (void) snprintf(buf, LOCKFS_MAXCOMMENTLEN, 16487c478bd9Sstevel@tonic-gate "%s, done:%02d/%02d/%02d %02d:%02d:%02d]", 16497c478bd9Sstevel@tonic-gate elock_combuf, 1650*355d6bb5Sswilcox local->tm_mon + 1, local->tm_mday, 16517c478bd9Sstevel@tonic-gate (local->tm_year % 100), local->tm_hour, 16527c478bd9Sstevel@tonic-gate local->tm_min, local->tm_sec); 16537c478bd9Sstevel@tonic-gate } else { 1654*355d6bb5Sswilcox (void) snprintf(buf, LOCKFS_MAXCOMMENTLEN, 1655*355d6bb5Sswilcox "%s]", elock_combuf); 16567c478bd9Sstevel@tonic-gate } 16577c478bd9Sstevel@tonic-gate } else { 1658*355d6bb5Sswilcox (void) snprintf(buf, LOCKFS_MAXCOMMENTLEN, 1659*355d6bb5Sswilcox "%s]", elock_combuf); 16607c478bd9Sstevel@tonic-gate } 16617c478bd9Sstevel@tonic-gate if ((rc = ioctl(mountfd, _FIOLFSS, lfp)) == -1) { 1662*355d6bb5Sswilcox pwarn("do_errorlock: unlock failed: %s\n", 1663*355d6bb5Sswilcox strerror(errno)); 16647c478bd9Sstevel@tonic-gate goto out; 16657c478bd9Sstevel@tonic-gate } 16667c478bd9Sstevel@tonic-gate break; 16677c478bd9Sstevel@tonic-gate 16687c478bd9Sstevel@tonic-gate default: 16697c478bd9Sstevel@tonic-gate break; 16707c478bd9Sstevel@tonic-gate } 16717c478bd9Sstevel@tonic-gate 1672*355d6bb5Sswilcox (void) memmove((void *)elock_combuf, (void *)buf, 1673*355d6bb5Sswilcox LOCKFS_MAXCOMMENTLEN - 1); 16747c478bd9Sstevel@tonic-gate 1675*355d6bb5Sswilcox lfp->lf_lock = lock_type; 1676*355d6bb5Sswilcox lfp->lf_comlen = LOCKFS_MAXCOMMENTLEN; 1677*355d6bb5Sswilcox lfp->lf_comment = elock_combuf; 1678*355d6bb5Sswilcox lfp->lf_flags = 0; 1679*355d6bb5Sswilcox errno = 0; 16807c478bd9Sstevel@tonic-gate 16817c478bd9Sstevel@tonic-gate if ((rc = ioctl(mountfd, _FIOLFS, lfp)) == -1) { 16827c478bd9Sstevel@tonic-gate if (errno == EINVAL) { 16837c478bd9Sstevel@tonic-gate pwarn("Another fsck active?\n"); 16847c478bd9Sstevel@tonic-gate iscorrupt = 0; /* don't go away mad, just go away */ 16857c478bd9Sstevel@tonic-gate } else { 1686*355d6bb5Sswilcox pwarn("do_errorlock(lock_type:%d, %s) failed: %s\n", 1687*355d6bb5Sswilcox lock_type, elock_combuf, strerror(errno)); 16887c478bd9Sstevel@tonic-gate } 16897c478bd9Sstevel@tonic-gate } 16907c478bd9Sstevel@tonic-gate out: 1691*355d6bb5Sswilcox if (buf != NULL) { 1692*355d6bb5Sswilcox free((void *)buf); 1693*355d6bb5Sswilcox } 16947c478bd9Sstevel@tonic-gate 16957c478bd9Sstevel@tonic-gate return (rc != -1); 16967c478bd9Sstevel@tonic-gate } 16977c478bd9Sstevel@tonic-gate 16987c478bd9Sstevel@tonic-gate /* 1699*355d6bb5Sswilcox * Shadow inode support. To register a shadow with a client is to note 1700*355d6bb5Sswilcox * that an inode (the client) refers to the shadow. 17017c478bd9Sstevel@tonic-gate */ 17027c478bd9Sstevel@tonic-gate 17037c478bd9Sstevel@tonic-gate static struct shadowclients * 17047c478bd9Sstevel@tonic-gate newshadowclient(struct shadowclients *prev) 17057c478bd9Sstevel@tonic-gate { 17067c478bd9Sstevel@tonic-gate struct shadowclients *rc; 17077c478bd9Sstevel@tonic-gate 17087c478bd9Sstevel@tonic-gate rc = (struct shadowclients *)malloc(sizeof (*rc)); 17097c478bd9Sstevel@tonic-gate if (rc == NULL) 1710*355d6bb5Sswilcox errexit("newshadowclient: cannot malloc shadow client"); 17117c478bd9Sstevel@tonic-gate rc->next = prev; 17127c478bd9Sstevel@tonic-gate rc->nclients = 0; 17137c478bd9Sstevel@tonic-gate 1714*355d6bb5Sswilcox rc->client = (fsck_ino_t *)malloc(sizeof (fsck_ino_t) * 1715*355d6bb5Sswilcox maxshadowclients); 17167c478bd9Sstevel@tonic-gate if (rc->client == NULL) 1717*355d6bb5Sswilcox errexit("newshadowclient: cannot malloc client array"); 17187c478bd9Sstevel@tonic-gate return (rc); 17197c478bd9Sstevel@tonic-gate } 17207c478bd9Sstevel@tonic-gate 17217c478bd9Sstevel@tonic-gate void 1722*355d6bb5Sswilcox registershadowclient(fsck_ino_t shadow, fsck_ino_t client, 1723*355d6bb5Sswilcox struct shadowclientinfo **info) 17247c478bd9Sstevel@tonic-gate { 17257c478bd9Sstevel@tonic-gate struct shadowclientinfo *sci; 17267c478bd9Sstevel@tonic-gate struct shadowclients *scc; 17277c478bd9Sstevel@tonic-gate 1728*355d6bb5Sswilcox /* 1729*355d6bb5Sswilcox * Already have a record for this shadow? 1730*355d6bb5Sswilcox */ 1731*355d6bb5Sswilcox for (sci = *info; sci != NULL; sci = sci->next) 17327c478bd9Sstevel@tonic-gate if (sci->shadow == shadow) 17337c478bd9Sstevel@tonic-gate break; 17347c478bd9Sstevel@tonic-gate if (sci == NULL) { 1735*355d6bb5Sswilcox /* 1736*355d6bb5Sswilcox * It's a new shadow, add it to the list 1737*355d6bb5Sswilcox */ 17387c478bd9Sstevel@tonic-gate sci = (struct shadowclientinfo *)malloc(sizeof (*sci)); 17397c478bd9Sstevel@tonic-gate if (sci == NULL) 17407c478bd9Sstevel@tonic-gate errexit("registershadowclient: cannot malloc"); 17417c478bd9Sstevel@tonic-gate sci->next = *info; 17427c478bd9Sstevel@tonic-gate *info = sci; 17437c478bd9Sstevel@tonic-gate sci->shadow = shadow; 17447c478bd9Sstevel@tonic-gate sci->totalClients = 0; 17457c478bd9Sstevel@tonic-gate sci->clients = newshadowclient(NULL); 17467c478bd9Sstevel@tonic-gate } 17477c478bd9Sstevel@tonic-gate 17487c478bd9Sstevel@tonic-gate sci->totalClients++; 17497c478bd9Sstevel@tonic-gate scc = sci->clients; 17507c478bd9Sstevel@tonic-gate if (scc->nclients >= maxshadowclients) { 17517c478bd9Sstevel@tonic-gate scc = newshadowclient(sci->clients); 17527c478bd9Sstevel@tonic-gate sci->clients = scc; 17537c478bd9Sstevel@tonic-gate } 17547c478bd9Sstevel@tonic-gate 17557c478bd9Sstevel@tonic-gate scc->client[scc->nclients++] = client; 17567c478bd9Sstevel@tonic-gate } 17577c478bd9Sstevel@tonic-gate 1758*355d6bb5Sswilcox /* 1759*355d6bb5Sswilcox * Locate and discard a shadow. 1760*355d6bb5Sswilcox */ 1761*355d6bb5Sswilcox void 1762*355d6bb5Sswilcox clearshadow(fsck_ino_t shadow, struct shadowclientinfo **info) 1763*355d6bb5Sswilcox { 1764*355d6bb5Sswilcox struct shadowclientinfo *sci, *prev; 1765*355d6bb5Sswilcox 1766*355d6bb5Sswilcox /* 1767*355d6bb5Sswilcox * Do we have a record for this shadow? 1768*355d6bb5Sswilcox */ 1769*355d6bb5Sswilcox prev = NULL; 1770*355d6bb5Sswilcox for (sci = *info; sci != NULL; sci = sci->next) { 1771*355d6bb5Sswilcox if (sci->shadow == shadow) 1772*355d6bb5Sswilcox break; 1773*355d6bb5Sswilcox prev = sci; 1774*355d6bb5Sswilcox } 1775*355d6bb5Sswilcox 1776*355d6bb5Sswilcox if (sci != NULL) { 1777*355d6bb5Sswilcox /* 1778*355d6bb5Sswilcox * First, pull it off the list, since we know there 1779*355d6bb5Sswilcox * shouldn't be any future references to this one. 1780*355d6bb5Sswilcox */ 1781*355d6bb5Sswilcox if (prev == NULL) 1782*355d6bb5Sswilcox *info = sci->next; 1783*355d6bb5Sswilcox else 1784*355d6bb5Sswilcox prev->next = sci->next; 1785*355d6bb5Sswilcox deshadow(sci, clearattrref); 1786*355d6bb5Sswilcox } 1787*355d6bb5Sswilcox } 1788*355d6bb5Sswilcox 1789*355d6bb5Sswilcox /* 1790*355d6bb5Sswilcox * Discard all memory used to track clients of a shadow. 1791*355d6bb5Sswilcox */ 1792*355d6bb5Sswilcox void 1793*355d6bb5Sswilcox deshadow(struct shadowclientinfo *sci, void (*cb)(fsck_ino_t)) 1794*355d6bb5Sswilcox { 1795*355d6bb5Sswilcox struct shadowclients *clients, *discard; 1796*355d6bb5Sswilcox int idx; 1797*355d6bb5Sswilcox 1798*355d6bb5Sswilcox clients = sci->clients; 1799*355d6bb5Sswilcox while (clients != NULL) { 1800*355d6bb5Sswilcox discard = clients; 1801*355d6bb5Sswilcox clients = clients->next; 1802*355d6bb5Sswilcox if (discard->client != NULL) { 1803*355d6bb5Sswilcox if (cb != NULL) { 1804*355d6bb5Sswilcox for (idx = 0; idx < discard->nclients; idx++) 1805*355d6bb5Sswilcox (*cb)(discard->client[idx]); 1806*355d6bb5Sswilcox } 1807*355d6bb5Sswilcox free((void *)discard->client); 1808*355d6bb5Sswilcox } 1809*355d6bb5Sswilcox free((void *)discard); 1810*355d6bb5Sswilcox } 1811*355d6bb5Sswilcox 1812*355d6bb5Sswilcox free((void *)sci); 1813*355d6bb5Sswilcox } 1814*355d6bb5Sswilcox 18157c478bd9Sstevel@tonic-gate /* 18167c478bd9Sstevel@tonic-gate * Allocate more buffer as need arises but allocate one at a time. 18177c478bd9Sstevel@tonic-gate * This is done to make sure that fsck does not exit with error if it 1818*355d6bb5Sswilcox * needs more buffer to complete its task. 18197c478bd9Sstevel@tonic-gate */ 18207c478bd9Sstevel@tonic-gate static struct bufarea * 1821*355d6bb5Sswilcox alloc_bufarea(void) 18227c478bd9Sstevel@tonic-gate { 1823*355d6bb5Sswilcox struct bufarea *newbp; 1824*355d6bb5Sswilcox caddr_t bufp; 18257c478bd9Sstevel@tonic-gate 18267c478bd9Sstevel@tonic-gate bufp = malloc((unsigned int)sblock.fs_bsize); 1827*355d6bb5Sswilcox if (bufp == NULL) 1828*355d6bb5Sswilcox return (NULL); 1829*355d6bb5Sswilcox 1830*355d6bb5Sswilcox newbp = (struct bufarea *)malloc(sizeof (struct bufarea)); 1831*355d6bb5Sswilcox if (newbp == NULL) { 1832*355d6bb5Sswilcox free((void *)bufp); 18337c478bd9Sstevel@tonic-gate return (NULL); 18347c478bd9Sstevel@tonic-gate } 1835*355d6bb5Sswilcox 1836*355d6bb5Sswilcox initbarea(newbp); 1837*355d6bb5Sswilcox newbp->b_un.b_buf = bufp; 1838*355d6bb5Sswilcox newbp->b_prev = &bufhead; 1839*355d6bb5Sswilcox newbp->b_next = bufhead.b_next; 1840*355d6bb5Sswilcox bufhead.b_next->b_prev = newbp; 1841*355d6bb5Sswilcox bufhead.b_next = newbp; 18427c478bd9Sstevel@tonic-gate bufhead.b_size++; 1843*355d6bb5Sswilcox return (newbp); 1844*355d6bb5Sswilcox } 1845*355d6bb5Sswilcox 1846*355d6bb5Sswilcox /* 1847*355d6bb5Sswilcox * We length-limit in both unrawname() and rawname() to avoid 1848*355d6bb5Sswilcox * overflowing our arrays or those of our naive, trusting callers. 1849*355d6bb5Sswilcox */ 1850*355d6bb5Sswilcox 1851*355d6bb5Sswilcox caddr_t 1852*355d6bb5Sswilcox unrawname(caddr_t name) 1853*355d6bb5Sswilcox { 1854*355d6bb5Sswilcox caddr_t dp; 1855*355d6bb5Sswilcox static char fullname[MAXPATHLEN + 1]; 1856*355d6bb5Sswilcox 1857*355d6bb5Sswilcox if ((dp = getfullblkname(name)) == NULL) 1858*355d6bb5Sswilcox return (""); 1859*355d6bb5Sswilcox 1860*355d6bb5Sswilcox (void) strlcpy(fullname, dp, sizeof (fullname)); 1861*355d6bb5Sswilcox /* 1862*355d6bb5Sswilcox * Not reporting under debug, as the allocation isn't 1863*355d6bb5Sswilcox * reported by getfullblkname. The idea is that we 1864*355d6bb5Sswilcox * produce balanced alloc/free instances. 1865*355d6bb5Sswilcox */ 1866*355d6bb5Sswilcox free(dp); 1867*355d6bb5Sswilcox 1868*355d6bb5Sswilcox return (fullname); 1869*355d6bb5Sswilcox } 1870*355d6bb5Sswilcox 1871*355d6bb5Sswilcox caddr_t 1872*355d6bb5Sswilcox rawname(caddr_t name) 1873*355d6bb5Sswilcox { 1874*355d6bb5Sswilcox caddr_t dp; 1875*355d6bb5Sswilcox static char fullname[MAXPATHLEN + 1]; 1876*355d6bb5Sswilcox 1877*355d6bb5Sswilcox if ((dp = getfullrawname(name)) == NULL) 1878*355d6bb5Sswilcox return (""); 1879*355d6bb5Sswilcox 1880*355d6bb5Sswilcox (void) strlcpy(fullname, dp, sizeof (fullname)); 1881*355d6bb5Sswilcox /* 1882*355d6bb5Sswilcox * Not reporting under debug, as the allocation isn't 1883*355d6bb5Sswilcox * reported by getfullblkname. The idea is that we 1884*355d6bb5Sswilcox * produce balanced alloc/free instances. 1885*355d6bb5Sswilcox */ 1886*355d6bb5Sswilcox free(dp); 1887*355d6bb5Sswilcox 1888*355d6bb5Sswilcox return (fullname); 1889*355d6bb5Sswilcox } 1890*355d6bb5Sswilcox 1891*355d6bb5Sswilcox /* 1892*355d6bb5Sswilcox * Make sure that a cg header looks at least moderately reasonable. 1893*355d6bb5Sswilcox * We want to be able to trust the contents enough to be able to use 1894*355d6bb5Sswilcox * the standard accessor macros. So, besides looking at the obvious 1895*355d6bb5Sswilcox * such as the magic number, we verify that the offset field values 1896*355d6bb5Sswilcox * are properly aligned and not too big or small. 1897*355d6bb5Sswilcox * 1898*355d6bb5Sswilcox * Returns a NULL pointer if the cg is sane enough for our needs, else 1899*355d6bb5Sswilcox * a dynamically-allocated string describing all of its faults. 1900*355d6bb5Sswilcox */ 1901*355d6bb5Sswilcox #define Append_Error(full, full_len, addition, addition_len) \ 1902*355d6bb5Sswilcox if (full == NULL) { \ 1903*355d6bb5Sswilcox full = addition; \ 1904*355d6bb5Sswilcox full_len = addition_len; \ 1905*355d6bb5Sswilcox } else { \ 1906*355d6bb5Sswilcox /* lint doesn't think realloc() understands NULLs */ \ 1907*355d6bb5Sswilcox full = realloc(full, full_len + addition_len + 1); \ 1908*355d6bb5Sswilcox if (full == NULL) { \ 1909*355d6bb5Sswilcox errexit("Out of memory in cg_sanity"); \ 1910*355d6bb5Sswilcox /* NOTREACHED */ \ 1911*355d6bb5Sswilcox } \ 1912*355d6bb5Sswilcox (void) strcpy(full + full_len, addition); \ 1913*355d6bb5Sswilcox full_len += addition_len; \ 1914*355d6bb5Sswilcox free(addition); \ 1915*355d6bb5Sswilcox } 1916*355d6bb5Sswilcox 1917*355d6bb5Sswilcox caddr_t 1918*355d6bb5Sswilcox cg_sanity(struct cg *cgp, int cgno, int *is_fatal) 1919*355d6bb5Sswilcox { 1920*355d6bb5Sswilcox caddr_t full_err; 1921*355d6bb5Sswilcox caddr_t this_err = NULL; 1922*355d6bb5Sswilcox int full_len, this_len; 1923*355d6bb5Sswilcox daddr32_t ndblk; 1924*355d6bb5Sswilcox daddr32_t exp_btotoff, exp_boff, exp_iusedoff; 1925*355d6bb5Sswilcox daddr32_t exp_freeoff, exp_nextfreeoff; 1926*355d6bb5Sswilcox 1927*355d6bb5Sswilcox cg_constants(cgno, &exp_btotoff, &exp_boff, &exp_iusedoff, 1928*355d6bb5Sswilcox &exp_freeoff, &exp_nextfreeoff, &ndblk); 1929*355d6bb5Sswilcox 1930*355d6bb5Sswilcox full_err = NULL; 1931*355d6bb5Sswilcox full_len = 0; 1932*355d6bb5Sswilcox *is_fatal = 0; 1933*355d6bb5Sswilcox 1934*355d6bb5Sswilcox if (!cg_chkmagic(cgp)) { 1935*355d6bb5Sswilcox this_len = fsck_asprintf(&this_err, 1936*355d6bb5Sswilcox "BAD CG MAGIC NUMBER (0x%x should be 0x%x)\n", 1937*355d6bb5Sswilcox cgp->cg_magic, CG_MAGIC); 1938*355d6bb5Sswilcox Append_Error(full_err, full_len, this_err, this_len); 1939*355d6bb5Sswilcox *is_fatal = 1; 1940*355d6bb5Sswilcox } 1941*355d6bb5Sswilcox 1942*355d6bb5Sswilcox if (cgp->cg_cgx != cgno) { 1943*355d6bb5Sswilcox this_len = fsck_asprintf(&this_err, 1944*355d6bb5Sswilcox "WRONG CG NUMBER (%d should be %d)\n", 1945*355d6bb5Sswilcox cgp->cg_cgx, cgno); 1946*355d6bb5Sswilcox Append_Error(full_err, full_len, this_err, this_len); 1947*355d6bb5Sswilcox } 1948*355d6bb5Sswilcox 1949*355d6bb5Sswilcox if ((cgp->cg_btotoff & 3) != 0) { 1950*355d6bb5Sswilcox this_len = fsck_asprintf(&this_err, 1951*355d6bb5Sswilcox "BLOCK TOTALS OFFSET %d NOT FOUR-BYTE ALIGNED\n", 1952*355d6bb5Sswilcox cgp->cg_btotoff); 1953*355d6bb5Sswilcox Append_Error(full_err, full_len, this_err, this_len); 1954*355d6bb5Sswilcox } 1955*355d6bb5Sswilcox 1956*355d6bb5Sswilcox if ((cgp->cg_boff & 1) != 0) { 1957*355d6bb5Sswilcox this_len = fsck_asprintf(&this_err, 1958*355d6bb5Sswilcox "FREE BLOCK POSITIONS TABLE OFFSET %d NOT TWO-BYTE ALIGNED\n", 1959*355d6bb5Sswilcox cgp->cg_boff); 1960*355d6bb5Sswilcox Append_Error(full_err, full_len, this_err, this_len); 1961*355d6bb5Sswilcox } 1962*355d6bb5Sswilcox 1963*355d6bb5Sswilcox if ((cgp->cg_ncyl < 1) || (cgp->cg_ncyl > sblock.fs_cpg)) { 1964*355d6bb5Sswilcox if (cgp->cg_ncyl < 1) { 1965*355d6bb5Sswilcox this_len = fsck_asprintf(&this_err, 1966*355d6bb5Sswilcox "IMPOSSIBLE NUMBER OF CYLINDERS IN GROUP (%d is less than 1)\n", 1967*355d6bb5Sswilcox cgp->cg_ncyl); 1968*355d6bb5Sswilcox } else { 1969*355d6bb5Sswilcox this_len = fsck_asprintf(&this_err, 1970*355d6bb5Sswilcox "IMPOSSIBLE NUMBER OF CYLINDERS IN GROUP (%d is greater than %d)\n", 1971*355d6bb5Sswilcox cgp->cg_ncyl, sblock.fs_cpg); 1972*355d6bb5Sswilcox } 1973*355d6bb5Sswilcox Append_Error(full_err, full_len, this_err, this_len); 1974*355d6bb5Sswilcox } 1975*355d6bb5Sswilcox 1976*355d6bb5Sswilcox if (cgp->cg_niblk != sblock.fs_ipg) { 1977*355d6bb5Sswilcox this_len = fsck_asprintf(&this_err, 1978*355d6bb5Sswilcox "INCORRECT NUMBER OF INODES IN GROUP (%d should be %d)\n", 1979*355d6bb5Sswilcox cgp->cg_niblk, sblock.fs_ipg); 1980*355d6bb5Sswilcox Append_Error(full_err, full_len, this_err, this_len); 1981*355d6bb5Sswilcox } 1982*355d6bb5Sswilcox 1983*355d6bb5Sswilcox if (cgp->cg_ndblk != ndblk) { 1984*355d6bb5Sswilcox this_len = fsck_asprintf(&this_err, 1985*355d6bb5Sswilcox "INCORRECT NUMBER OF DATA BLOCKS IN GROUP (%d should be %d)\n", 1986*355d6bb5Sswilcox cgp->cg_ndblk, ndblk); 1987*355d6bb5Sswilcox Append_Error(full_err, full_len, this_err, this_len); 1988*355d6bb5Sswilcox } 1989*355d6bb5Sswilcox 1990*355d6bb5Sswilcox if ((cgp->cg_rotor < 0) || (cgp->cg_rotor >= ndblk)) { 1991*355d6bb5Sswilcox this_len = fsck_asprintf(&this_err, 1992*355d6bb5Sswilcox "IMPOSSIBLE BLOCK ALLOCATION ROTOR POSITION " 1993*355d6bb5Sswilcox "(%d should be at least 0 and less than %d)\n", 1994*355d6bb5Sswilcox cgp->cg_rotor, ndblk); 1995*355d6bb5Sswilcox Append_Error(full_err, full_len, this_err, this_len); 1996*355d6bb5Sswilcox } 1997*355d6bb5Sswilcox 1998*355d6bb5Sswilcox if ((cgp->cg_frotor < 0) || (cgp->cg_frotor >= ndblk)) { 1999*355d6bb5Sswilcox this_len = fsck_asprintf(&this_err, 2000*355d6bb5Sswilcox "IMPOSSIBLE FRAGMENT ALLOCATION ROTOR POSITION " 2001*355d6bb5Sswilcox "(%d should be at least 0 and less than %d)\n", 2002*355d6bb5Sswilcox cgp->cg_frotor, ndblk); 2003*355d6bb5Sswilcox Append_Error(full_err, full_len, this_err, this_len); 2004*355d6bb5Sswilcox } 2005*355d6bb5Sswilcox 2006*355d6bb5Sswilcox if ((cgp->cg_irotor < 0) || (cgp->cg_irotor >= sblock.fs_ipg)) { 2007*355d6bb5Sswilcox this_len = fsck_asprintf(&this_err, 2008*355d6bb5Sswilcox "IMPOSSIBLE INODE ALLOCATION ROTOR POSITION " 2009*355d6bb5Sswilcox "(%d should be at least 0 and less than %d)\n", 2010*355d6bb5Sswilcox cgp->cg_irotor, sblock.fs_ipg); 2011*355d6bb5Sswilcox Append_Error(full_err, full_len, this_err, this_len); 2012*355d6bb5Sswilcox } 2013*355d6bb5Sswilcox 2014*355d6bb5Sswilcox if (cgp->cg_btotoff != exp_btotoff) { 2015*355d6bb5Sswilcox this_len = fsck_asprintf(&this_err, 2016*355d6bb5Sswilcox "INCORRECT BLOCK TOTALS OFFSET (%d should be %d)\n", 2017*355d6bb5Sswilcox cgp->cg_btotoff, exp_btotoff); 2018*355d6bb5Sswilcox Append_Error(full_err, full_len, this_err, this_len); 2019*355d6bb5Sswilcox } 2020*355d6bb5Sswilcox 2021*355d6bb5Sswilcox if (cgp->cg_boff != exp_boff) { 2022*355d6bb5Sswilcox this_len = fsck_asprintf(&this_err, 2023*355d6bb5Sswilcox "BAD FREE BLOCK POSITIONS TABLE OFFSET (%d should %d)\n", 2024*355d6bb5Sswilcox cgp->cg_boff, exp_boff); 2025*355d6bb5Sswilcox Append_Error(full_err, full_len, this_err, this_len); 2026*355d6bb5Sswilcox } 2027*355d6bb5Sswilcox 2028*355d6bb5Sswilcox if (cgp->cg_iusedoff != exp_iusedoff) { 2029*355d6bb5Sswilcox this_len = fsck_asprintf(&this_err, 2030*355d6bb5Sswilcox "INCORRECT USED INODE MAP OFFSET (%d should be %d)\n", 2031*355d6bb5Sswilcox cgp->cg_iusedoff, exp_iusedoff); 2032*355d6bb5Sswilcox Append_Error(full_err, full_len, this_err, this_len); 2033*355d6bb5Sswilcox } 2034*355d6bb5Sswilcox 2035*355d6bb5Sswilcox if (cgp->cg_freeoff != exp_freeoff) { 2036*355d6bb5Sswilcox this_len = fsck_asprintf(&this_err, 2037*355d6bb5Sswilcox "INCORRECT FREE FRAGMENT MAP OFFSET (%d should be %d)\n", 2038*355d6bb5Sswilcox cgp->cg_freeoff, exp_freeoff); 2039*355d6bb5Sswilcox Append_Error(full_err, full_len, this_err, this_len); 2040*355d6bb5Sswilcox } 2041*355d6bb5Sswilcox 2042*355d6bb5Sswilcox if (cgp->cg_nextfreeoff != exp_nextfreeoff) { 2043*355d6bb5Sswilcox this_len = fsck_asprintf(&this_err, 2044*355d6bb5Sswilcox "END OF HEADER POSITION INCORRECT (%d should be %d)\n", 2045*355d6bb5Sswilcox cgp->cg_nextfreeoff, exp_nextfreeoff); 2046*355d6bb5Sswilcox Append_Error(full_err, full_len, this_err, this_len); 2047*355d6bb5Sswilcox } 2048*355d6bb5Sswilcox 2049*355d6bb5Sswilcox return (full_err); 2050*355d6bb5Sswilcox } 2051*355d6bb5Sswilcox 2052*355d6bb5Sswilcox #undef Append_Error 2053*355d6bb5Sswilcox 2054*355d6bb5Sswilcox /* 2055*355d6bb5Sswilcox * This is taken from mkfs, and is what is used to come up with the 2056*355d6bb5Sswilcox * original values for a struct cg. This implies that, since these 2057*355d6bb5Sswilcox * are all constants, recalculating them now should give us the same 2058*355d6bb5Sswilcox * thing as what's on disk. 2059*355d6bb5Sswilcox */ 2060*355d6bb5Sswilcox static void 2061*355d6bb5Sswilcox cg_constants(int cgno, daddr32_t *btotoff, daddr32_t *boff, 2062*355d6bb5Sswilcox daddr32_t *iusedoff, daddr32_t *freeoff, daddr32_t *nextfreeoff, 2063*355d6bb5Sswilcox daddr32_t *ndblk) 2064*355d6bb5Sswilcox { 2065*355d6bb5Sswilcox daddr32_t cbase, dmax; 2066*355d6bb5Sswilcox struct cg *cgp; 2067*355d6bb5Sswilcox 2068*355d6bb5Sswilcox (void) getblk(&cgblk, (diskaddr_t)cgtod(&sblock, cgno), 2069*355d6bb5Sswilcox (size_t)sblock.fs_cgsize); 2070*355d6bb5Sswilcox cgp = cgblk.b_un.b_cg; 2071*355d6bb5Sswilcox 2072*355d6bb5Sswilcox cbase = cgbase(&sblock, cgno); 2073*355d6bb5Sswilcox dmax = cbase + sblock.fs_fpg; 2074*355d6bb5Sswilcox if (dmax > sblock.fs_size) 2075*355d6bb5Sswilcox dmax = sblock.fs_size; 2076*355d6bb5Sswilcox 2077*355d6bb5Sswilcox /* LINTED pointer difference won't overflow */ 2078*355d6bb5Sswilcox *btotoff = &cgp->cg_space[0] - (uchar_t *)(&cgp->cg_link); 2079*355d6bb5Sswilcox *boff = *btotoff + sblock.fs_cpg * sizeof (daddr32_t); 2080*355d6bb5Sswilcox *iusedoff = *boff + sblock.fs_cpg * sblock.fs_nrpos * sizeof (int16_t); 2081*355d6bb5Sswilcox *freeoff = *iusedoff + howmany(sblock.fs_ipg, NBBY); 2082*355d6bb5Sswilcox *nextfreeoff = *freeoff + 2083*355d6bb5Sswilcox howmany(sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock), NBBY); 2084*355d6bb5Sswilcox *ndblk = dmax - cbase; 2085*355d6bb5Sswilcox } 2086*355d6bb5Sswilcox 2087*355d6bb5Sswilcox /* 2088*355d6bb5Sswilcox * Corrects all fields in the cg that can be done with the available 2089*355d6bb5Sswilcox * redundant data. 2090*355d6bb5Sswilcox */ 2091*355d6bb5Sswilcox void 2092*355d6bb5Sswilcox fix_cg(struct cg *cgp, int cgno) 2093*355d6bb5Sswilcox { 2094*355d6bb5Sswilcox daddr32_t exp_btotoff, exp_boff, exp_iusedoff; 2095*355d6bb5Sswilcox daddr32_t exp_freeoff, exp_nextfreeoff; 2096*355d6bb5Sswilcox daddr32_t ndblk; 2097*355d6bb5Sswilcox 2098*355d6bb5Sswilcox cg_constants(cgno, &exp_btotoff, &exp_boff, &exp_iusedoff, 2099*355d6bb5Sswilcox &exp_freeoff, &exp_nextfreeoff, &ndblk); 2100*355d6bb5Sswilcox 2101*355d6bb5Sswilcox if (cgp->cg_cgx != cgno) { 2102*355d6bb5Sswilcox cgp->cg_cgx = cgno; 2103*355d6bb5Sswilcox } 2104*355d6bb5Sswilcox 2105*355d6bb5Sswilcox if ((cgp->cg_ncyl < 1) || (cgp->cg_ncyl > sblock.fs_cpg)) { 2106*355d6bb5Sswilcox if (cgno == sblock.fs_ncg) { 2107*355d6bb5Sswilcox cgp->cg_ncyl = sblock.fs_ncyl - 2108*355d6bb5Sswilcox (sblock.fs_ncg * (cgno - 1)); 2109*355d6bb5Sswilcox } else { 2110*355d6bb5Sswilcox cgp->cg_ncyl = sblock.fs_cpg; 2111*355d6bb5Sswilcox } 2112*355d6bb5Sswilcox } 2113*355d6bb5Sswilcox 2114*355d6bb5Sswilcox if (cgp->cg_niblk != sblock.fs_ipg) { 2115*355d6bb5Sswilcox /* 2116*355d6bb5Sswilcox * This is not used by the kernel, so it's pretty 2117*355d6bb5Sswilcox * harmless if it's wrong. 2118*355d6bb5Sswilcox */ 2119*355d6bb5Sswilcox cgp->cg_niblk = sblock.fs_ipg; 2120*355d6bb5Sswilcox } 2121*355d6bb5Sswilcox 2122*355d6bb5Sswilcox if (cgp->cg_ndblk != ndblk) { 2123*355d6bb5Sswilcox cgp->cg_ndblk = ndblk; 2124*355d6bb5Sswilcox } 2125*355d6bb5Sswilcox 2126*355d6bb5Sswilcox /* 2127*355d6bb5Sswilcox * For the rotors, any position's valid, so pick the one we know 2128*355d6bb5Sswilcox * will always exist. 2129*355d6bb5Sswilcox */ 2130*355d6bb5Sswilcox if ((cgp->cg_rotor < 0) || (cgp->cg_rotor >= cgp->cg_ndblk)) { 2131*355d6bb5Sswilcox cgp->cg_rotor = 0; 2132*355d6bb5Sswilcox } 2133*355d6bb5Sswilcox 2134*355d6bb5Sswilcox if ((cgp->cg_frotor < 0) || (cgp->cg_frotor >= cgp->cg_ndblk)) { 2135*355d6bb5Sswilcox cgp->cg_frotor = 0; 2136*355d6bb5Sswilcox } 2137*355d6bb5Sswilcox 2138*355d6bb5Sswilcox if ((cgp->cg_irotor < 0) || (cgp->cg_irotor >= sblock.fs_ipg)) { 2139*355d6bb5Sswilcox cgp->cg_irotor = 0; 2140*355d6bb5Sswilcox } 2141*355d6bb5Sswilcox 2142*355d6bb5Sswilcox /* 2143*355d6bb5Sswilcox * For btotoff and boff, if they're misaligned they won't 2144*355d6bb5Sswilcox * match the expected values, so we're catching both cases 2145*355d6bb5Sswilcox * here. Of course, if any of these are off, it seems likely 2146*355d6bb5Sswilcox * that the tables really won't be where we calculate they 2147*355d6bb5Sswilcox * should be anyway. 2148*355d6bb5Sswilcox */ 2149*355d6bb5Sswilcox if (cgp->cg_btotoff != exp_btotoff) { 2150*355d6bb5Sswilcox cgp->cg_btotoff = exp_btotoff; 2151*355d6bb5Sswilcox } 2152*355d6bb5Sswilcox 2153*355d6bb5Sswilcox if (cgp->cg_boff != exp_boff) { 2154*355d6bb5Sswilcox cgp->cg_boff = exp_boff; 2155*355d6bb5Sswilcox } 2156*355d6bb5Sswilcox 2157*355d6bb5Sswilcox if (cgp->cg_iusedoff != exp_iusedoff) { 2158*355d6bb5Sswilcox cgp->cg_iusedoff = exp_iusedoff; 2159*355d6bb5Sswilcox } 2160*355d6bb5Sswilcox 2161*355d6bb5Sswilcox if (cgp->cg_freeoff != exp_freeoff) { 2162*355d6bb5Sswilcox cgp->cg_freeoff = exp_freeoff; 2163*355d6bb5Sswilcox } 2164*355d6bb5Sswilcox 2165*355d6bb5Sswilcox if (cgp->cg_nextfreeoff != exp_nextfreeoff) { 2166*355d6bb5Sswilcox cgp->cg_nextfreeoff = exp_nextfreeoff; 2167*355d6bb5Sswilcox } 2168*355d6bb5Sswilcox 2169*355d6bb5Sswilcox /* 2170*355d6bb5Sswilcox * We know there was at least one correctable problem, 2171*355d6bb5Sswilcox * or else we wouldn't have been called. So instead of 2172*355d6bb5Sswilcox * marking the buffer dirty N times above, just do it 2173*355d6bb5Sswilcox * once here. 2174*355d6bb5Sswilcox */ 2175*355d6bb5Sswilcox cgdirty(); 2176*355d6bb5Sswilcox } 2177*355d6bb5Sswilcox 2178*355d6bb5Sswilcox void 2179*355d6bb5Sswilcox examinelog(daddr32_t start, void (*cb)(daddr32_t)) 2180*355d6bb5Sswilcox { 2181*355d6bb5Sswilcox struct bufarea *bp; 2182*355d6bb5Sswilcox extent_block_t *ebp; 2183*355d6bb5Sswilcox extent_t *ep; 2184*355d6bb5Sswilcox daddr32_t nfno, fno; 2185*355d6bb5Sswilcox int i; 2186*355d6bb5Sswilcox int j; 2187*355d6bb5Sswilcox 2188*355d6bb5Sswilcox if (start < SBLOCK) 2189*355d6bb5Sswilcox return; 2190*355d6bb5Sswilcox 2191*355d6bb5Sswilcox /* 2192*355d6bb5Sswilcox * Read errors will return zeros, which will cause us 2193*355d6bb5Sswilcox * to do nothing harmful, so don't need to handle it. 2194*355d6bb5Sswilcox */ 2195*355d6bb5Sswilcox bp = getdatablk(logbtofrag(&sblock, sblock.fs_logbno), 2196*355d6bb5Sswilcox (size_t)sblock.fs_bsize); 2197*355d6bb5Sswilcox ebp = (void *)bp->b_un.b_buf; 2198*355d6bb5Sswilcox 2199*355d6bb5Sswilcox /* 2200*355d6bb5Sswilcox * Does it look like a log allocation table? 2201*355d6bb5Sswilcox */ 2202*355d6bb5Sswilcox /* LINTED pointer cast is aligned */ 2203*355d6bb5Sswilcox if (!log_checksum(&ebp->chksum, (int32_t *)bp->b_un.b_buf, 2204*355d6bb5Sswilcox sblock.fs_bsize)) 2205*355d6bb5Sswilcox return; 2206*355d6bb5Sswilcox if (ebp->type != LUFS_EXTENTS || ebp->nextents == 0) 2207*355d6bb5Sswilcox return; 2208*355d6bb5Sswilcox 2209*355d6bb5Sswilcox ep = &ebp->extents[0]; 2210*355d6bb5Sswilcox for (i = 0; i < ebp->nextents; ++i, ++ep) { 2211*355d6bb5Sswilcox fno = logbtofrag(&sblock, ep->pbno); 2212*355d6bb5Sswilcox nfno = dbtofsb(&sblock, ep->nbno); 2213*355d6bb5Sswilcox for (j = 0; j < nfno; ++j, ++fno) { 2214*355d6bb5Sswilcox /* 2215*355d6bb5Sswilcox * Invoke the callback first, so that pass1 can 2216*355d6bb5Sswilcox * mark the log blocks in-use. Then, if any 2217*355d6bb5Sswilcox * subsequent pass over the log shows us that a 2218*355d6bb5Sswilcox * block got freed (say, it was also claimed by 2219*355d6bb5Sswilcox * an inode that we cleared), we can safely declare 2220*355d6bb5Sswilcox * the log bad. 2221*355d6bb5Sswilcox */ 2222*355d6bb5Sswilcox if (cb != NULL) 2223*355d6bb5Sswilcox (*cb)(fno); 2224*355d6bb5Sswilcox if (!testbmap(fno)) 2225*355d6bb5Sswilcox islogok = 0; 2226*355d6bb5Sswilcox } 2227*355d6bb5Sswilcox } 2228*355d6bb5Sswilcox brelse(bp); 2229*355d6bb5Sswilcox 2230*355d6bb5Sswilcox if (cb != NULL) { 2231*355d6bb5Sswilcox fno = logbtofrag(&sblock, sblock.fs_logbno); 2232*355d6bb5Sswilcox for (j = 0; j < sblock.fs_frag; ++j, ++fno) 2233*355d6bb5Sswilcox (*cb)(fno); 2234*355d6bb5Sswilcox } 2235*355d6bb5Sswilcox } 2236*355d6bb5Sswilcox 2237*355d6bb5Sswilcox static void 2238*355d6bb5Sswilcox freelogblk(daddr32_t frag) 2239*355d6bb5Sswilcox { 2240*355d6bb5Sswilcox freeblk(sblock.fs_logbno, frag, 1); 2241*355d6bb5Sswilcox } 2242*355d6bb5Sswilcox 2243*355d6bb5Sswilcox caddr_t 2244*355d6bb5Sswilcox file_id(fsck_ino_t inum, mode_t mode) 2245*355d6bb5Sswilcox { 2246*355d6bb5Sswilcox static char name[MAXPATHLEN + 1]; 2247*355d6bb5Sswilcox 2248*355d6bb5Sswilcox if (lfdir == inum) { 2249*355d6bb5Sswilcox return (lfname); 2250*355d6bb5Sswilcox } 2251*355d6bb5Sswilcox 2252*355d6bb5Sswilcox if ((mode & IFMT) == IFDIR) { 2253*355d6bb5Sswilcox (void) strcpy(name, "DIR"); 2254*355d6bb5Sswilcox } else if ((mode & IFMT) == IFATTRDIR) { 2255*355d6bb5Sswilcox (void) strcpy(name, "ATTR DIR"); 2256*355d6bb5Sswilcox } else if ((mode & IFMT) == IFSHAD) { 2257*355d6bb5Sswilcox (void) strcpy(name, "ACL"); 2258*355d6bb5Sswilcox } else { 2259*355d6bb5Sswilcox (void) strcpy(name, "FILE"); 2260*355d6bb5Sswilcox } 2261*355d6bb5Sswilcox 2262*355d6bb5Sswilcox return (name); 2263*355d6bb5Sswilcox } 2264*355d6bb5Sswilcox 2265*355d6bb5Sswilcox /* 2266*355d6bb5Sswilcox * Simple initializer for inodesc structures, so users of only a few 2267*355d6bb5Sswilcox * fields don't have to worry about getting the right defaults for 2268*355d6bb5Sswilcox * everything out. 2269*355d6bb5Sswilcox */ 2270*355d6bb5Sswilcox void 2271*355d6bb5Sswilcox init_inodesc(struct inodesc *idesc) 2272*355d6bb5Sswilcox { 2273*355d6bb5Sswilcox /* 2274*355d6bb5Sswilcox * Most fields should be zero, just hit the special cases. 2275*355d6bb5Sswilcox */ 2276*355d6bb5Sswilcox (void) memset((void *)idesc, 0, sizeof (struct inodesc)); 2277*355d6bb5Sswilcox idesc->id_fix = DONTKNOW; 2278*355d6bb5Sswilcox idesc->id_lbn = -1; 2279*355d6bb5Sswilcox idesc->id_truncto = -1; 2280*355d6bb5Sswilcox idesc->id_firsthole = -1; 2281*355d6bb5Sswilcox } 2282*355d6bb5Sswilcox 2283*355d6bb5Sswilcox /* 2284*355d6bb5Sswilcox * Compare routine for tsearch(C) to use on ino_t instances. 2285*355d6bb5Sswilcox */ 2286*355d6bb5Sswilcox int 2287*355d6bb5Sswilcox ino_t_cmp(const void *left, const void *right) 2288*355d6bb5Sswilcox { 2289*355d6bb5Sswilcox const fsck_ino_t lino = (const fsck_ino_t)left; 2290*355d6bb5Sswilcox const fsck_ino_t rino = (const fsck_ino_t)right; 2291*355d6bb5Sswilcox 2292*355d6bb5Sswilcox return (lino - rino); 2293*355d6bb5Sswilcox } 2294*355d6bb5Sswilcox 2295*355d6bb5Sswilcox int 2296*355d6bb5Sswilcox cgisdirty(void) 2297*355d6bb5Sswilcox { 2298*355d6bb5Sswilcox return (cgblk.b_dirty); 2299*355d6bb5Sswilcox } 2300*355d6bb5Sswilcox 2301*355d6bb5Sswilcox void 2302*355d6bb5Sswilcox cgflush(void) 2303*355d6bb5Sswilcox { 2304*355d6bb5Sswilcox flush(fswritefd, &cgblk); 2305*355d6bb5Sswilcox } 2306*355d6bb5Sswilcox 2307*355d6bb5Sswilcox void 2308*355d6bb5Sswilcox dirty(struct bufarea *bp) 2309*355d6bb5Sswilcox { 2310*355d6bb5Sswilcox if (fswritefd < 0) { 2311*355d6bb5Sswilcox pfatal("SETTING DIRTY FLAG IN READ_ONLY MODE\n"); 2312*355d6bb5Sswilcox } else { 2313*355d6bb5Sswilcox (bp)->b_dirty = 1; 2314*355d6bb5Sswilcox isdirty = 1; 2315*355d6bb5Sswilcox } 2316*355d6bb5Sswilcox } 2317*355d6bb5Sswilcox 2318*355d6bb5Sswilcox void 2319*355d6bb5Sswilcox initbarea(struct bufarea *bp) 2320*355d6bb5Sswilcox { 2321*355d6bb5Sswilcox (bp)->b_dirty = 0; 2322*355d6bb5Sswilcox (bp)->b_bno = (diskaddr_t)-1LL; 2323*355d6bb5Sswilcox (bp)->b_flags = 0; 2324*355d6bb5Sswilcox (bp)->b_cnt = 0; 2325*355d6bb5Sswilcox (bp)->b_errs = 0; 2326*355d6bb5Sswilcox } 2327*355d6bb5Sswilcox 2328*355d6bb5Sswilcox /* 2329*355d6bb5Sswilcox * Partition-sizing routines adapted from ../newfs/newfs.c. 2330*355d6bb5Sswilcox * Needed because calcsb() needs to use mkfs to work out what the 2331*355d6bb5Sswilcox * superblock should be, and mkfs insists on being told how many 2332*355d6bb5Sswilcox * sectors to use. 2333*355d6bb5Sswilcox * 2334*355d6bb5Sswilcox * Error handling assumes we're never called while preening. 2335*355d6bb5Sswilcox * 2336*355d6bb5Sswilcox * XXX This should be extracted into a ../ufslib.{c,h}, 2337*355d6bb5Sswilcox * in the same spirit to ../../fslib.{c,h}. Once that is 2338*355d6bb5Sswilcox * done, both fsck and newfs should be modified to link 2339*355d6bb5Sswilcox * against it. 2340*355d6bb5Sswilcox */ 2341*355d6bb5Sswilcox 2342*355d6bb5Sswilcox static int label_type; 2343*355d6bb5Sswilcox 2344*355d6bb5Sswilcox #define LABEL_TYPE_VTOC 1 2345*355d6bb5Sswilcox #define LABEL_TYPE_EFI 2 2346*355d6bb5Sswilcox #define LABEL_TYPE_OTHER 3 2347*355d6bb5Sswilcox 2348*355d6bb5Sswilcox #define MB (1024 * 1024) 2349*355d6bb5Sswilcox #define SECTORS_PER_TERABYTE (1LL << 31) 2350*355d6bb5Sswilcox #define FS_SIZE_UPPER_LIMIT 0x100000000000LL 2351*355d6bb5Sswilcox 2352*355d6bb5Sswilcox diskaddr_t 2353*355d6bb5Sswilcox getdisksize(caddr_t disk, int fd) 2354*355d6bb5Sswilcox { 2355*355d6bb5Sswilcox int rpm; 2356*355d6bb5Sswilcox struct dk_geom g; 2357*355d6bb5Sswilcox struct dk_cinfo ci; 2358*355d6bb5Sswilcox diskaddr_t actual_size; 2359*355d6bb5Sswilcox 2360*355d6bb5Sswilcox /* 2361*355d6bb5Sswilcox * get_device_size() determines the actual size of the 2362*355d6bb5Sswilcox * device, and also the disk's attributes, such as geometry. 2363*355d6bb5Sswilcox */ 2364*355d6bb5Sswilcox actual_size = get_device_size(fd, disk); 2365*355d6bb5Sswilcox 2366*355d6bb5Sswilcox if (label_type == LABEL_TYPE_VTOC) { 2367*355d6bb5Sswilcox if (ioctl(fd, DKIOCGGEOM, &g)) { 2368*355d6bb5Sswilcox pwarn("%s: Unable to read Disk geometry", disk); 2369*355d6bb5Sswilcox return (0); 2370*355d6bb5Sswilcox } 2371*355d6bb5Sswilcox if (sblock.fs_nsect == 0) 2372*355d6bb5Sswilcox sblock.fs_nsect = g.dkg_nsect; 2373*355d6bb5Sswilcox if (sblock.fs_ntrak == 0) 2374*355d6bb5Sswilcox sblock.fs_ntrak = g.dkg_nhead; 2375*355d6bb5Sswilcox if (sblock.fs_rps == 0) { 2376*355d6bb5Sswilcox rpm = ((int)g.dkg_rpm <= 0) ? 3600: g.dkg_rpm; 2377*355d6bb5Sswilcox sblock.fs_rps = rpm / 60; 2378*355d6bb5Sswilcox } 2379*355d6bb5Sswilcox } 2380*355d6bb5Sswilcox 2381*355d6bb5Sswilcox if (sblock.fs_bsize == 0) 2382*355d6bb5Sswilcox sblock.fs_bsize = MAXBSIZE; 2383*355d6bb5Sswilcox 2384*355d6bb5Sswilcox /* 2385*355d6bb5Sswilcox * Adjust maxcontig by the device's maxtransfer. If maxtransfer 2386*355d6bb5Sswilcox * information is not available, default to the min of a MB and 2387*355d6bb5Sswilcox * maxphys. 2388*355d6bb5Sswilcox */ 2389*355d6bb5Sswilcox if (sblock.fs_maxcontig == -1 && ioctl(fd, DKIOCINFO, &ci) == 0) { 2390*355d6bb5Sswilcox sblock.fs_maxcontig = ci.dki_maxtransfer * DEV_BSIZE; 2391*355d6bb5Sswilcox if (sblock.fs_maxcontig < 0) { 2392*355d6bb5Sswilcox int gotit, maxphys; 2393*355d6bb5Sswilcox 2394*355d6bb5Sswilcox gotit = fsgetmaxphys(&maxphys, NULL); 2395*355d6bb5Sswilcox 2396*355d6bb5Sswilcox /* 2397*355d6bb5Sswilcox * If we cannot get the maxphys value, default 2398*355d6bb5Sswilcox * to ufs_maxmaxphys (MB). 2399*355d6bb5Sswilcox */ 2400*355d6bb5Sswilcox if (gotit) { 2401*355d6bb5Sswilcox sblock.fs_maxcontig = MIN(maxphys, MB); 2402*355d6bb5Sswilcox } else { 2403*355d6bb5Sswilcox sblock.fs_maxcontig = MB; 2404*355d6bb5Sswilcox } 2405*355d6bb5Sswilcox } 2406*355d6bb5Sswilcox sblock.fs_maxcontig /= sblock.fs_bsize; 2407*355d6bb5Sswilcox } 2408*355d6bb5Sswilcox 2409*355d6bb5Sswilcox return (actual_size); 2410*355d6bb5Sswilcox } 2411*355d6bb5Sswilcox 2412*355d6bb5Sswilcox /* 2413*355d6bb5Sswilcox * Figure out how big the partition we're dealing with is. 2414*355d6bb5Sswilcox */ 2415*355d6bb5Sswilcox static diskaddr_t 2416*355d6bb5Sswilcox get_device_size(int fd, caddr_t name) 2417*355d6bb5Sswilcox { 2418*355d6bb5Sswilcox struct vtoc vtoc; 2419*355d6bb5Sswilcox struct dk_gpt *efi_vtoc; 2420*355d6bb5Sswilcox diskaddr_t slicesize = 0; 2421*355d6bb5Sswilcox 2422*355d6bb5Sswilcox int index = read_vtoc(fd, &vtoc); 2423*355d6bb5Sswilcox 2424*355d6bb5Sswilcox if (index >= 0) { 2425*355d6bb5Sswilcox label_type = LABEL_TYPE_VTOC; 2426*355d6bb5Sswilcox } else { 2427*355d6bb5Sswilcox if (index == VT_ENOTSUP || index == VT_ERROR) { 2428*355d6bb5Sswilcox /* it might be an EFI label */ 2429*355d6bb5Sswilcox index = efi_alloc_and_read(fd, &efi_vtoc); 2430*355d6bb5Sswilcox if (index >= 0) 2431*355d6bb5Sswilcox label_type = LABEL_TYPE_EFI; 2432*355d6bb5Sswilcox } 2433*355d6bb5Sswilcox } 2434*355d6bb5Sswilcox 2435*355d6bb5Sswilcox if (index < 0) { 2436*355d6bb5Sswilcox /* 2437*355d6bb5Sswilcox * Since both attempts to read the label failed, we're 2438*355d6bb5Sswilcox * going to fall back to a brute force approach to 2439*355d6bb5Sswilcox * determining the device's size: see how far out we can 2440*355d6bb5Sswilcox * perform reads on the device. 2441*355d6bb5Sswilcox */ 2442*355d6bb5Sswilcox 2443*355d6bb5Sswilcox slicesize = brute_force_get_device_size(fd); 2444*355d6bb5Sswilcox if (slicesize == 0) { 2445*355d6bb5Sswilcox switch (index) { 2446*355d6bb5Sswilcox case VT_ERROR: 2447*355d6bb5Sswilcox pwarn("%s: %s\n", name, strerror(errno)); 2448*355d6bb5Sswilcox break; 2449*355d6bb5Sswilcox case VT_EIO: 2450*355d6bb5Sswilcox pwarn("%s: I/O error accessing VTOC", name); 2451*355d6bb5Sswilcox break; 2452*355d6bb5Sswilcox case VT_EINVAL: 2453*355d6bb5Sswilcox pwarn("%s: Invalid field in VTOC", name); 2454*355d6bb5Sswilcox break; 2455*355d6bb5Sswilcox default: 2456*355d6bb5Sswilcox pwarn("%s: unknown error %d accessing VTOC", 2457*355d6bb5Sswilcox name, index); 2458*355d6bb5Sswilcox break; 2459*355d6bb5Sswilcox } 2460*355d6bb5Sswilcox return (0); 2461*355d6bb5Sswilcox } else { 2462*355d6bb5Sswilcox label_type = LABEL_TYPE_OTHER; 2463*355d6bb5Sswilcox } 2464*355d6bb5Sswilcox } 2465*355d6bb5Sswilcox 2466*355d6bb5Sswilcox if (label_type == LABEL_TYPE_EFI) { 2467*355d6bb5Sswilcox slicesize = efi_vtoc->efi_parts[index].p_size; 2468*355d6bb5Sswilcox efi_free(efi_vtoc); 2469*355d6bb5Sswilcox } else if (label_type == LABEL_TYPE_VTOC) { 2470*355d6bb5Sswilcox /* 2471*355d6bb5Sswilcox * In the vtoc struct, p_size is a 32-bit signed quantity. 2472*355d6bb5Sswilcox * In the dk_gpt struct (efi's version of the vtoc), p_size 2473*355d6bb5Sswilcox * is an unsigned 64-bit quantity. By casting the vtoc's 2474*355d6bb5Sswilcox * psize to an unsigned 32-bit quantity, it will be copied 2475*355d6bb5Sswilcox * to 'slicesize' (an unsigned 64-bit diskaddr_t) without 2476*355d6bb5Sswilcox * sign extension. 2477*355d6bb5Sswilcox */ 2478*355d6bb5Sswilcox 2479*355d6bb5Sswilcox slicesize = (uint32_t)vtoc.v_part[index].p_size; 2480*355d6bb5Sswilcox } 2481*355d6bb5Sswilcox 2482*355d6bb5Sswilcox return (slicesize); 2483*355d6bb5Sswilcox } 2484*355d6bb5Sswilcox 2485*355d6bb5Sswilcox /* 2486*355d6bb5Sswilcox * brute_force_get_device_size 2487*355d6bb5Sswilcox * 2488*355d6bb5Sswilcox * Determine the size of the device by seeing how far we can 2489*355d6bb5Sswilcox * read. Doing an llseek( , , SEEK_END) would probably work 2490*355d6bb5Sswilcox * in most cases, but we've seen at least one third-party driver 2491*355d6bb5Sswilcox * which doesn't correctly support the SEEK_END option when the 2492*355d6bb5Sswilcox * the device is greater than a terabyte. 2493*355d6bb5Sswilcox */ 2494*355d6bb5Sswilcox 2495*355d6bb5Sswilcox static diskaddr_t 2496*355d6bb5Sswilcox brute_force_get_device_size(int fd) 2497*355d6bb5Sswilcox { 2498*355d6bb5Sswilcox diskaddr_t min_fail = 0; 2499*355d6bb5Sswilcox diskaddr_t max_succeed = 0; 2500*355d6bb5Sswilcox diskaddr_t cur_db_off; 2501*355d6bb5Sswilcox char buf[DEV_BSIZE]; 2502*355d6bb5Sswilcox 2503*355d6bb5Sswilcox /* 2504*355d6bb5Sswilcox * First, see if we can read the device at all, just to 2505*355d6bb5Sswilcox * eliminate errors that have nothing to do with the 2506*355d6bb5Sswilcox * device's size. 2507*355d6bb5Sswilcox */ 2508*355d6bb5Sswilcox 2509*355d6bb5Sswilcox if (((llseek(fd, (offset_t)0, SEEK_SET)) == -1) || 2510*355d6bb5Sswilcox ((read(fd, buf, DEV_BSIZE)) == -1)) 2511*355d6bb5Sswilcox return (0); /* can't determine size */ 2512*355d6bb5Sswilcox 2513*355d6bb5Sswilcox /* 2514*355d6bb5Sswilcox * Now, go sequentially through the multiples of 4TB 2515*355d6bb5Sswilcox * to find the first read that fails (this isn't strictly 2516*355d6bb5Sswilcox * the most efficient way to find the actual size if the 2517*355d6bb5Sswilcox * size really could be anything between 0 and 2**64 bytes. 2518*355d6bb5Sswilcox * We expect the sizes to be less than 16 TB for some time, 2519*355d6bb5Sswilcox * so why do a bunch of reads that are larger than that? 2520*355d6bb5Sswilcox * However, this algorithm *will* work for sizes of greater 2521*355d6bb5Sswilcox * than 16 TB. We're just not optimizing for those sizes.) 2522*355d6bb5Sswilcox */ 2523*355d6bb5Sswilcox 2524*355d6bb5Sswilcox /* 2525*355d6bb5Sswilcox * XXX lint uses 32-bit arithmetic for doing flow analysis. 2526*355d6bb5Sswilcox * We're using > 32-bit constants here. Therefore, its flow 2527*355d6bb5Sswilcox * analysis is wrong. For the time being, ignore complaints 2528*355d6bb5Sswilcox * from it about the body of the for() being unreached. 2529*355d6bb5Sswilcox */ 2530*355d6bb5Sswilcox for (cur_db_off = SECTORS_PER_TERABYTE * 4; 2531*355d6bb5Sswilcox (min_fail == 0) && (cur_db_off < FS_SIZE_UPPER_LIMIT); 2532*355d6bb5Sswilcox cur_db_off += 4 * SECTORS_PER_TERABYTE) { 2533*355d6bb5Sswilcox if ((llseek(fd, (offset_t)(cur_db_off * DEV_BSIZE), 2534*355d6bb5Sswilcox SEEK_SET) == -1) || 2535*355d6bb5Sswilcox (read(fd, buf, DEV_BSIZE) != DEV_BSIZE)) 2536*355d6bb5Sswilcox min_fail = cur_db_off; 2537*355d6bb5Sswilcox else 2538*355d6bb5Sswilcox max_succeed = cur_db_off; 2539*355d6bb5Sswilcox } 2540*355d6bb5Sswilcox 2541*355d6bb5Sswilcox /* 2542*355d6bb5Sswilcox * XXX Same lint flow analysis problem as above. 2543*355d6bb5Sswilcox */ 2544*355d6bb5Sswilcox if (min_fail == 0) 2545*355d6bb5Sswilcox return (0); 2546*355d6bb5Sswilcox 2547*355d6bb5Sswilcox /* 2548*355d6bb5Sswilcox * We now know that the size of the device is less than 2549*355d6bb5Sswilcox * min_fail and greater than or equal to max_succeed. Now 2550*355d6bb5Sswilcox * keep splitting the difference until the actual size in 2551*355d6bb5Sswilcox * sectors in known. We also know that the difference 2552*355d6bb5Sswilcox * between max_succeed and min_fail at this time is 2553*355d6bb5Sswilcox * 4 * SECTORS_PER_TERABYTE, which is a power of two, which 2554*355d6bb5Sswilcox * simplifies the math below. 2555*355d6bb5Sswilcox */ 2556*355d6bb5Sswilcox 2557*355d6bb5Sswilcox while (min_fail - max_succeed > 1) { 2558*355d6bb5Sswilcox cur_db_off = max_succeed + (min_fail - max_succeed)/2; 2559*355d6bb5Sswilcox if (((llseek(fd, (offset_t)(cur_db_off * DEV_BSIZE), 2560*355d6bb5Sswilcox SEEK_SET)) == -1) || 2561*355d6bb5Sswilcox ((read(fd, buf, DEV_BSIZE)) != DEV_BSIZE)) 2562*355d6bb5Sswilcox min_fail = cur_db_off; 2563*355d6bb5Sswilcox else 2564*355d6bb5Sswilcox max_succeed = cur_db_off; 2565*355d6bb5Sswilcox } 2566*355d6bb5Sswilcox 2567*355d6bb5Sswilcox /* the size is the last successfully read sector offset plus one */ 2568*355d6bb5Sswilcox return (max_succeed + 1); 2569*355d6bb5Sswilcox } 2570*355d6bb5Sswilcox 2571*355d6bb5Sswilcox static void 2572*355d6bb5Sswilcox vfileerror(fsck_ino_t cwd, fsck_ino_t ino, caddr_t fmt, va_list ap) 2573*355d6bb5Sswilcox { 2574*355d6bb5Sswilcox struct dinode *dp; 2575*355d6bb5Sswilcox char pathbuf[MAXPATHLEN + 1]; 2576*355d6bb5Sswilcox 2577*355d6bb5Sswilcox vpwarn(fmt, ap); 2578*355d6bb5Sswilcox (void) putchar(' '); 2579*355d6bb5Sswilcox pinode(ino); 2580*355d6bb5Sswilcox (void) printf("\n"); 2581*355d6bb5Sswilcox getpathname(pathbuf, cwd, ino); 2582*355d6bb5Sswilcox if (ino < UFSROOTINO || ino > maxino) { 2583*355d6bb5Sswilcox pfatal("NAME=%s\n", pathbuf); 2584*355d6bb5Sswilcox return; 2585*355d6bb5Sswilcox } 2586*355d6bb5Sswilcox dp = ginode(ino); 2587*355d6bb5Sswilcox if (ftypeok(dp)) 2588*355d6bb5Sswilcox pfatal("%s=%s\n", file_id(ino, dp->di_mode), pathbuf); 2589*355d6bb5Sswilcox else 2590*355d6bb5Sswilcox pfatal("NAME=%s\n", pathbuf); 2591*355d6bb5Sswilcox } 2592*355d6bb5Sswilcox 2593*355d6bb5Sswilcox void 2594*355d6bb5Sswilcox direrror(fsck_ino_t ino, caddr_t fmt, ...) 2595*355d6bb5Sswilcox { 2596*355d6bb5Sswilcox va_list ap; 2597*355d6bb5Sswilcox 2598*355d6bb5Sswilcox va_start(ap, fmt); 2599*355d6bb5Sswilcox vfileerror(ino, ino, fmt, ap); 2600*355d6bb5Sswilcox va_end(ap); 2601*355d6bb5Sswilcox } 2602*355d6bb5Sswilcox 2603*355d6bb5Sswilcox static void 2604*355d6bb5Sswilcox vdirerror(fsck_ino_t ino, caddr_t fmt, va_list ap) 2605*355d6bb5Sswilcox { 2606*355d6bb5Sswilcox vfileerror(ino, ino, fmt, ap); 2607*355d6bb5Sswilcox } 2608*355d6bb5Sswilcox 2609*355d6bb5Sswilcox void 2610*355d6bb5Sswilcox fileerror(fsck_ino_t cwd, fsck_ino_t ino, caddr_t fmt, ...) 2611*355d6bb5Sswilcox { 2612*355d6bb5Sswilcox va_list ap; 2613*355d6bb5Sswilcox 2614*355d6bb5Sswilcox va_start(ap, fmt); 2615*355d6bb5Sswilcox vfileerror(cwd, ino, fmt, ap); 2616*355d6bb5Sswilcox va_end(ap); 2617*355d6bb5Sswilcox } 2618*355d6bb5Sswilcox 2619*355d6bb5Sswilcox /* 2620*355d6bb5Sswilcox * Adds the given inode to the orphaned-directories list, limbo_dirs. 2621*355d6bb5Sswilcox * Assumes that the caller has set INCLEAR in the inode's statemap[] 2622*355d6bb5Sswilcox * entry. 2623*355d6bb5Sswilcox * 2624*355d6bb5Sswilcox * With INCLEAR set, the inode will get ignored by passes 2 and 3, 2625*355d6bb5Sswilcox * meaning it's effectively an orphan. It needs to be noted now, so 2626*355d6bb5Sswilcox * it will be remembered in pass 4. 2627*355d6bb5Sswilcox */ 2628*355d6bb5Sswilcox 2629*355d6bb5Sswilcox void 2630*355d6bb5Sswilcox add_orphan_dir(fsck_ino_t ino) 2631*355d6bb5Sswilcox { 2632*355d6bb5Sswilcox if (tsearch((void *)ino, &limbo_dirs, ino_t_cmp) == NULL) 2633*355d6bb5Sswilcox errexit("add_orphan_dir: out of memory"); 2634*355d6bb5Sswilcox } 2635*355d6bb5Sswilcox 2636*355d6bb5Sswilcox /* 2637*355d6bb5Sswilcox * Remove an inode from the orphaned-directories list, presumably 2638*355d6bb5Sswilcox * because it's been cleared. 2639*355d6bb5Sswilcox */ 2640*355d6bb5Sswilcox void 2641*355d6bb5Sswilcox remove_orphan_dir(fsck_ino_t ino) 2642*355d6bb5Sswilcox { 2643*355d6bb5Sswilcox (void) tdelete((void *)ino, &limbo_dirs, ino_t_cmp); 2644*355d6bb5Sswilcox } 2645*355d6bb5Sswilcox 2646*355d6bb5Sswilcox /* 2647*355d6bb5Sswilcox * log_setsum() and log_checksum() are equivalent to lufs.c:setsum() 2648*355d6bb5Sswilcox * and lufs.c:checksum(). 2649*355d6bb5Sswilcox */ 2650*355d6bb5Sswilcox static void 2651*355d6bb5Sswilcox log_setsum(int32_t *sp, int32_t *lp, int nb) 2652*355d6bb5Sswilcox { 2653*355d6bb5Sswilcox int32_t csum = 0; 2654*355d6bb5Sswilcox 2655*355d6bb5Sswilcox *sp = 0; 2656*355d6bb5Sswilcox nb /= sizeof (int32_t); 2657*355d6bb5Sswilcox while (nb--) 2658*355d6bb5Sswilcox csum += *lp++; 2659*355d6bb5Sswilcox *sp = csum; 2660*355d6bb5Sswilcox } 2661*355d6bb5Sswilcox 2662*355d6bb5Sswilcox static int 2663*355d6bb5Sswilcox log_checksum(int32_t *sp, int32_t *lp, int nb) 2664*355d6bb5Sswilcox { 2665*355d6bb5Sswilcox int32_t ssum = *sp; 2666*355d6bb5Sswilcox 2667*355d6bb5Sswilcox log_setsum(sp, lp, nb); 2668*355d6bb5Sswilcox if (ssum != *sp) { 2669*355d6bb5Sswilcox *sp = ssum; 2670*355d6bb5Sswilcox return (0); 2671*355d6bb5Sswilcox } 2672*355d6bb5Sswilcox return (1); 26737c478bd9Sstevel@tonic-gate } 2674