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$";
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