fsdbutil.c revision 122621
1193326Sed/* $NetBSD: fsdbutil.c,v 1.2 1995/10/08 23:18:12 thorpej Exp $ */ 2193326Sed 3193326Sed/* 4193326Sed * Copyright (c) 1995 John T. Kohl 5193326Sed * All rights reserved. 6193326Sed * 7193326Sed * Redistribution and use in source and binary forms, with or without 8193326Sed * modification, are permitted provided that the following conditions 9193326Sed * are met: 10193326Sed * 1. Redistributions of source code must retain the above copyright 11193326Sed * notice, this list of conditions and the following disclaimer. 12193326Sed * 2. Redistributions in binary form must reproduce the above copyright 13193326Sed * notice, this list of conditions and the following disclaimer in the 14193326Sed * documentation and/or other materials provided with the distribution. 15193326Sed * 3. The name of the author may not be used to endorse or promote products 16193326Sed * derived from this software without specific prior written permission. 17193326Sed * 18193326Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 19198092Srdivacky * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20193326Sed * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21193326Sed * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 22193326Sed * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23193326Sed * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24193326Sed * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25193326Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26193326Sed * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 27193326Sed * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28193326Sed * POSSIBILITY OF SUCH DAMAGE. 29193326Sed */ 30193326Sed 31193326Sed#ifndef lint 32193326Sedstatic const char rcsid[] = 33193326Sed "$FreeBSD: head/sbin/fsdb/fsdbutil.c 122621 2003-11-13 19:08:43Z johan $"; 34193326Sed#endif /* not lint */ 35193326Sed 36193326Sed#include <sys/param.h> 37193326Sed#include <ctype.h> 38193326Sed#include <err.h> 39193326Sed#include <grp.h> 40193326Sed#include <pwd.h> 41193326Sed#include <stdint.h> 42193326Sed#include <string.h> 43193326Sed#include <time.h> 44193326Sed#include <timeconv.h> 45193326Sed 46193326Sed#include <ufs/ufs/dinode.h> 47198092Srdivacky#include <ufs/ffs/fs.h> 48193326Sed 49193326Sed#include <sys/ioctl.h> 50193326Sed 51193326Sed#include "fsdb.h" 52193326Sed#include "fsck.h" 53193326Sed 54193326Sedstatic int charsperline(void); 55193326Sedstatic int printindir(ufs2_daddr_t blk, int level, char *bufp); 56193326Sedstatic void printblocks(ino_t inum, union dinode *dp); 57193326Sed 58193326Sedchar ** 59193326Sedcrack(char *line, int *argc) 60194179Sed{ 61194179Sed static char *argv[8]; 62194179Sed int i; 63194179Sed char *p, *val; 64193326Sed for (p = line, i = 0; p != NULL && i < 8; i++) { 65193326Sed while ((val = strsep(&p, " \t\n")) != NULL && *val == '\0') 66193326Sed /**/; 67193326Sed if (val) 68193326Sed argv[i] = val; 69193326Sed else 70193326Sed break; 71193326Sed } 72193326Sed *argc = i; 73193326Sed return argv; 74193326Sed} 75193326Sed 76193326Sedchar ** 77193326Sedrecrack(char *line, int *argc, int argc_max) 78193326Sed{ 79193326Sed static char *argv[8]; 80193326Sed int i; 81193326Sed char *p, *val; 82193326Sed for (p = line, i = 0; p != NULL && i < 8 && i < argc_max - 1; i++) { 83193326Sed while ((val = strsep(&p, " \t\n")) != NULL && *val == '\0') 84193326Sed /**/; 85193326Sed if (val) 86198092Srdivacky argv[i] = val; 87193326Sed else 88193326Sed break; 89193326Sed } 90193326Sed argv[i] = argv[i - 1] + strlen(argv[i - 1]) + 1; 91193326Sed argv[i][strcspn(argv[i], "\n")] = '\0'; 92193326Sed *argc = i + 1; 93193326Sed return argv; 94193326Sed} 95193326Sed 96193326Sedint 97193326Sedargcount(struct cmdtable *cmdp, int argc, char *argv[]) 98193326Sed{ 99198092Srdivacky if (cmdp->minargc == cmdp->maxargc) 100198092Srdivacky warnx("command `%s' takes %u arguments, got %u", cmdp->cmd, 101198092Srdivacky cmdp->minargc-1, argc); 102198092Srdivacky else 103193326Sed warnx("command `%s' takes from %u to %u arguments", 104193326Sed cmdp->cmd, cmdp->minargc-1, cmdp->maxargc-1); 105193326Sed 106193326Sed warnx("usage: %s: %s", cmdp->cmd, cmdp->helptxt); 107198092Srdivacky return 1; 108193326Sed} 109193326Sed 110193326Sedvoid 111193326Sedprintstat(const char *cp, ino_t inum, union dinode *dp) 112193326Sed{ 113193326Sed struct group *grp; 114193326Sed struct passwd *pw; 115193326Sed ufs2_daddr_t blocks; 116193326Sed int64_t gen; 117193326Sed char *p; 118193326Sed time_t t; 119193326Sed 120193326Sed printf("%s: ", cp); 121193326Sed switch (DIP(dp, di_mode) & IFMT) { 122193326Sed case IFDIR: 123193326Sed puts("directory"); 124193326Sed break; 125193326Sed case IFREG: 126193326Sed puts("regular file"); 127193326Sed break; 128198092Srdivacky case IFBLK: 129193326Sed printf("block special (%d,%d)", 130198092Srdivacky major(DIP(dp, di_rdev)), minor(DIP(dp, di_rdev))); 131198092Srdivacky break; 132198092Srdivacky case IFCHR: 133198092Srdivacky printf("character special (%d,%d)", 134193326Sed major(DIP(dp, di_rdev)), minor(DIP(dp, di_rdev))); 135193326Sed break; 136193326Sed case IFLNK: 137193326Sed fputs("symlink",stdout); 138193326Sed if (DIP(dp, di_size) > 0 && 139193326Sed DIP(dp, di_size) < sblock.fs_maxsymlinklen && 140198092Srdivacky DIP(dp, di_blocks) == 0) { 141193326Sed if (sblock.fs_magic == FS_UFS1_MAGIC) 142193326Sed p = (caddr_t)dp->dp1.di_db; 143193326Sed else 144193326Sed p = (caddr_t)dp->dp2.di_db; 145193326Sed printf(" to `%.*s'\n", (int) DIP(dp, di_size), p); 146193326Sed } else { 147193326Sed putchar('\n'); 148193326Sed } 149193326Sed break; 150193326Sed case IFSOCK: 151193326Sed puts("socket"); 152193326Sed break; 153193326Sed case IFIFO: 154198092Srdivacky puts("fifo"); 155193326Sed break; 156193326Sed } 157193326Sed printf("I=%lu MODE=%o SIZE=%ju", (u_long)inum, DIP(dp, di_mode), 158193326Sed (uintmax_t)DIP(dp, di_size)); 159193326Sed if (sblock.fs_magic == FS_UFS1_MAGIC) 160193326Sed t = _time32_to_time(dp->dp1.di_mtime); 161193326Sed else 162198092Srdivacky t = _time64_to_time(dp->dp2.di_mtime); 163198092Srdivacky p = ctime(&t); 164198092Srdivacky printf("\n\tMTIME=%15.15s %4.4s [%d nsec]", &p[4], &p[20], 165193326Sed DIP(dp, di_mtimensec)); 166193326Sed if (sblock.fs_magic == FS_UFS1_MAGIC) 167193326Sed t = _time32_to_time(dp->dp1.di_ctime); 168198092Srdivacky else 169193326Sed t = _time64_to_time(dp->dp2.di_ctime); 170193326Sed p = ctime(&t); 171198092Srdivacky printf("\n\tCTIME=%15.15s %4.4s [%d nsec]", &p[4], &p[20], 172193326Sed DIP(dp, di_ctimensec)); 173193326Sed if (sblock.fs_magic == FS_UFS1_MAGIC) 174193326Sed t = _time32_to_time(dp->dp1.di_atime); 175193326Sed else 176193326Sed t = _time64_to_time(dp->dp2.di_atime); 177193326Sed p = ctime(&t); 178193326Sed printf("\n\tATIME=%15.15s %4.4s [%d nsec]\n", &p[4], &p[20], 179193326Sed DIP(dp, di_atimensec)); 180193326Sed 181198092Srdivacky if ((pw = getpwuid(DIP(dp, di_uid)))) 182193326Sed printf("OWNER=%s ", pw->pw_name); 183193326Sed else 184193326Sed printf("OWNUID=%u ", DIP(dp, di_uid)); 185193326Sed if ((grp = getgrgid(DIP(dp, di_gid)))) 186193326Sed printf("GRP=%s ", grp->gr_name); 187193326Sed else 188193326Sed printf("GID=%u ", DIP(dp, di_gid)); 189193326Sed 190193326Sed blocks = DIP(dp, di_blocks); 191193326Sed gen = DIP(dp, di_gen); 192193326Sed printf("LINKCNT=%hd FLAGS=%#x BLKCNT=%jx GEN=%jx\n", DIP(dp, di_nlink), 193193326Sed DIP(dp, di_flags), (intmax_t)blocks, (intmax_t)gen); 194193326Sed} 195193326Sed 196193326Sed 197198092Srdivacky/* 198193326Sed * Determine the number of characters in a 199193326Sed * single line. 200198092Srdivacky */ 201193326Sed 202193326Sedstatic int 203193326Sedcharsperline(void) 204193326Sed{ 205193326Sed int columns; 206193326Sed char *cp; 207193326Sed struct winsize ws; 208193326Sed 209198092Srdivacky columns = 0; 210193326Sed if (ioctl(0, TIOCGWINSZ, &ws) != -1) 211193326Sed columns = ws.ws_col; 212193326Sed if (columns == 0 && (cp = getenv("COLUMNS"))) 213193326Sed columns = atoi(cp); 214193326Sed if (columns == 0) 215193326Sed columns = 80; /* last resort */ 216193326Sed return (columns); 217193326Sed} 218193326Sed 219193326Sed 220193326Sed/* 221198092Srdivacky * Recursively print a list of indirect blocks. 222193326Sed */ 223193326Sedstatic int 224198092Srdivackyprintindir(ufs2_daddr_t blk, int level, char *bufp) 225193326Sed{ 226193326Sed struct bufarea buf, *bp; 227198092Srdivacky char tempbuf[32]; /* enough to print an ufs2_daddr_t */ 228193326Sed int i, j, cpl, charssofar; 229193326Sed ufs2_daddr_t blkno; 230193326Sed 231193326Sed if (level == 0) { 232193326Sed /* for the final indirect level, don't use the cache */ 233193326Sed bp = &buf; 234193326Sed bp->b_un.b_buf = bufp; 235193326Sed bp->b_prev = bp->b_next = bp; 236193326Sed initbarea(bp); 237193326Sed 238193326Sed getblk(bp, blk, sblock.fs_bsize); 239193326Sed } else 240193326Sed bp = getdatablk(blk, sblock.fs_bsize); 241193326Sed 242193326Sed cpl = charsperline(); 243193326Sed for (i = charssofar = 0; i < NINDIR(&sblock); i++) { 244193326Sed if (sblock.fs_magic == FS_UFS1_MAGIC) 245193326Sed blkno = bp->b_un.b_indir1[i]; 246193326Sed else 247198092Srdivacky blkno = bp->b_un.b_indir2[i]; 248193326Sed if (blkno == 0) { 249193326Sed if (level == 0) 250198092Srdivacky putchar('\n'); 251193326Sed return 0; 252193326Sed } 253198092Srdivacky j = sprintf(tempbuf, "%jd", (intmax_t)blkno); 254193326Sed if (level == 0) { 255193326Sed charssofar += j; 256193326Sed if (charssofar >= cpl - 2) { 257193326Sed putchar('\n'); 258193326Sed charssofar = j; 259193326Sed } 260193326Sed } 261193326Sed fputs(tempbuf, stdout); 262193326Sed if (level == 0) { 263193326Sed printf(", "); 264193326Sed charssofar += 2; 265193326Sed } else { 266193326Sed printf(" =>\n"); 267193326Sed if (printindir(blkno, level - 1, bufp) == 0) 268193326Sed return 0; 269193326Sed } 270193326Sed } 271193326Sed if (level == 0) 272193326Sed putchar('\n'); 273193326Sed return 1; 274193326Sed} 275198092Srdivacky 276193326Sed 277193326Sed/* 278193326Sed * Print the block pointers for one inode. 279193326Sed */ 280193326Sedstatic void 281193326Sedprintblocks(ino_t inum, union dinode *dp) 282193326Sed{ 283193326Sed char *bufp; 284193326Sed int i, nfrags; 285198092Srdivacky long ndb, offset; 286193326Sed ufs2_daddr_t blkno; 287193326Sed 288193326Sed printf("Blocks for inode %d:\n", inum); 289193326Sed printf("Direct blocks:\n"); 290193326Sed ndb = howmany(DIP(dp, di_size), sblock.fs_bsize); 291193326Sed for (i = 0; i < NDADDR; i++) { 292198092Srdivacky if (DIP(dp, di_db[i]) == 0) { 293193326Sed putchar('\n'); 294193326Sed return; 295193326Sed } 296193326Sed if (i > 0) 297193326Sed printf(", "); 298193326Sed blkno = DIP(dp, di_db[i]); 299193326Sed printf("%jd", (intmax_t)blkno); 300193326Sed if (--ndb == 0 && (offset = blkoff(&sblock, DIP(dp, di_size))) != 0) { 301198092Srdivacky nfrags = numfrags(&sblock, fragroundup(&sblock, offset)); 302193326Sed printf(" (%d frag%s)", nfrags, nfrags > 1? "s": ""); 303198092Srdivacky } 304193326Sed } 305193326Sed putchar('\n'); 306193326Sed if (DIP(dp, di_ib[0]) == 0) 307193326Sed return; 308193326Sed 309193326Sed bufp = malloc((unsigned int)sblock.fs_bsize); 310193326Sed if (bufp == 0) 311193326Sed errx(EEXIT, "cannot allocate indirect block buffer"); 312193326Sed printf("Indirect blocks:\n"); 313193326Sed for (i = 0; i < NIADDR; i++) 314193326Sed if (printindir(DIP(dp, di_ib[i]), i, bufp) == 0) 315193326Sed break; 316193326Sed free(bufp); 317193326Sed} 318193326Sed 319193326Sed 320193326Sedint 321193326Sedcheckactive(void) 322198092Srdivacky{ 323193326Sed if (!curinode) { 324193326Sed warnx("no current inode\n"); 325193326Sed return 0; 326193326Sed } 327193326Sed return 1; 328193326Sed} 329193326Sed 330193326Sedint 331193326Sedcheckactivedir(void) 332193326Sed{ 333193326Sed if (!curinode) { 334193326Sed warnx("no current inode\n"); 335193326Sed return 0; 336193326Sed } 337193326Sed if ((DIP(curinode, di_mode) & IFMT) != IFDIR) { 338193326Sed warnx("inode %d not a directory", curinum); 339193326Sed return 0; 340193326Sed } 341198092Srdivacky return 1; 342193326Sed} 343193326Sed 344193326Sedint 345198092Srdivackyprintactive(int doblocks) 346193326Sed{ 347193326Sed if (!checkactive()) 348193326Sed return 1; 349193326Sed switch (DIP(curinode, di_mode) & IFMT) { 350193326Sed case IFDIR: 351193326Sed case IFREG: 352193326Sed case IFBLK: 353193326Sed case IFCHR: 354193326Sed case IFLNK: 355193326Sed case IFSOCK: 356193326Sed case IFIFO: 357193326Sed if (doblocks) 358193326Sed printblocks(curinum, curinode); 359193326Sed else 360193326Sed printstat("current inode", curinum, curinode); 361193326Sed break; 362193326Sed case 0: 363193326Sed printf("current inode %d: unallocated inode\n", curinum); 364193326Sed break; 365193326Sed default: 366198092Srdivacky printf("current inode %d: screwy itype 0%o (mode 0%o)?\n", 367193326Sed curinum, DIP(curinode, di_mode) & IFMT, DIP(curinode, di_mode)); 368193326Sed break; 369193326Sed } 370193326Sed return 0; 371193326Sed} 372193326Sed