112048Speter/* $NetBSD: fsdbutil.c,v 1.2 1995/10/08 23:18:12 thorpej Exp $ */ 212048Speter 312048Speter/* 412048Speter * Copyright (c) 1995 John T. Kohl 512048Speter * All rights reserved. 612048Speter * 712048Speter * Redistribution and use in source and binary forms, with or without 812048Speter * modification, are permitted provided that the following conditions 912048Speter * are met: 1012048Speter * 1. Redistributions of source code must retain the above copyright 1112048Speter * notice, this list of conditions and the following disclaimer. 1212048Speter * 2. Redistributions in binary form must reproduce the above copyright 1312048Speter * notice, this list of conditions and the following disclaimer in the 1412048Speter * documentation and/or other materials provided with the distribution. 1512048Speter * 3. The name of the author may not be used to endorse or promote products 1612048Speter * derived from this software without specific prior written permission. 1712048Speter * 1812048Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 1912048Speter * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 2012048Speter * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 2112048Speter * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 2212048Speter * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 2312048Speter * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 2412048Speter * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2512048Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 2612048Speter * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 2712048Speter * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2812048Speter * POSSIBILITY OF SUCH DAMAGE. 2912048Speter */ 3012048Speter 3112048Speter#ifndef lint 3237001Scharnierstatic const char rcsid[] = 3350476Speter "$FreeBSD: releng/10.2/sbin/fsdb/fsdbutil.c 247234 2013-02-24 19:32:43Z pluknet $"; 3412048Speter#endif /* not lint */ 3512048Speter 3674594Salfred#include <sys/param.h> 3712048Speter#include <ctype.h> 3837001Scharnier#include <err.h> 3912048Speter#include <grp.h> 4012048Speter#include <pwd.h> 41122621Sjohan#include <stdint.h> 4212048Speter#include <string.h> 4337001Scharnier#include <time.h> 44122621Sjohan#include <timeconv.h> 4512048Speter 4612048Speter#include <ufs/ufs/dinode.h> 4774594Salfred#include <ufs/ffs/fs.h> 4812048Speter 4989827Sjoerg#include <sys/ioctl.h> 5089827Sjoerg 5112048Speter#include "fsdb.h" 5212048Speter#include "fsck.h" 5312048Speter 5492881Simpstatic int charsperline(void); 55207141Sjeffstatic void printindir(ufs2_daddr_t blk, int level, char *bufp); 5698542Smckusickstatic void printblocks(ino_t inum, union dinode *dp); 5789827Sjoerg 5812048Speterchar ** 5992881Simpcrack(char *line, int *argc) 6012048Speter{ 6112048Speter static char *argv[8]; 6212048Speter int i; 6312048Speter char *p, *val; 6412048Speter for (p = line, i = 0; p != NULL && i < 8; i++) { 6512048Speter while ((val = strsep(&p, " \t\n")) != NULL && *val == '\0') 6612048Speter /**/; 6712048Speter if (val) 6812048Speter argv[i] = val; 6912048Speter else 7012048Speter break; 7112048Speter } 7212048Speter *argc = i; 7312048Speter return argv; 7412048Speter} 7512048Speter 7689791Sgreenchar ** 7792881Simprecrack(char *line, int *argc, int argc_max) 7889791Sgreen{ 7989791Sgreen static char *argv[8]; 8089791Sgreen int i; 8189791Sgreen char *p, *val; 8289791Sgreen for (p = line, i = 0; p != NULL && i < 8 && i < argc_max - 1; i++) { 8389791Sgreen while ((val = strsep(&p, " \t\n")) != NULL && *val == '\0') 8489791Sgreen /**/; 8589791Sgreen if (val) 8689791Sgreen argv[i] = val; 8789791Sgreen else 8889791Sgreen break; 8989791Sgreen } 9089791Sgreen argv[i] = argv[i - 1] + strlen(argv[i - 1]) + 1; 9189791Sgreen argv[i][strcspn(argv[i], "\n")] = '\0'; 9289791Sgreen *argc = i + 1; 9389791Sgreen return argv; 9489791Sgreen} 9589791Sgreen 9612048Speterint 9792881Simpargcount(struct cmdtable *cmdp, int argc, char *argv[]) 9812048Speter{ 9912048Speter if (cmdp->minargc == cmdp->maxargc) 10089791Sgreen warnx("command `%s' takes %u arguments, got %u", cmdp->cmd, 101157950Smaxim cmdp->minargc-1, argc-1); 10212048Speter else 10312048Speter warnx("command `%s' takes from %u to %u arguments", 10412048Speter cmdp->cmd, cmdp->minargc-1, cmdp->maxargc-1); 10512048Speter 10612048Speter warnx("usage: %s: %s", cmdp->cmd, cmdp->helptxt); 10712048Speter return 1; 10812048Speter} 10912048Speter 11012048Spetervoid 11198542Smckusickprintstat(const char *cp, ino_t inum, union dinode *dp) 11212048Speter{ 11312048Speter struct group *grp; 11412048Speter struct passwd *pw; 11598542Smckusick ufs2_daddr_t blocks; 11698542Smckusick int64_t gen; 11712048Speter char *p; 11823854Sbde time_t t; 11912048Speter 12012048Speter printf("%s: ", cp); 12198542Smckusick switch (DIP(dp, di_mode) & IFMT) { 12212048Speter case IFDIR: 12312048Speter puts("directory"); 12412048Speter break; 12512048Speter case IFREG: 12612048Speter puts("regular file"); 12712048Speter break; 12812048Speter case IFBLK: 129225847Sed printf("block special (%#jx)", (uintmax_t)DIP(dp, di_rdev)); 13012048Speter break; 13112048Speter case IFCHR: 132225847Sed printf("character special (%#jx)", DIP(dp, di_rdev)); 13312048Speter break; 13412048Speter case IFLNK: 13512048Speter fputs("symlink",stdout); 13698542Smckusick if (DIP(dp, di_size) > 0 && 13798542Smckusick DIP(dp, di_size) < sblock.fs_maxsymlinklen && 13898542Smckusick DIP(dp, di_blocks) == 0) { 13998542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 14098542Smckusick p = (caddr_t)dp->dp1.di_db; 14198542Smckusick else 14298542Smckusick p = (caddr_t)dp->dp2.di_db; 14398542Smckusick printf(" to `%.*s'\n", (int) DIP(dp, di_size), p); 14498542Smckusick } else { 14598542Smckusick putchar('\n'); 14698542Smckusick } 14712048Speter break; 14812048Speter case IFSOCK: 14912048Speter puts("socket"); 15012048Speter break; 15112048Speter case IFIFO: 15212048Speter puts("fifo"); 15312048Speter break; 15412048Speter } 155241013Smdf printf("I=%ju MODE=%o SIZE=%ju", (uintmax_t)inum, DIP(dp, di_mode), 156122621Sjohan (uintmax_t)DIP(dp, di_size)); 157161558Sceri if (sblock.fs_magic != FS_UFS1_MAGIC) { 158161558Sceri t = _time64_to_time(dp->dp2.di_birthtime); 159161558Sceri p = ctime(&t); 160161558Sceri printf("\n\tBTIME=%15.15s %4.4s [%d nsec]", &p[4], &p[20], 161161558Sceri dp->dp2.di_birthnsec); 162161558Sceri } 16398542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 16498542Smckusick t = _time32_to_time(dp->dp1.di_mtime); 16598542Smckusick else 16698542Smckusick t = _time64_to_time(dp->dp2.di_mtime); 16723854Sbde p = ctime(&t); 16812048Speter printf("\n\tMTIME=%15.15s %4.4s [%d nsec]", &p[4], &p[20], 16998542Smckusick DIP(dp, di_mtimensec)); 17098542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 17198542Smckusick t = _time32_to_time(dp->dp1.di_ctime); 17298542Smckusick else 17398542Smckusick t = _time64_to_time(dp->dp2.di_ctime); 17423854Sbde p = ctime(&t); 17512048Speter printf("\n\tCTIME=%15.15s %4.4s [%d nsec]", &p[4], &p[20], 17698542Smckusick DIP(dp, di_ctimensec)); 17798542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 17898542Smckusick t = _time32_to_time(dp->dp1.di_atime); 17998542Smckusick else 18098542Smckusick t = _time64_to_time(dp->dp2.di_atime); 18123854Sbde p = ctime(&t); 18212048Speter printf("\n\tATIME=%15.15s %4.4s [%d nsec]\n", &p[4], &p[20], 18398542Smckusick DIP(dp, di_atimensec)); 18412048Speter 18598542Smckusick if ((pw = getpwuid(DIP(dp, di_uid)))) 18612048Speter printf("OWNER=%s ", pw->pw_name); 18712048Speter else 18898542Smckusick printf("OWNUID=%u ", DIP(dp, di_uid)); 18998542Smckusick if ((grp = getgrgid(DIP(dp, di_gid)))) 19012048Speter printf("GRP=%s ", grp->gr_name); 19112048Speter else 19298542Smckusick printf("GID=%u ", DIP(dp, di_gid)); 19312048Speter 19498542Smckusick blocks = DIP(dp, di_blocks); 19598542Smckusick gen = DIP(dp, di_gen); 196232749Sdim printf("LINKCNT=%d FLAGS=%#x BLKCNT=%jx GEN=%jx\n", DIP(dp, di_nlink), 197228693Sdim DIP(dp, di_flags), (intmax_t)blocks, (intmax_t)gen); 19812048Speter} 19912048Speter 20089827Sjoerg 20189827Sjoerg/* 20289827Sjoerg * Determine the number of characters in a 20389827Sjoerg * single line. 20489827Sjoerg */ 20589827Sjoerg 20689827Sjoergstatic int 20792881Simpcharsperline(void) 20889827Sjoerg{ 20989827Sjoerg int columns; 21089827Sjoerg char *cp; 21189827Sjoerg struct winsize ws; 21289827Sjoerg 21389827Sjoerg columns = 0; 21489827Sjoerg if (ioctl(0, TIOCGWINSZ, &ws) != -1) 21589827Sjoerg columns = ws.ws_col; 21689827Sjoerg if (columns == 0 && (cp = getenv("COLUMNS"))) 21789827Sjoerg columns = atoi(cp); 21889827Sjoerg if (columns == 0) 21989827Sjoerg columns = 80; /* last resort */ 22089827Sjoerg return (columns); 22189827Sjoerg} 22289827Sjoerg 22389827Sjoerg 22489827Sjoerg/* 22589827Sjoerg * Recursively print a list of indirect blocks. 22689827Sjoerg */ 227207141Sjeffstatic void 22898542Smckusickprintindir(ufs2_daddr_t blk, int level, char *bufp) 22989827Sjoerg{ 23089827Sjoerg struct bufarea buf, *bp; 23198542Smckusick char tempbuf[32]; /* enough to print an ufs2_daddr_t */ 23289827Sjoerg int i, j, cpl, charssofar; 23398542Smckusick ufs2_daddr_t blkno; 23489827Sjoerg 235207141Sjeff if (blk == 0) 236207141Sjeff return; 237207141Sjeff printf("%jd (%d) =>\n", (intmax_t)blk, level); 23889827Sjoerg if (level == 0) { 23989827Sjoerg /* for the final indirect level, don't use the cache */ 24089827Sjoerg bp = &buf; 24189827Sjoerg bp->b_un.b_buf = bufp; 242247234Spluknet initbarea(bp, BT_UNKNOWN); 24389827Sjoerg 24489827Sjoerg getblk(bp, blk, sblock.fs_bsize); 24589827Sjoerg } else 246247234Spluknet bp = getdatablk(blk, sblock.fs_bsize, BT_UNKNOWN); 24789827Sjoerg 24889827Sjoerg cpl = charsperline(); 24989827Sjoerg for (i = charssofar = 0; i < NINDIR(&sblock); i++) { 25098542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 25198542Smckusick blkno = bp->b_un.b_indir1[i]; 25298542Smckusick else 25398542Smckusick blkno = bp->b_un.b_indir2[i]; 254207141Sjeff if (blkno == 0) 255207141Sjeff continue; 256122621Sjohan j = sprintf(tempbuf, "%jd", (intmax_t)blkno); 25789827Sjoerg if (level == 0) { 25889827Sjoerg charssofar += j; 25989827Sjoerg if (charssofar >= cpl - 2) { 26089827Sjoerg putchar('\n'); 26189827Sjoerg charssofar = j; 26289827Sjoerg } 26389827Sjoerg } 26489827Sjoerg fputs(tempbuf, stdout); 26589827Sjoerg if (level == 0) { 26689827Sjoerg printf(", "); 26789827Sjoerg charssofar += 2; 26889827Sjoerg } else { 26989827Sjoerg printf(" =>\n"); 270207141Sjeff printindir(blkno, level - 1, bufp); 271207141Sjeff printf("\n"); 272207141Sjeff charssofar = 0; 27389827Sjoerg } 27489827Sjoerg } 27589827Sjoerg if (level == 0) 27689827Sjoerg putchar('\n'); 277207141Sjeff return; 27889827Sjoerg} 27989827Sjoerg 28089827Sjoerg 28189827Sjoerg/* 28289827Sjoerg * Print the block pointers for one inode. 28389827Sjoerg */ 28489827Sjoergstatic void 28598542Smckusickprintblocks(ino_t inum, union dinode *dp) 28689827Sjoerg{ 28789827Sjoerg char *bufp; 288122621Sjohan int i, nfrags; 28989827Sjoerg long ndb, offset; 29098542Smckusick ufs2_daddr_t blkno; 29189827Sjoerg 292241013Smdf printf("Blocks for inode %ju:\n", (uintmax_t)inum); 29389827Sjoerg printf("Direct blocks:\n"); 29498542Smckusick ndb = howmany(DIP(dp, di_size), sblock.fs_bsize); 295231102Struckman for (i = 0; i < NDADDR && i < ndb; i++) { 29689827Sjoerg if (i > 0) 29789827Sjoerg printf(", "); 29898542Smckusick blkno = DIP(dp, di_db[i]); 299122621Sjohan printf("%jd", (intmax_t)blkno); 300231102Struckman } 301231102Struckman if (ndb <= NDADDR) { 302231102Struckman offset = blkoff(&sblock, DIP(dp, di_size)); 303231102Struckman if (offset != 0) { 30489827Sjoerg nfrags = numfrags(&sblock, fragroundup(&sblock, offset)); 30589827Sjoerg printf(" (%d frag%s)", nfrags, nfrags > 1? "s": ""); 30689827Sjoerg } 30789827Sjoerg } 30889827Sjoerg putchar('\n'); 309231102Struckman if (ndb <= NDADDR) 31089827Sjoerg return; 31189827Sjoerg 31289827Sjoerg bufp = malloc((unsigned int)sblock.fs_bsize); 31389827Sjoerg if (bufp == 0) 31489827Sjoerg errx(EEXIT, "cannot allocate indirect block buffer"); 31589827Sjoerg printf("Indirect blocks:\n"); 31689827Sjoerg for (i = 0; i < NIADDR; i++) 317207141Sjeff printindir(DIP(dp, di_ib[i]), i, bufp); 31889827Sjoerg free(bufp); 31989827Sjoerg} 32089827Sjoerg 32189827Sjoerg 32212048Speterint 32392881Simpcheckactive(void) 32412048Speter{ 32512048Speter if (!curinode) { 32612048Speter warnx("no current inode\n"); 32712048Speter return 0; 32812048Speter } 32912048Speter return 1; 33012048Speter} 33112048Speter 33212048Speterint 33392881Simpcheckactivedir(void) 33412048Speter{ 33512048Speter if (!curinode) { 33612048Speter warnx("no current inode\n"); 33712048Speter return 0; 33812048Speter } 33998542Smckusick if ((DIP(curinode, di_mode) & IFMT) != IFDIR) { 340241013Smdf warnx("inode %ju not a directory", (uintmax_t)curinum); 34112048Speter return 0; 34212048Speter } 34312048Speter return 1; 34412048Speter} 34512048Speter 34612048Speterint 34792881Simpprintactive(int doblocks) 34812048Speter{ 34912048Speter if (!checkactive()) 35012048Speter return 1; 35198542Smckusick switch (DIP(curinode, di_mode) & IFMT) { 35212048Speter case IFDIR: 35312048Speter case IFREG: 35412048Speter case IFBLK: 35512048Speter case IFCHR: 35612048Speter case IFLNK: 35712048Speter case IFSOCK: 35812048Speter case IFIFO: 35989827Sjoerg if (doblocks) 36089827Sjoerg printblocks(curinum, curinode); 36189827Sjoerg else 36289827Sjoerg printstat("current inode", curinum, curinode); 36312048Speter break; 36412048Speter case 0: 365241013Smdf printf("current inode %ju: unallocated inode\n", (uintmax_t)curinum); 36612048Speter break; 36712048Speter default: 368241013Smdf printf("current inode %ju: screwy itype 0%o (mode 0%o)?\n", 369241013Smdf (uintmax_t)curinum, DIP(curinode, di_mode) & IFMT, 370241013Smdf DIP(curinode, di_mode)); 37112048Speter break; 37212048Speter } 37312048Speter return 0; 37412048Speter} 375