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