xref: /freebsd/sbin/fsdb/fsdb.c (revision eba230afba4932f02a1ca44efc797cf7499a5cb0)
139bb6d1eSPeter Wemm /*	$NetBSD: fsdb.c,v 1.2 1995/10/08 23:18:10 thorpej Exp $	*/
239bb6d1eSPeter Wemm 
31de7b4b8SPedro F. Giffuni /*-
41de7b4b8SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
51de7b4b8SPedro F. Giffuni  *
639bb6d1eSPeter Wemm  *  Copyright (c) 1995 John T. Kohl
739bb6d1eSPeter Wemm  *  All rights reserved.
839bb6d1eSPeter Wemm  *
939bb6d1eSPeter Wemm  *  Redistribution and use in source and binary forms, with or without
1039bb6d1eSPeter Wemm  *  modification, are permitted provided that the following conditions
1139bb6d1eSPeter Wemm  *  are met:
1239bb6d1eSPeter Wemm  *  1. Redistributions of source code must retain the above copyright
1339bb6d1eSPeter Wemm  *     notice, this list of conditions and the following disclaimer.
1439bb6d1eSPeter Wemm  *  2. Redistributions in binary form must reproduce the above copyright
1539bb6d1eSPeter Wemm  *     notice, this list of conditions and the following disclaimer in the
1639bb6d1eSPeter Wemm  *     documentation and/or other materials provided with the distribution.
1739bb6d1eSPeter Wemm  *  3. The name of the author may not be used to endorse or promote products
1839bb6d1eSPeter Wemm  *     derived from this software without specific prior written permission.
1939bb6d1eSPeter Wemm  *
2039bb6d1eSPeter Wemm  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
2139bb6d1eSPeter Wemm  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2239bb6d1eSPeter Wemm  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2339bb6d1eSPeter Wemm  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
2439bb6d1eSPeter Wemm  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2539bb6d1eSPeter Wemm  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2639bb6d1eSPeter Wemm  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2739bb6d1eSPeter Wemm  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2839bb6d1eSPeter Wemm  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
2939bb6d1eSPeter Wemm  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3039bb6d1eSPeter Wemm  * POSSIBILITY OF SUCH DAMAGE.
3139bb6d1eSPeter Wemm  */
3239bb6d1eSPeter Wemm 
3339bb6d1eSPeter Wemm #include <sys/param.h>
3439bb6d1eSPeter Wemm #include <ctype.h>
350227048aSPhilippe Charnier #include <err.h>
3639bb6d1eSPeter Wemm #include <grp.h>
3739bb6d1eSPeter Wemm #include <histedit.h>
3839bb6d1eSPeter Wemm #include <pwd.h>
39e25a029eSMatthew D Fleming #include <stdint.h>
4039bb6d1eSPeter Wemm #include <string.h>
417649cb00SKirk McKusick #include <time.h>
428b5e064dSJohan Karlsson #include <timeconv.h>
4339bb6d1eSPeter Wemm 
4439bb6d1eSPeter Wemm #include <ufs/ufs/dinode.h>
4539bb6d1eSPeter Wemm #include <ufs/ufs/dir.h>
4639bb6d1eSPeter Wemm #include <ufs/ffs/fs.h>
4739bb6d1eSPeter Wemm 
4839bb6d1eSPeter Wemm #include "fsdb.h"
4939bb6d1eSPeter Wemm #include "fsck.h"
5039bb6d1eSPeter Wemm 
510638cc1aSWarner Losh static void usage(void) __dead2;
520638cc1aSWarner Losh int cmdloop(void);
5382d9b14eSMaxim Konovalov static int compare_blk32(uint32_t *wantedblk, uint32_t curblk);
5482d9b14eSMaxim Konovalov static int compare_blk64(uint64_t *wantedblk, uint64_t curblk);
5582d9b14eSMaxim Konovalov static int founddatablk(uint64_t blk);
5682d9b14eSMaxim Konovalov static int find_blks32(uint32_t *buf, int size, uint32_t *blknum);
5782d9b14eSMaxim Konovalov static int find_blks64(uint64_t *buf, int size, uint64_t *blknum);
5882d9b14eSMaxim Konovalov static int find_indirblks32(uint32_t blk, int ind_level, uint32_t *blknum);
5982d9b14eSMaxim Konovalov static int find_indirblks64(uint64_t blk, int ind_level, uint64_t *blknum);
6039bb6d1eSPeter Wemm 
61d51bdf32SKirk McKusick /*
62d51bdf32SKirk McKusick  * Track modifications to the filesystem. Two types of changes are tracked.
63d51bdf32SKirk McKusick  * The first type of changes are those that are not critical to the integrity
64d51bdf32SKirk McKusick  * of the filesystem such as owner, group, time stamps, access mode, and
65d51bdf32SKirk McKusick  * generation number. The second type of changes are those that do affect
66d51bdf32SKirk McKusick  * the integrity of the filesystem including zeroing inodes, changing block
67d51bdf32SKirk McKusick  * pointers, directory entries, link counts, file lengths, file types and
68d51bdf32SKirk McKusick  * file flags.
69d51bdf32SKirk McKusick  *
70d51bdf32SKirk McKusick  * When quitting having made no changes or only changes to data that is not
71d51bdf32SKirk McKusick  * critical to filesystem integrity, the clean state of the filesystem is
72d51bdf32SKirk McKusick  * left unchanged. But if filesystem critical data are changed then fsdb
73d51bdf32SKirk McKusick  * will set the unclean flag which will require a full fsck to be run
74d51bdf32SKirk McKusick  * before the filesystem can be mounted.
75d51bdf32SKirk McKusick  */
76d51bdf32SKirk McKusick static int fsnoncritmodified;	/* filesystem non-critical modifications */
77d51bdf32SKirk McKusick static int fscritmodified;	/* filesystem integrity critical mods */
785cc52631SKirk McKusick struct inode curip;
795cc52631SKirk McKusick union dinode *curinode;
805cc52631SKirk McKusick ino_t curinum, ocurrent;
815cc52631SKirk McKusick 
82617f1bc8SPhilippe Charnier static void
usage(void)830638cc1aSWarner Losh usage(void)
8439bb6d1eSPeter Wemm {
85617f1bc8SPhilippe Charnier 	fprintf(stderr, "usage: fsdb [-d] [-f] [-r] fsname\n");
86617f1bc8SPhilippe Charnier 	exit(1);
8739bb6d1eSPeter Wemm }
8839bb6d1eSPeter Wemm 
8939bb6d1eSPeter Wemm /*
9039bb6d1eSPeter Wemm  * We suck in lots of fsck code, and just pick & choose the stuff we want.
9139bb6d1eSPeter Wemm  *
9239bb6d1eSPeter Wemm  * fsreadfd is set up to read from the file system, fswritefd to write to
9339bb6d1eSPeter Wemm  * the file system.
9439bb6d1eSPeter Wemm  */
95ebe70c8fSWarner Losh int
main(int argc,char * argv[])960638cc1aSWarner Losh main(int argc, char *argv[])
9739bb6d1eSPeter Wemm {
9839bb6d1eSPeter Wemm 	int ch, rval;
9939bb6d1eSPeter Wemm 	char *fsys = NULL;
10039bb6d1eSPeter Wemm 
101617f1bc8SPhilippe Charnier 	while (-1 != (ch = getopt(argc, argv, "fdr"))) {
10239bb6d1eSPeter Wemm 		switch (ch) {
10339bb6d1eSPeter Wemm 		case 'f':
104617f1bc8SPhilippe Charnier 			/* The -f option is left for historical
105617f1bc8SPhilippe Charnier 			 * reasons and has no meaning.
106617f1bc8SPhilippe Charnier 			 */
10739bb6d1eSPeter Wemm 			break;
10839bb6d1eSPeter Wemm 		case 'd':
10939bb6d1eSPeter Wemm 			debug++;
11039bb6d1eSPeter Wemm 			break;
11136b8baa3SJoerg Wunsch 		case 'r':
11236b8baa3SJoerg Wunsch 			nflag++; /* "no" in fsck, readonly for us */
11336b8baa3SJoerg Wunsch 			break;
11439bb6d1eSPeter Wemm 		default:
11539bb6d1eSPeter Wemm 			usage();
11639bb6d1eSPeter Wemm 		}
11739bb6d1eSPeter Wemm 	}
118fe3a5bd4SGuido van Rooij 	argc -= optind;
119fe3a5bd4SGuido van Rooij 	argv += optind;
120fe3a5bd4SGuido van Rooij 	if (argc != 1)
12139bb6d1eSPeter Wemm 		usage();
122fe3a5bd4SGuido van Rooij 	else
123fe3a5bd4SGuido van Rooij 		fsys = argv[0];
124fe3a5bd4SGuido van Rooij 
125d164d805SIan Dowse 	sblock_init();
126e6886616SKirk McKusick 	if (openfilesys(fsys) == 0 || readsb() == 0 || setup(fsys) == 0)
12739bb6d1eSPeter Wemm 		errx(1, "cannot set up file system `%s'", fsys);
12868d7185bSKirk McKusick 	if (fswritefd < 0)
12968d7185bSKirk McKusick 		nflag++;
13036b8baa3SJoerg Wunsch 	printf("%s file system `%s'\nLast Mounted on %s\n",
13136b8baa3SJoerg Wunsch 	       nflag? "Examining": "Editing", fsys, sblock.fs_fsmnt);
13239bb6d1eSPeter Wemm 	rval = cmdloop();
13336b8baa3SJoerg Wunsch 	if (!nflag) {
134d51bdf32SKirk McKusick 		if (fscritmodified != 0) {
13539bb6d1eSPeter Wemm 			sblock.fs_clean = 0;	/* mark it dirty */
13639bb6d1eSPeter Wemm 			sbdirty();
137d51bdf32SKirk McKusick 		}
138d51bdf32SKirk McKusick 		ckfini(fscritmodified ? 0 : sblock.fs_clean);
139d51bdf32SKirk McKusick 		if (fscritmodified == 0)
140d51bdf32SKirk McKusick 			exit(0);
14139bb6d1eSPeter Wemm 		printf("*** FILE SYSTEM MARKED DIRTY\n");
14239bb6d1eSPeter Wemm 		printf("*** BE SURE TO RUN FSCK TO CLEAN UP ANY DAMAGE\n");
1435cc52631SKirk McKusick 		printf("*** IF IT IS MOUNTED, RE-MOUNT WITH -u -o reload\n");
14436b8baa3SJoerg Wunsch 	}
14539bb6d1eSPeter Wemm 	exit(rval);
14639bb6d1eSPeter Wemm }
14739bb6d1eSPeter Wemm 
1480638cc1aSWarner Losh #define CMDFUNC(func) int func(int argc, char *argv[])
1490638cc1aSWarner Losh #define CMDFUNCSTART(func) int func(int argc, char *argv[])
15039bb6d1eSPeter Wemm 
15139bb6d1eSPeter Wemm CMDFUNC(helpfn);
15239bb6d1eSPeter Wemm CMDFUNC(focus);				/* focus on inode */
15339bb6d1eSPeter Wemm CMDFUNC(active);			/* print active inode */
154280a49ecSJoerg Wunsch CMDFUNC(blocks);			/* print blocks for active inode */
15539bb6d1eSPeter Wemm CMDFUNC(focusname);			/* focus by name */
15639bb6d1eSPeter Wemm CMDFUNC(zapi);				/* clear inode */
15739bb6d1eSPeter Wemm CMDFUNC(uplink);			/* incr link */
15839bb6d1eSPeter Wemm CMDFUNC(downlink);			/* decr link */
15939bb6d1eSPeter Wemm CMDFUNC(linkcount);			/* set link count */
16039bb6d1eSPeter Wemm CMDFUNC(quit);				/* quit */
161*d059e44bSKirk McKusick CMDFUNC(quitclean);			/* quit with filesystem marked clean */
16282d9b14eSMaxim Konovalov CMDFUNC(findblk);			/* find block */
16339bb6d1eSPeter Wemm CMDFUNC(ls);				/* list directory */
16439bb6d1eSPeter Wemm CMDFUNC(rm);				/* remove name */
16539bb6d1eSPeter Wemm CMDFUNC(ln);				/* add name */
16639bb6d1eSPeter Wemm CMDFUNC(newtype);			/* change type */
16739bb6d1eSPeter Wemm CMDFUNC(chmode);			/* change mode */
168a9bb2677SGuido van Rooij CMDFUNC(chlen);				/* change length */
16939bb6d1eSPeter Wemm CMDFUNC(chaflags);			/* change flags */
17039bb6d1eSPeter Wemm CMDFUNC(chgen);				/* change generation */
17139bb6d1eSPeter Wemm CMDFUNC(chowner);			/* change owner */
17239bb6d1eSPeter Wemm CMDFUNC(chgroup);			/* Change group */
17339bb6d1eSPeter Wemm CMDFUNC(back);				/* pop back to last ino */
17496dd6360SCeri Davies CMDFUNC(chbtime);			/* Change btime */
17539bb6d1eSPeter Wemm CMDFUNC(chmtime);			/* Change mtime */
17639bb6d1eSPeter Wemm CMDFUNC(chctime);			/* Change ctime */
17739bb6d1eSPeter Wemm CMDFUNC(chatime);			/* Change atime */
17839bb6d1eSPeter Wemm CMDFUNC(chinum);			/* Change inode # of dirent */
17939bb6d1eSPeter Wemm CMDFUNC(chname);			/* Change dirname of dirent */
180ac4b20a0SKirk McKusick CMDFUNC(chsize);			/* Change size */
1817636973cSKirk McKusick CMDFUNC(chdb);				/* Change direct block pointer */
18239bb6d1eSPeter Wemm 
18339bb6d1eSPeter Wemm struct cmdtable cmds[] = {
18436b8baa3SJoerg Wunsch 	{ "help", "Print out help", 1, 1, FL_RO, helpfn },
18536b8baa3SJoerg Wunsch 	{ "?", "Print out help", 1, 1, FL_RO, helpfn },
18636b8baa3SJoerg Wunsch 	{ "inode", "Set active inode to INUM", 2, 2, FL_RO, focus },
187d51bdf32SKirk McKusick 	{ "clri", "Clear inode INUM", 2, 2, FL_CWR, zapi },
1881bc50849SMaxim Konovalov 	{ "lookup", "Set active inode by looking up NAME", 2, 2, FL_RO | FL_ST, focusname },
1891bc50849SMaxim Konovalov 	{ "cd", "Set active inode by looking up NAME", 2, 2, FL_RO | FL_ST, focusname },
19036b8baa3SJoerg Wunsch 	{ "back", "Go to previous active inode", 1, 1, FL_RO, back },
19136b8baa3SJoerg Wunsch 	{ "active", "Print active inode", 1, 1, FL_RO, active },
19236b8baa3SJoerg Wunsch 	{ "print", "Print active inode", 1, 1, FL_RO, active },
193280a49ecSJoerg Wunsch 	{ "blocks", "Print block numbers of active inode", 1, 1, FL_RO, blocks },
194d51bdf32SKirk McKusick 	{ "uplink", "Increment link count", 1, 1, FL_CWR, uplink },
195d51bdf32SKirk McKusick 	{ "downlink", "Decrement link count", 1, 1, FL_CWR, downlink },
196d51bdf32SKirk McKusick 	{ "linkcount", "Set link count to COUNT", 2, 2, FL_CWR, linkcount },
19782d9b14eSMaxim Konovalov 	{ "findblk", "Find inode owning disk block(s)", 2, 33, FL_RO, findblk},
19836b8baa3SJoerg Wunsch 	{ "ls", "List current inode as directory", 1, 1, FL_RO, ls },
199d51bdf32SKirk McKusick 	{ "rm", "Remove NAME from current inode directory", 2, 2, FL_CWR | FL_ST, rm },
200d51bdf32SKirk McKusick 	{ "del", "Remove NAME from current inode directory", 2, 2, FL_CWR | FL_ST, rm },
201d51bdf32SKirk McKusick 	{ "ln", "Hardlink INO into current inode directory as NAME", 3, 3, FL_CWR | FL_ST, ln },
202d51bdf32SKirk McKusick 	{ "chinum", "Change dir entry number INDEX to INUM", 3, 3, FL_CWR, chinum },
2031bc50849SMaxim Konovalov 	{ "chname", "Change dir entry number INDEX to NAME", 3, 3, FL_WR | FL_ST, chname },
204d51bdf32SKirk McKusick 	{ "chtype", "Change type of current inode to TYPE", 2, 2, FL_CWR, newtype },
20536b8baa3SJoerg Wunsch 	{ "chmod", "Change mode of current inode to MODE", 2, 2, FL_WR, chmode },
20636b8baa3SJoerg Wunsch 	{ "chown", "Change owner of current inode to OWNER", 2, 2, FL_WR, chowner },
20736b8baa3SJoerg Wunsch 	{ "chgrp", "Change group of current inode to GROUP", 2, 2, FL_WR, chgroup },
208d51bdf32SKirk McKusick 	{ "chflags", "Change flags of current inode to FLAGS", 2, 2, FL_CWR, chaflags },
20936b8baa3SJoerg Wunsch 	{ "chgen", "Change generation number of current inode to GEN", 2, 2, FL_WR, chgen },
210d51bdf32SKirk McKusick 	{ "chsize", "Change size of current inode to SIZE", 2, 2, FL_CWR, chsize },
21196dd6360SCeri Davies 	{ "btime", "Change btime of current inode to BTIME", 2, 2, FL_WR, chbtime },
21236b8baa3SJoerg Wunsch 	{ "mtime", "Change mtime of current inode to MTIME", 2, 2, FL_WR, chmtime },
21336b8baa3SJoerg Wunsch 	{ "ctime", "Change ctime of current inode to CTIME", 2, 2, FL_WR, chctime },
21436b8baa3SJoerg Wunsch 	{ "atime", "Change atime of current inode to ATIME", 2, 2, FL_WR, chatime },
215d51bdf32SKirk McKusick 	{ "chdb", "Change db pointer N of current inode to BLKNO", 3, 3, FL_CWR, chdb },
216*d059e44bSKirk McKusick 	{ "quitclean", "Exit with filesystem marked clean", 1, 1, FL_RO, quitclean },
21736b8baa3SJoerg Wunsch 	{ "quit", "Exit", 1, 1, FL_RO, quit },
21836b8baa3SJoerg Wunsch 	{ "q", "Exit", 1, 1, FL_RO, quit },
21936b8baa3SJoerg Wunsch 	{ "exit", "Exit", 1, 1, FL_RO, quit },
220c9eaf226SLukas Ertl 	{ NULL, 0, 0, 0, 0, NULL },
22139bb6d1eSPeter Wemm };
22239bb6d1eSPeter Wemm 
22339bb6d1eSPeter Wemm int
helpfn(int argc,char * argv[])2240638cc1aSWarner Losh helpfn(int argc, char *argv[])
22539bb6d1eSPeter Wemm {
2263d438ad6SDavid E. O'Brien     struct cmdtable *cmdtp;
22739bb6d1eSPeter Wemm 
22839bb6d1eSPeter Wemm     printf("Commands are:\n%-10s %5s %5s   %s\n",
2291bc50849SMaxim Konovalov 	   "command", "min args", "max args", "what");
23039bb6d1eSPeter Wemm 
23139bb6d1eSPeter Wemm     for (cmdtp = cmds; cmdtp->cmd; cmdtp++)
23239bb6d1eSPeter Wemm 	printf("%-10s %5u %5u   %s\n",
2331bc50849SMaxim Konovalov 		cmdtp->cmd, cmdtp->minargc-1, cmdtp->maxargc-1, cmdtp->helptxt);
23439bb6d1eSPeter Wemm     return 0;
23539bb6d1eSPeter Wemm }
23639bb6d1eSPeter Wemm 
23739bb6d1eSPeter Wemm char *
prompt(EditLine * el)2380638cc1aSWarner Losh prompt(EditLine *el)
23939bb6d1eSPeter Wemm {
24039bb6d1eSPeter Wemm     static char pstring[64];
241e25a029eSMatthew D Fleming     snprintf(pstring, sizeof(pstring), "fsdb (inum: %ju)> ",
242e25a029eSMatthew D Fleming 	(uintmax_t)curinum);
24339bb6d1eSPeter Wemm     return pstring;
24439bb6d1eSPeter Wemm }
24539bb6d1eSPeter Wemm 
2465cc52631SKirk McKusick static void
setcurinode(ino_t inum)2475cc52631SKirk McKusick setcurinode(ino_t inum)
2485cc52631SKirk McKusick {
2495cc52631SKirk McKusick 
2505cc52631SKirk McKusick 	if (curip.i_number != 0)
2515cc52631SKirk McKusick 		irelse(&curip);
2525cc52631SKirk McKusick 	ginode(inum, &curip);
2535cc52631SKirk McKusick 	curinode = curip.i_dp;
2545cc52631SKirk McKusick 	curinum = inum;
2555cc52631SKirk McKusick }
25639bb6d1eSPeter Wemm 
25739bb6d1eSPeter Wemm int
cmdloop(void)2580638cc1aSWarner Losh cmdloop(void)
25939bb6d1eSPeter Wemm {
26039bb6d1eSPeter Wemm     char *line;
26139bb6d1eSPeter Wemm     const char *elline;
26239bb6d1eSPeter Wemm     int cmd_argc, rval = 0, known;
26339bb6d1eSPeter Wemm #define scratch known
26439bb6d1eSPeter Wemm     char **cmd_argv;
26539bb6d1eSPeter Wemm     struct cmdtable *cmdp;
26639bb6d1eSPeter Wemm     History *hist;
26739bb6d1eSPeter Wemm     EditLine *elptr;
268757eeda0SDavid E. O'Brien     HistEvent he;
26939bb6d1eSPeter Wemm 
2705cc52631SKirk McKusick     setcurinode(UFS_ROOTINO);
271280a49ecSJoerg Wunsch     printactive(0);
27239bb6d1eSPeter Wemm 
27339bb6d1eSPeter Wemm     hist = history_init();
2742110d9c3SStefan Farfeleder     history(hist, &he, H_SETSIZE, 100);	/* 100 elt history buffer */
27539bb6d1eSPeter Wemm 
276757eeda0SDavid E. O'Brien     elptr = el_init("fsdb", stdin, stdout, stderr);
27739bb6d1eSPeter Wemm     el_set(elptr, EL_EDITOR, "emacs");
27839bb6d1eSPeter Wemm     el_set(elptr, EL_PROMPT, prompt);
27939bb6d1eSPeter Wemm     el_set(elptr, EL_HIST, history, hist);
28039bb6d1eSPeter Wemm     el_source(elptr, NULL);
28139bb6d1eSPeter Wemm 
28239bb6d1eSPeter Wemm     while ((elline = el_gets(elptr, &scratch)) != NULL && scratch != 0) {
28339bb6d1eSPeter Wemm 	if (debug)
2840227048aSPhilippe Charnier 	    printf("command `%s'\n", elline);
28539bb6d1eSPeter Wemm 
286757eeda0SDavid E. O'Brien 	history(hist, &he, H_ENTER, elline);
28739bb6d1eSPeter Wemm 
28839bb6d1eSPeter Wemm 	line = strdup(elline);
28939bb6d1eSPeter Wemm 	cmd_argv = crack(line, &cmd_argc);
29039bb6d1eSPeter Wemm 	/*
29139bb6d1eSPeter Wemm 	 * el_parse returns -1 to signal that it's not been handled
29239bb6d1eSPeter Wemm 	 * internally.
29339bb6d1eSPeter Wemm 	 */
294515faf2fSStefan Farfeleder 	if (el_parse(elptr, cmd_argc, (const char **)cmd_argv) != -1)
29539bb6d1eSPeter Wemm 	    continue;
29639bb6d1eSPeter Wemm 	if (cmd_argc) {
29739bb6d1eSPeter Wemm 	    known = 0;
29839bb6d1eSPeter Wemm 	    for (cmdp = cmds; cmdp->cmd; cmdp++) {
29939bb6d1eSPeter Wemm 		if (!strcmp(cmdp->cmd, cmd_argv[0])) {
300d51bdf32SKirk McKusick 		    if ((cmdp->flags & (FL_CWR | FL_WR)) != 0 && nflag)
30136b8baa3SJoerg Wunsch 			warnx("`%s' requires write access", cmd_argv[0]),
30236b8baa3SJoerg Wunsch 			    rval = 1;
30336b8baa3SJoerg Wunsch 		    else if (cmd_argc >= cmdp->minargc &&
30439bb6d1eSPeter Wemm 			cmd_argc <= cmdp->maxargc)
30539bb6d1eSPeter Wemm 			rval = (*cmdp->handler)(cmd_argc, cmd_argv);
3061bc50849SMaxim Konovalov 		    else if (cmd_argc >= cmdp->minargc &&
3071bc50849SMaxim Konovalov 			(cmdp->flags & FL_ST) == FL_ST) {
3088660ce22SBrian Feldman 			strcpy(line, elline);
3098660ce22SBrian Feldman 			cmd_argv = recrack(line, &cmd_argc, cmdp->maxargc);
3108660ce22SBrian Feldman 			rval = (*cmdp->handler)(cmd_argc, cmd_argv);
3118660ce22SBrian Feldman 		    } else
31239bb6d1eSPeter Wemm 			rval = argcount(cmdp, cmd_argc, cmd_argv);
31339bb6d1eSPeter Wemm 		    known = 1;
314d51bdf32SKirk McKusick 		    if (rval == 0) {
315d51bdf32SKirk McKusick 			if ((cmdp->flags & FL_WR) != 0)
316d51bdf32SKirk McKusick 			    fsnoncritmodified = 1;
317d51bdf32SKirk McKusick 			if ((cmdp->flags & FL_CWR) != 0)
318d51bdf32SKirk McKusick 			    fscritmodified = 1;
319d51bdf32SKirk McKusick 		    }
32039bb6d1eSPeter Wemm 		    break;
32139bb6d1eSPeter Wemm 		}
32239bb6d1eSPeter Wemm 	    }
32339bb6d1eSPeter Wemm 	    if (!known)
32439bb6d1eSPeter Wemm 		warnx("unknown command `%s'", cmd_argv[0]), rval = 1;
32539bb6d1eSPeter Wemm 	} else
32639bb6d1eSPeter Wemm 	    rval = 0;
32739bb6d1eSPeter Wemm 	free(line);
3285cc52631SKirk McKusick 	if (rval < 0) {
329aaadf688SJoerg Wunsch 	    /* user typed "quit" */
3305cc52631SKirk McKusick 	    irelse(&curip);
331aaadf688SJoerg Wunsch 	    return 0;
3325cc52631SKirk McKusick 	}
33339bb6d1eSPeter Wemm 	if (rval)
334d51bdf32SKirk McKusick 	    warnx("command failed, return value was %d", rval);
33539bb6d1eSPeter Wemm     }
33639bb6d1eSPeter Wemm     el_end(elptr);
33739bb6d1eSPeter Wemm     history_end(hist);
3385cc52631SKirk McKusick     irelse(&curip);
33939bb6d1eSPeter Wemm     return rval;
34039bb6d1eSPeter Wemm }
34139bb6d1eSPeter Wemm 
34239bb6d1eSPeter Wemm #define GETINUM(ac,inum)    inum = strtoul(argv[ac], &cp, 0); \
3431dc349abSEd Maste if (inum < UFS_ROOTINO || inum > maxino || cp == argv[ac] || *cp != '\0' ) { \
344e25a029eSMatthew D Fleming 	printf("inode %ju out of range; range is [%ju,%ju]\n",		\
3451dc349abSEd Maste 	    (uintmax_t)inum, (uintmax_t)UFS_ROOTINO, (uintmax_t)maxino);\
34639bb6d1eSPeter Wemm 	return 1; \
34739bb6d1eSPeter Wemm }
34839bb6d1eSPeter Wemm 
34939bb6d1eSPeter Wemm /*
35039bb6d1eSPeter Wemm  * Focus on given inode number
35139bb6d1eSPeter Wemm  */
CMDFUNCSTART(focus)35239bb6d1eSPeter Wemm CMDFUNCSTART(focus)
35339bb6d1eSPeter Wemm {
35439bb6d1eSPeter Wemm     ino_t inum;
35539bb6d1eSPeter Wemm     char *cp;
35639bb6d1eSPeter Wemm 
35739bb6d1eSPeter Wemm     GETINUM(1,inum);
35839bb6d1eSPeter Wemm     ocurrent = curinum;
3595cc52631SKirk McKusick     setcurinode(inum);
360280a49ecSJoerg Wunsch     printactive(0);
36139bb6d1eSPeter Wemm     return 0;
36239bb6d1eSPeter Wemm }
36339bb6d1eSPeter Wemm 
CMDFUNCSTART(back)36439bb6d1eSPeter Wemm CMDFUNCSTART(back)
36539bb6d1eSPeter Wemm {
3665cc52631SKirk McKusick     setcurinode(ocurrent);
367280a49ecSJoerg Wunsch     printactive(0);
36839bb6d1eSPeter Wemm     return 0;
36939bb6d1eSPeter Wemm }
37039bb6d1eSPeter Wemm 
CMDFUNCSTART(zapi)37139bb6d1eSPeter Wemm CMDFUNCSTART(zapi)
37239bb6d1eSPeter Wemm {
3735cc52631SKirk McKusick     struct inode ip;
37439bb6d1eSPeter Wemm     ino_t inum;
37539bb6d1eSPeter Wemm     char *cp;
37639bb6d1eSPeter Wemm 
37739bb6d1eSPeter Wemm     GETINUM(1,inum);
3785cc52631SKirk McKusick     ginode(inum, &ip);
3795cc52631SKirk McKusick     clearinode(ip.i_dp);
3805cc52631SKirk McKusick     inodirty(&ip);
3815cc52631SKirk McKusick     irelse(&ip);
38239bb6d1eSPeter Wemm     return 0;
38339bb6d1eSPeter Wemm }
38439bb6d1eSPeter Wemm 
CMDFUNCSTART(active)38539bb6d1eSPeter Wemm CMDFUNCSTART(active)
38639bb6d1eSPeter Wemm {
387280a49ecSJoerg Wunsch     printactive(0);
38839bb6d1eSPeter Wemm     return 0;
38939bb6d1eSPeter Wemm }
39039bb6d1eSPeter Wemm 
CMDFUNCSTART(blocks)391280a49ecSJoerg Wunsch CMDFUNCSTART(blocks)
392280a49ecSJoerg Wunsch {
393280a49ecSJoerg Wunsch     printactive(1);
394280a49ecSJoerg Wunsch     return 0;
395280a49ecSJoerg Wunsch }
39639bb6d1eSPeter Wemm 
CMDFUNCSTART(quit)39739bb6d1eSPeter Wemm CMDFUNCSTART(quit)
39839bb6d1eSPeter Wemm {
39939bb6d1eSPeter Wemm     return -1;
40039bb6d1eSPeter Wemm }
40139bb6d1eSPeter Wemm 
CMDFUNCSTART(quitclean)402*d059e44bSKirk McKusick CMDFUNCSTART(quitclean)
403*d059e44bSKirk McKusick {
404*d059e44bSKirk McKusick     if (fscritmodified) {
405*d059e44bSKirk McKusick 	printf("Warning: modified filesystem marked clean\n");
406*d059e44bSKirk McKusick 	fscritmodified = 0;
407*d059e44bSKirk McKusick 	sblock.fs_clean = 1;
408*d059e44bSKirk McKusick     }
409*d059e44bSKirk McKusick     return -1;
410*d059e44bSKirk McKusick }
411*d059e44bSKirk McKusick 
CMDFUNCSTART(uplink)41239bb6d1eSPeter Wemm CMDFUNCSTART(uplink)
41339bb6d1eSPeter Wemm {
41439bb6d1eSPeter Wemm     if (!checkactive())
41539bb6d1eSPeter Wemm 	return 1;
416c9eaf226SLukas Ertl     DIP_SET(curinode, di_nlink, DIP(curinode, di_nlink) + 1);
417e25a029eSMatthew D Fleming     printf("inode %ju link count now %d\n",
418e25a029eSMatthew D Fleming 	(uintmax_t)curinum, DIP(curinode, di_nlink));
4195cc52631SKirk McKusick     inodirty(&curip);
42039bb6d1eSPeter Wemm     return 0;
42139bb6d1eSPeter Wemm }
42239bb6d1eSPeter Wemm 
CMDFUNCSTART(downlink)42339bb6d1eSPeter Wemm CMDFUNCSTART(downlink)
42439bb6d1eSPeter Wemm {
42539bb6d1eSPeter Wemm     if (!checkactive())
42639bb6d1eSPeter Wemm 	return 1;
427c9eaf226SLukas Ertl     DIP_SET(curinode, di_nlink, DIP(curinode, di_nlink) - 1);
428e25a029eSMatthew D Fleming     printf("inode %ju link count now %d\n",
429e25a029eSMatthew D Fleming 	(uintmax_t)curinum, DIP(curinode, di_nlink));
4305cc52631SKirk McKusick     inodirty(&curip);
43139bb6d1eSPeter Wemm     return 0;
43239bb6d1eSPeter Wemm }
43339bb6d1eSPeter Wemm 
43439bb6d1eSPeter Wemm const char *typename[] = {
43539bb6d1eSPeter Wemm     "unknown",
43639bb6d1eSPeter Wemm     "fifo",
43739bb6d1eSPeter Wemm     "char special",
43839bb6d1eSPeter Wemm     "unregistered #3",
43939bb6d1eSPeter Wemm     "directory",
44039bb6d1eSPeter Wemm     "unregistered #5",
44139bb6d1eSPeter Wemm     "blk special",
44239bb6d1eSPeter Wemm     "unregistered #7",
44339bb6d1eSPeter Wemm     "regular",
44439bb6d1eSPeter Wemm     "unregistered #9",
44539bb6d1eSPeter Wemm     "symlink",
44639bb6d1eSPeter Wemm     "unregistered #11",
44739bb6d1eSPeter Wemm     "socket",
44839bb6d1eSPeter Wemm     "unregistered #13",
44939bb6d1eSPeter Wemm     "whiteout",
45039bb6d1eSPeter Wemm };
45139bb6d1eSPeter Wemm 
452113db2ddSJeff Roberson int diroff;
45339bb6d1eSPeter Wemm int slot;
45439bb6d1eSPeter Wemm 
45539bb6d1eSPeter Wemm int
scannames(struct inodesc * idesc)4560638cc1aSWarner Losh scannames(struct inodesc *idesc)
45739bb6d1eSPeter Wemm {
4583d438ad6SDavid E. O'Brien 	struct direct *dirp = idesc->id_dirp;
45939bb6d1eSPeter Wemm 
460113db2ddSJeff Roberson 	printf("slot %d off %d ino %d reclen %d: %s, `%.*s'\n",
461113db2ddSJeff Roberson 	       slot++, diroff, dirp->d_ino, dirp->d_reclen,
462113db2ddSJeff Roberson 	       typename[dirp->d_type], dirp->d_namlen, dirp->d_name);
463113db2ddSJeff Roberson 	diroff += dirp->d_reclen;
46439bb6d1eSPeter Wemm 	return (KEEPON);
46539bb6d1eSPeter Wemm }
46639bb6d1eSPeter Wemm 
CMDFUNCSTART(ls)46739bb6d1eSPeter Wemm CMDFUNCSTART(ls)
46839bb6d1eSPeter Wemm {
46939bb6d1eSPeter Wemm     struct inodesc idesc;
47039bb6d1eSPeter Wemm     checkactivedir();			/* let it go on anyway */
47139bb6d1eSPeter Wemm 
47239bb6d1eSPeter Wemm     slot = 0;
473113db2ddSJeff Roberson     diroff = 0;
47439bb6d1eSPeter Wemm     idesc.id_number = curinum;
47539bb6d1eSPeter Wemm     idesc.id_func = scannames;
47639bb6d1eSPeter Wemm     idesc.id_type = DATA;
47739bb6d1eSPeter Wemm     idesc.id_fix = IGNORE;
47839bb6d1eSPeter Wemm     ckinode(curinode, &idesc);
47939bb6d1eSPeter Wemm 
48039bb6d1eSPeter Wemm     return 0;
48139bb6d1eSPeter Wemm }
48239bb6d1eSPeter Wemm 
48382d9b14eSMaxim Konovalov static int findblk_numtofind;
48482d9b14eSMaxim Konovalov static int wantedblksize;
48582d9b14eSMaxim Konovalov 
CMDFUNCSTART(findblk)48682d9b14eSMaxim Konovalov CMDFUNCSTART(findblk)
48782d9b14eSMaxim Konovalov {
48882d9b14eSMaxim Konovalov     ino_t inum, inosused;
48982d9b14eSMaxim Konovalov     uint32_t *wantedblk32;
49082d9b14eSMaxim Konovalov     uint64_t *wantedblk64;
49181fbded2SKirk McKusick     struct bufarea *cgbp;
49281fbded2SKirk McKusick     struct cg *cgp;
49382d9b14eSMaxim Konovalov     int c, i, is_ufs2;
49482d9b14eSMaxim Konovalov 
49582d9b14eSMaxim Konovalov     wantedblksize = (argc - 1);
49682d9b14eSMaxim Konovalov     is_ufs2 = sblock.fs_magic == FS_UFS2_MAGIC;
49782d9b14eSMaxim Konovalov     ocurrent = curinum;
49882d9b14eSMaxim Konovalov 
49982d9b14eSMaxim Konovalov     if (is_ufs2) {
50082d9b14eSMaxim Konovalov 	wantedblk64 = calloc(wantedblksize, sizeof(uint64_t));
50182d9b14eSMaxim Konovalov 	if (wantedblk64 == NULL)
50282d9b14eSMaxim Konovalov 	    err(1, "malloc");
50382d9b14eSMaxim Konovalov 	for (i = 1; i < argc; i++)
50482d9b14eSMaxim Konovalov 	    wantedblk64[i - 1] = dbtofsb(&sblock, strtoull(argv[i], NULL, 0));
50582d9b14eSMaxim Konovalov     } else {
50682d9b14eSMaxim Konovalov 	wantedblk32 = calloc(wantedblksize, sizeof(uint32_t));
50782d9b14eSMaxim Konovalov 	if (wantedblk32 == NULL)
50882d9b14eSMaxim Konovalov 	    err(1, "malloc");
50982d9b14eSMaxim Konovalov 	for (i = 1; i < argc; i++)
51082d9b14eSMaxim Konovalov 	    wantedblk32[i - 1] = dbtofsb(&sblock, strtoull(argv[i], NULL, 0));
51182d9b14eSMaxim Konovalov     }
51282d9b14eSMaxim Konovalov     findblk_numtofind = wantedblksize;
51382d9b14eSMaxim Konovalov     /*
51482d9b14eSMaxim Konovalov      * sblock.fs_ncg holds a number of cylinder groups.
51582d9b14eSMaxim Konovalov      * Iterate over all cylinder groups.
51682d9b14eSMaxim Konovalov      */
51782d9b14eSMaxim Konovalov     for (c = 0; c < sblock.fs_ncg; c++) {
51882d9b14eSMaxim Konovalov 	/*
51982d9b14eSMaxim Konovalov 	 * sblock.fs_ipg holds a number of inodes per cylinder group.
52082d9b14eSMaxim Konovalov 	 * Calculate a highest inode number for a given cylinder group.
52182d9b14eSMaxim Konovalov 	 */
52282d9b14eSMaxim Konovalov 	inum = c * sblock.fs_ipg;
52382d9b14eSMaxim Konovalov 	/* Read cylinder group. */
5242d3c3a50SDimitry Andric 	cgbp = cglookup(c);
52581fbded2SKirk McKusick 	cgp = cgbp->b_un.b_cg;
52682d9b14eSMaxim Konovalov 	/*
52782d9b14eSMaxim Konovalov 	 * Get a highest used inode number for a given cylinder group.
52882d9b14eSMaxim Konovalov 	 * For UFS1 all inodes initialized at the newfs stage.
52982d9b14eSMaxim Konovalov 	 */
53082d9b14eSMaxim Konovalov 	if (is_ufs2)
53182d9b14eSMaxim Konovalov 	    inosused = cgp->cg_initediblk;
53282d9b14eSMaxim Konovalov 	else
53382d9b14eSMaxim Konovalov 	    inosused = sblock.fs_ipg;
53482d9b14eSMaxim Konovalov 
53582d9b14eSMaxim Konovalov 	for (; inosused > 0; inum++, inosused--) {
5361dc349abSEd Maste 	    /* Skip magic inodes: 0, UFS_WINO, UFS_ROOTINO. */
5371dc349abSEd Maste 	    if (inum < UFS_ROOTINO)
53882d9b14eSMaxim Konovalov 		continue;
53982d9b14eSMaxim Konovalov 	    /*
54082d9b14eSMaxim Konovalov 	     * Check if the block we are looking for is just an inode block.
54182d9b14eSMaxim Konovalov 	     *
54282d9b14eSMaxim Konovalov 	     * ino_to_fsba() - get block containing inode from its number.
54382d9b14eSMaxim Konovalov 	     * INOPB() - get a number of inodes in one disk block.
54482d9b14eSMaxim Konovalov 	     */
54582d9b14eSMaxim Konovalov 	    if (is_ufs2 ?
54682d9b14eSMaxim Konovalov 		compare_blk64(wantedblk64, ino_to_fsba(&sblock, inum)) :
54782d9b14eSMaxim Konovalov 		compare_blk32(wantedblk32, ino_to_fsba(&sblock, inum))) {
548e25a029eSMatthew D Fleming 		printf("block %llu: inode block (%ju-%ju)\n",
54982d9b14eSMaxim Konovalov 		    (unsigned long long)fsbtodb(&sblock,
55082d9b14eSMaxim Konovalov 			ino_to_fsba(&sblock, inum)),
551e25a029eSMatthew D Fleming 		    (uintmax_t)(inum / INOPB(&sblock)) * INOPB(&sblock),
552e25a029eSMatthew D Fleming 		    (uintmax_t)(inum / INOPB(&sblock) + 1) * INOPB(&sblock));
55382d9b14eSMaxim Konovalov 		findblk_numtofind--;
55482d9b14eSMaxim Konovalov 		if (findblk_numtofind == 0)
55582d9b14eSMaxim Konovalov 		    goto end;
55682d9b14eSMaxim Konovalov 	    }
55782d9b14eSMaxim Konovalov 	    /* Get on-disk inode aka dinode. */
5585cc52631SKirk McKusick 	    setcurinode(inum);
559d8ba45e2SEd Maste 	    /* Find IFLNK dinode with allocated data blocks. */
560d8ba45e2SEd Maste 	    switch (DIP(curinode, di_mode) & IFMT) {
561d8ba45e2SEd Maste 	    case IFDIR:
562d8ba45e2SEd Maste 	    case IFREG:
56382d9b14eSMaxim Konovalov 		if (DIP(curinode, di_blocks) == 0)
56482d9b14eSMaxim Konovalov 		    continue;
56582d9b14eSMaxim Konovalov 		break;
566d8ba45e2SEd Maste 	    case IFLNK:
56782d9b14eSMaxim Konovalov 		{
56882d9b14eSMaxim Konovalov 		    uint64_t size = DIP(curinode, di_size);
56982d9b14eSMaxim Konovalov 		    if (size > 0 && size < sblock.fs_maxsymlinklen &&
57082d9b14eSMaxim Konovalov 			DIP(curinode, di_blocks) == 0)
57182d9b14eSMaxim Konovalov 			continue;
57282d9b14eSMaxim Konovalov 		    else
57382d9b14eSMaxim Konovalov 			break;
57482d9b14eSMaxim Konovalov 		}
57582d9b14eSMaxim Konovalov 	    default:
57682d9b14eSMaxim Konovalov 		continue;
57782d9b14eSMaxim Konovalov 	    }
57882d9b14eSMaxim Konovalov 	    /* Look through direct data blocks. */
57982d9b14eSMaxim Konovalov 	    if (is_ufs2 ?
5801dc349abSEd Maste 		find_blks64(curinode->dp2.di_db, UFS_NDADDR, wantedblk64) :
5811dc349abSEd Maste 		find_blks32(curinode->dp1.di_db, UFS_NDADDR, wantedblk32))
58282d9b14eSMaxim Konovalov 		goto end;
5831dc349abSEd Maste 	    for (i = 0; i < UFS_NIADDR; i++) {
58482d9b14eSMaxim Konovalov 		/*
58582d9b14eSMaxim Konovalov 		 * Does the block we are looking for belongs to the
58682d9b14eSMaxim Konovalov 		 * indirect blocks?
58782d9b14eSMaxim Konovalov 		 */
58882d9b14eSMaxim Konovalov 		if (is_ufs2 ?
58982d9b14eSMaxim Konovalov 		    compare_blk64(wantedblk64, curinode->dp2.di_ib[i]) :
59082d9b14eSMaxim Konovalov 		    compare_blk32(wantedblk32, curinode->dp1.di_ib[i]))
59182d9b14eSMaxim Konovalov 		    if (founddatablk(is_ufs2 ? curinode->dp2.di_ib[i] :
59282d9b14eSMaxim Konovalov 			curinode->dp1.di_ib[i]))
59382d9b14eSMaxim Konovalov 			goto end;
59482d9b14eSMaxim Konovalov 		/*
59582d9b14eSMaxim Konovalov 		 * Search through indirect, double and triple indirect
59682d9b14eSMaxim Konovalov 		 * data blocks.
59782d9b14eSMaxim Konovalov 		 */
59882d9b14eSMaxim Konovalov 		if (is_ufs2 ? (curinode->dp2.di_ib[i] != 0) :
59982d9b14eSMaxim Konovalov 		    (curinode->dp1.di_ib[i] != 0))
60082d9b14eSMaxim Konovalov 		    if (is_ufs2 ?
60182d9b14eSMaxim Konovalov 			find_indirblks64(curinode->dp2.di_ib[i], i,
60282d9b14eSMaxim Konovalov 			    wantedblk64) :
60382d9b14eSMaxim Konovalov 			find_indirblks32(curinode->dp1.di_ib[i], i,
60482d9b14eSMaxim Konovalov 			    wantedblk32))
60582d9b14eSMaxim Konovalov 			goto end;
60682d9b14eSMaxim Konovalov 	    }
60782d9b14eSMaxim Konovalov 	}
60882d9b14eSMaxim Konovalov     }
60982d9b14eSMaxim Konovalov end:
6105cc52631SKirk McKusick     setcurinode(ocurrent);
6115a8ad265SXin LI     if (is_ufs2)
6120bebba31SWarner Losh 	free(wantedblk64);
6135a8ad265SXin LI     else
6145a8ad265SXin LI 	free(wantedblk32);
61582d9b14eSMaxim Konovalov     return 0;
61682d9b14eSMaxim Konovalov }
61782d9b14eSMaxim Konovalov 
61882d9b14eSMaxim Konovalov static int
compare_blk32(uint32_t * wantedblk,uint32_t curblk)61982d9b14eSMaxim Konovalov compare_blk32(uint32_t *wantedblk, uint32_t curblk)
62082d9b14eSMaxim Konovalov {
62182d9b14eSMaxim Konovalov     int i;
62282d9b14eSMaxim Konovalov 
62382d9b14eSMaxim Konovalov     for (i = 0; i < wantedblksize; i++) {
62482d9b14eSMaxim Konovalov 	if (wantedblk[i] != 0 && wantedblk[i] == curblk) {
62582d9b14eSMaxim Konovalov 	    wantedblk[i] = 0;
62682d9b14eSMaxim Konovalov 	    return 1;
62782d9b14eSMaxim Konovalov 	}
62882d9b14eSMaxim Konovalov     }
62982d9b14eSMaxim Konovalov     return 0;
63082d9b14eSMaxim Konovalov }
63182d9b14eSMaxim Konovalov 
63282d9b14eSMaxim Konovalov static int
compare_blk64(uint64_t * wantedblk,uint64_t curblk)63382d9b14eSMaxim Konovalov compare_blk64(uint64_t *wantedblk, uint64_t curblk)
63482d9b14eSMaxim Konovalov {
63582d9b14eSMaxim Konovalov     int i;
63682d9b14eSMaxim Konovalov 
63782d9b14eSMaxim Konovalov     for (i = 0; i < wantedblksize; i++) {
63882d9b14eSMaxim Konovalov 	if (wantedblk[i] != 0 && wantedblk[i] == curblk) {
63982d9b14eSMaxim Konovalov 	    wantedblk[i] = 0;
64082d9b14eSMaxim Konovalov 	    return 1;
64182d9b14eSMaxim Konovalov 	}
64282d9b14eSMaxim Konovalov     }
64382d9b14eSMaxim Konovalov     return 0;
64482d9b14eSMaxim Konovalov }
64582d9b14eSMaxim Konovalov 
64682d9b14eSMaxim Konovalov static int
founddatablk(uint64_t blk)64782d9b14eSMaxim Konovalov founddatablk(uint64_t blk)
64882d9b14eSMaxim Konovalov {
64982d9b14eSMaxim Konovalov 
650e25a029eSMatthew D Fleming     printf("%llu: data block of inode %ju\n",
651e25a029eSMatthew D Fleming 	(unsigned long long)fsbtodb(&sblock, blk), (uintmax_t)curinum);
65282d9b14eSMaxim Konovalov     findblk_numtofind--;
65382d9b14eSMaxim Konovalov     if (findblk_numtofind == 0)
65482d9b14eSMaxim Konovalov 	return 1;
65582d9b14eSMaxim Konovalov     return 0;
65682d9b14eSMaxim Konovalov }
65782d9b14eSMaxim Konovalov 
65882d9b14eSMaxim Konovalov static int
find_blks32(uint32_t * buf,int size,uint32_t * wantedblk)65982d9b14eSMaxim Konovalov find_blks32(uint32_t *buf, int size, uint32_t *wantedblk)
66082d9b14eSMaxim Konovalov {
66182d9b14eSMaxim Konovalov     int blk;
66282d9b14eSMaxim Konovalov     for (blk = 0; blk < size; blk++) {
66382d9b14eSMaxim Konovalov 	if (buf[blk] == 0)
66482d9b14eSMaxim Konovalov 	    continue;
66582d9b14eSMaxim Konovalov 	if (compare_blk32(wantedblk, buf[blk])) {
66682d9b14eSMaxim Konovalov 	    if (founddatablk(buf[blk]))
66782d9b14eSMaxim Konovalov 		return 1;
66882d9b14eSMaxim Konovalov 	}
66982d9b14eSMaxim Konovalov     }
67082d9b14eSMaxim Konovalov     return 0;
67182d9b14eSMaxim Konovalov }
67282d9b14eSMaxim Konovalov 
67382d9b14eSMaxim Konovalov static int
find_indirblks32(uint32_t blk,int ind_level,uint32_t * wantedblk)67482d9b14eSMaxim Konovalov find_indirblks32(uint32_t blk, int ind_level, uint32_t *wantedblk)
67582d9b14eSMaxim Konovalov {
67682d9b14eSMaxim Konovalov #define MAXNINDIR      (MAXBSIZE / sizeof(uint32_t))
67782d9b14eSMaxim Konovalov     uint32_t idblk[MAXNINDIR];
67882d9b14eSMaxim Konovalov     int i;
67982d9b14eSMaxim Konovalov 
680fffbc2a5SPawel Jakub Dawidek     blread(fsreadfd, (char *)idblk, fsbtodb(&sblock, blk), (int)sblock.fs_bsize);
68182d9b14eSMaxim Konovalov     if (ind_level <= 0) {
68282d9b14eSMaxim Konovalov 	if (find_blks32(idblk, sblock.fs_bsize / sizeof(uint32_t), wantedblk))
68382d9b14eSMaxim Konovalov 	    return 1;
68482d9b14eSMaxim Konovalov     } else {
68582d9b14eSMaxim Konovalov 	ind_level--;
68682d9b14eSMaxim Konovalov 	for (i = 0; i < sblock.fs_bsize / sizeof(uint32_t); i++) {
68782d9b14eSMaxim Konovalov 	    if (compare_blk32(wantedblk, idblk[i])) {
68882d9b14eSMaxim Konovalov 		if (founddatablk(idblk[i]))
68982d9b14eSMaxim Konovalov 		    return 1;
69082d9b14eSMaxim Konovalov 	    }
69182d9b14eSMaxim Konovalov 	    if (idblk[i] != 0)
69282d9b14eSMaxim Konovalov 		if (find_indirblks32(idblk[i], ind_level, wantedblk))
69382d9b14eSMaxim Konovalov 		    return 1;
69482d9b14eSMaxim Konovalov 	}
69582d9b14eSMaxim Konovalov     }
69682d9b14eSMaxim Konovalov #undef MAXNINDIR
69782d9b14eSMaxim Konovalov     return 0;
69882d9b14eSMaxim Konovalov }
69982d9b14eSMaxim Konovalov 
70082d9b14eSMaxim Konovalov static int
find_blks64(uint64_t * buf,int size,uint64_t * wantedblk)70182d9b14eSMaxim Konovalov find_blks64(uint64_t *buf, int size, uint64_t *wantedblk)
70282d9b14eSMaxim Konovalov {
70382d9b14eSMaxim Konovalov     int blk;
70482d9b14eSMaxim Konovalov     for (blk = 0; blk < size; blk++) {
70582d9b14eSMaxim Konovalov 	if (buf[blk] == 0)
70682d9b14eSMaxim Konovalov 	    continue;
70782d9b14eSMaxim Konovalov 	if (compare_blk64(wantedblk, buf[blk])) {
70882d9b14eSMaxim Konovalov 	    if (founddatablk(buf[blk]))
70982d9b14eSMaxim Konovalov 		return 1;
71082d9b14eSMaxim Konovalov 	}
71182d9b14eSMaxim Konovalov     }
71282d9b14eSMaxim Konovalov     return 0;
71382d9b14eSMaxim Konovalov }
71482d9b14eSMaxim Konovalov 
71582d9b14eSMaxim Konovalov static int
find_indirblks64(uint64_t blk,int ind_level,uint64_t * wantedblk)71682d9b14eSMaxim Konovalov find_indirblks64(uint64_t blk, int ind_level, uint64_t *wantedblk)
71782d9b14eSMaxim Konovalov {
71882d9b14eSMaxim Konovalov #define MAXNINDIR      (MAXBSIZE / sizeof(uint64_t))
71982d9b14eSMaxim Konovalov     uint64_t idblk[MAXNINDIR];
72082d9b14eSMaxim Konovalov     int i;
72182d9b14eSMaxim Konovalov 
722fffbc2a5SPawel Jakub Dawidek     blread(fsreadfd, (char *)idblk, fsbtodb(&sblock, blk), (int)sblock.fs_bsize);
72382d9b14eSMaxim Konovalov     if (ind_level <= 0) {
72482d9b14eSMaxim Konovalov 	if (find_blks64(idblk, sblock.fs_bsize / sizeof(uint64_t), wantedblk))
72582d9b14eSMaxim Konovalov 	    return 1;
72682d9b14eSMaxim Konovalov     } else {
72782d9b14eSMaxim Konovalov 	ind_level--;
72882d9b14eSMaxim Konovalov 	for (i = 0; i < sblock.fs_bsize / sizeof(uint64_t); i++) {
72982d9b14eSMaxim Konovalov 	    if (compare_blk64(wantedblk, idblk[i])) {
73082d9b14eSMaxim Konovalov 		if (founddatablk(idblk[i]))
73182d9b14eSMaxim Konovalov 		    return 1;
73282d9b14eSMaxim Konovalov 	    }
73382d9b14eSMaxim Konovalov 	    if (idblk[i] != 0)
73482d9b14eSMaxim Konovalov 		if (find_indirblks64(idblk[i], ind_level, wantedblk))
73582d9b14eSMaxim Konovalov 		    return 1;
73682d9b14eSMaxim Konovalov 	}
73782d9b14eSMaxim Konovalov     }
73882d9b14eSMaxim Konovalov #undef MAXNINDIR
73982d9b14eSMaxim Konovalov     return 0;
74082d9b14eSMaxim Konovalov }
74182d9b14eSMaxim Konovalov 
7420638cc1aSWarner Losh int findino(struct inodesc *idesc); /* from fsck */
7430638cc1aSWarner Losh static int dolookup(char *name);
74439bb6d1eSPeter Wemm 
74539bb6d1eSPeter Wemm static int
dolookup(char * name)7460638cc1aSWarner Losh dolookup(char *name)
74739bb6d1eSPeter Wemm {
74839bb6d1eSPeter Wemm     struct inodesc idesc;
74939bb6d1eSPeter Wemm 
75039bb6d1eSPeter Wemm     if (!checkactivedir())
75139bb6d1eSPeter Wemm 	    return 0;
75239bb6d1eSPeter Wemm     idesc.id_number = curinum;
75339bb6d1eSPeter Wemm     idesc.id_func = findino;
75439bb6d1eSPeter Wemm     idesc.id_name = name;
75539bb6d1eSPeter Wemm     idesc.id_type = DATA;
75639bb6d1eSPeter Wemm     idesc.id_fix = IGNORE;
75739bb6d1eSPeter Wemm     if (ckinode(curinode, &idesc) & FOUND) {
7585cc52631SKirk McKusick 	setcurinode(idesc.id_parent);
759280a49ecSJoerg Wunsch 	printactive(0);
76039bb6d1eSPeter Wemm 	return 1;
76139bb6d1eSPeter Wemm     } else {
76239bb6d1eSPeter Wemm 	warnx("name `%s' not found in current inode directory", name);
76339bb6d1eSPeter Wemm 	return 0;
76439bb6d1eSPeter Wemm     }
76539bb6d1eSPeter Wemm }
76639bb6d1eSPeter Wemm 
CMDFUNCSTART(focusname)76739bb6d1eSPeter Wemm CMDFUNCSTART(focusname)
76839bb6d1eSPeter Wemm {
76939bb6d1eSPeter Wemm     char *p, *val;
77039bb6d1eSPeter Wemm 
77139bb6d1eSPeter Wemm     if (!checkactive())
77239bb6d1eSPeter Wemm 	return 1;
77339bb6d1eSPeter Wemm 
77439bb6d1eSPeter Wemm     ocurrent = curinum;
77539bb6d1eSPeter Wemm 
77639bb6d1eSPeter Wemm     if (argv[1][0] == '/') {
7775cc52631SKirk McKusick 	setcurinode(UFS_ROOTINO);
77839bb6d1eSPeter Wemm     } else {
77939bb6d1eSPeter Wemm 	if (!checkactivedir())
78039bb6d1eSPeter Wemm 	    return 1;
78139bb6d1eSPeter Wemm     }
78239bb6d1eSPeter Wemm     for (p = argv[1]; p != NULL;) {
78339bb6d1eSPeter Wemm 	while ((val = strsep(&p, "/")) != NULL && *val == '\0');
78439bb6d1eSPeter Wemm 	if (val) {
78539bb6d1eSPeter Wemm 	    printf("component `%s': ", val);
78639bb6d1eSPeter Wemm 	    fflush(stdout);
78739bb6d1eSPeter Wemm 	    if (!dolookup(val)) {
78839bb6d1eSPeter Wemm 		return(1);
78939bb6d1eSPeter Wemm 	    }
79039bb6d1eSPeter Wemm 	}
79139bb6d1eSPeter Wemm     }
79239bb6d1eSPeter Wemm     return 0;
79339bb6d1eSPeter Wemm }
79439bb6d1eSPeter Wemm 
CMDFUNCSTART(ln)79539bb6d1eSPeter Wemm CMDFUNCSTART(ln)
79639bb6d1eSPeter Wemm {
79739bb6d1eSPeter Wemm     ino_t inum;
79839bb6d1eSPeter Wemm     int rval;
79939bb6d1eSPeter Wemm     char *cp;
80039bb6d1eSPeter Wemm 
80139bb6d1eSPeter Wemm     GETINUM(1,inum);
80239bb6d1eSPeter Wemm 
80339bb6d1eSPeter Wemm     if (!checkactivedir())
80439bb6d1eSPeter Wemm 	return 1;
80539bb6d1eSPeter Wemm     rval = makeentry(curinum, inum, argv[2]);
80639bb6d1eSPeter Wemm     if (rval)
807e25a029eSMatthew D Fleming 	    printf("Ino %ju entered as `%s'\n", (uintmax_t)inum, argv[2]);
80839bb6d1eSPeter Wemm     else
80939bb6d1eSPeter Wemm 	printf("could not enter name? weird.\n");
81039bb6d1eSPeter Wemm     return rval;
81139bb6d1eSPeter Wemm }
81239bb6d1eSPeter Wemm 
CMDFUNCSTART(rm)81339bb6d1eSPeter Wemm CMDFUNCSTART(rm)
81439bb6d1eSPeter Wemm {
81539bb6d1eSPeter Wemm     int rval;
81639bb6d1eSPeter Wemm 
81739bb6d1eSPeter Wemm     if (!checkactivedir())
81839bb6d1eSPeter Wemm 	return 1;
819fe5e6e2cSKirk McKusick     rval = changeino(curinum, argv[1], 0, 0);
82039bb6d1eSPeter Wemm     if (rval & ALTERED) {
82139bb6d1eSPeter Wemm 	printf("Name `%s' removed\n", argv[1]);
82239bb6d1eSPeter Wemm 	return 0;
82339bb6d1eSPeter Wemm     } else {
8248660ce22SBrian Feldman 	printf("could not remove name ('%s')? weird.\n", argv[1]);
82539bb6d1eSPeter Wemm 	return 1;
82639bb6d1eSPeter Wemm     }
82739bb6d1eSPeter Wemm }
82839bb6d1eSPeter Wemm 
82939bb6d1eSPeter Wemm long slotcount, desired;
83039bb6d1eSPeter Wemm 
83139bb6d1eSPeter Wemm int
chinumfunc(struct inodesc * idesc)8320638cc1aSWarner Losh chinumfunc(struct inodesc *idesc)
83339bb6d1eSPeter Wemm {
8343d438ad6SDavid E. O'Brien 	struct direct *dirp = idesc->id_dirp;
83539bb6d1eSPeter Wemm 
83639bb6d1eSPeter Wemm 	if (slotcount++ == desired) {
83739bb6d1eSPeter Wemm 	    dirp->d_ino = idesc->id_parent;
83839bb6d1eSPeter Wemm 	    return STOP|ALTERED|FOUND;
83939bb6d1eSPeter Wemm 	}
84039bb6d1eSPeter Wemm 	return KEEPON;
84139bb6d1eSPeter Wemm }
84239bb6d1eSPeter Wemm 
CMDFUNCSTART(chinum)84339bb6d1eSPeter Wemm CMDFUNCSTART(chinum)
84439bb6d1eSPeter Wemm {
84539bb6d1eSPeter Wemm     char *cp;
84639bb6d1eSPeter Wemm     ino_t inum;
84739bb6d1eSPeter Wemm     struct inodesc idesc;
84839bb6d1eSPeter Wemm 
84939bb6d1eSPeter Wemm     slotcount = 0;
85039bb6d1eSPeter Wemm     if (!checkactivedir())
85139bb6d1eSPeter Wemm 	return 1;
85239bb6d1eSPeter Wemm     GETINUM(2,inum);
85339bb6d1eSPeter Wemm 
85439bb6d1eSPeter Wemm     desired = strtol(argv[1], &cp, 0);
85539bb6d1eSPeter Wemm     if (cp == argv[1] || *cp != '\0' || desired < 0) {
85639bb6d1eSPeter Wemm 	printf("invalid slot number `%s'\n", argv[1]);
85739bb6d1eSPeter Wemm 	return 1;
85839bb6d1eSPeter Wemm     }
85939bb6d1eSPeter Wemm 
86039bb6d1eSPeter Wemm     idesc.id_number = curinum;
86139bb6d1eSPeter Wemm     idesc.id_func = chinumfunc;
86239bb6d1eSPeter Wemm     idesc.id_fix = IGNORE;
86339bb6d1eSPeter Wemm     idesc.id_type = DATA;
86439bb6d1eSPeter Wemm     idesc.id_parent = inum;		/* XXX convenient hiding place */
86539bb6d1eSPeter Wemm 
86639bb6d1eSPeter Wemm     if (ckinode(curinode, &idesc) & FOUND)
86739bb6d1eSPeter Wemm 	return 0;
86839bb6d1eSPeter Wemm     else {
86939bb6d1eSPeter Wemm 	warnx("no %sth slot in current directory", argv[1]);
87039bb6d1eSPeter Wemm 	return 1;
87139bb6d1eSPeter Wemm     }
87239bb6d1eSPeter Wemm }
87339bb6d1eSPeter Wemm 
87439bb6d1eSPeter Wemm int
chnamefunc(struct inodesc * idesc)8750638cc1aSWarner Losh chnamefunc(struct inodesc *idesc)
87639bb6d1eSPeter Wemm {
8773d438ad6SDavid E. O'Brien 	struct direct *dirp = idesc->id_dirp;
87839bb6d1eSPeter Wemm 	struct direct testdir;
87939bb6d1eSPeter Wemm 
88039bb6d1eSPeter Wemm 	if (slotcount++ == desired) {
88139bb6d1eSPeter Wemm 	    /* will name fit? */
88239bb6d1eSPeter Wemm 	    testdir.d_namlen = strlen(idesc->id_name);
88339bb6d1eSPeter Wemm 	    if (DIRSIZ(NEWDIRFMT, &testdir) <= dirp->d_reclen) {
88439bb6d1eSPeter Wemm 		dirp->d_namlen = testdir.d_namlen;
88539bb6d1eSPeter Wemm 		strcpy(dirp->d_name, idesc->id_name);
88639bb6d1eSPeter Wemm 		return STOP|ALTERED|FOUND;
88739bb6d1eSPeter Wemm 	    } else
88839bb6d1eSPeter Wemm 		return STOP|FOUND;	/* won't fit, so give up */
88939bb6d1eSPeter Wemm 	}
89039bb6d1eSPeter Wemm 	return KEEPON;
89139bb6d1eSPeter Wemm }
89239bb6d1eSPeter Wemm 
CMDFUNCSTART(chname)89339bb6d1eSPeter Wemm CMDFUNCSTART(chname)
89439bb6d1eSPeter Wemm {
89539bb6d1eSPeter Wemm     int rval;
89639bb6d1eSPeter Wemm     char *cp;
89739bb6d1eSPeter Wemm     struct inodesc idesc;
89839bb6d1eSPeter Wemm 
89939bb6d1eSPeter Wemm     slotcount = 0;
90039bb6d1eSPeter Wemm     if (!checkactivedir())
90139bb6d1eSPeter Wemm 	return 1;
90239bb6d1eSPeter Wemm 
90339bb6d1eSPeter Wemm     desired = strtoul(argv[1], &cp, 0);
90439bb6d1eSPeter Wemm     if (cp == argv[1] || *cp != '\0') {
90539bb6d1eSPeter Wemm 	printf("invalid slot number `%s'\n", argv[1]);
90639bb6d1eSPeter Wemm 	return 1;
90739bb6d1eSPeter Wemm     }
90839bb6d1eSPeter Wemm 
90939bb6d1eSPeter Wemm     idesc.id_number = curinum;
91039bb6d1eSPeter Wemm     idesc.id_func = chnamefunc;
91139bb6d1eSPeter Wemm     idesc.id_fix = IGNORE;
91239bb6d1eSPeter Wemm     idesc.id_type = DATA;
91339bb6d1eSPeter Wemm     idesc.id_name = argv[2];
91439bb6d1eSPeter Wemm 
91539bb6d1eSPeter Wemm     rval = ckinode(curinode, &idesc);
91639bb6d1eSPeter Wemm     if ((rval & (FOUND|ALTERED)) == (FOUND|ALTERED))
91739bb6d1eSPeter Wemm 	return 0;
91839bb6d1eSPeter Wemm     else if (rval & FOUND) {
91939bb6d1eSPeter Wemm 	warnx("new name `%s' does not fit in slot %s\n", argv[2], argv[1]);
92039bb6d1eSPeter Wemm 	return 1;
92139bb6d1eSPeter Wemm     } else {
92239bb6d1eSPeter Wemm 	warnx("no %sth slot in current directory", argv[1]);
92339bb6d1eSPeter Wemm 	return 1;
92439bb6d1eSPeter Wemm     }
92539bb6d1eSPeter Wemm }
92639bb6d1eSPeter Wemm 
92739bb6d1eSPeter Wemm struct typemap {
92839bb6d1eSPeter Wemm     const char *typename;
92939bb6d1eSPeter Wemm     int typebits;
93039bb6d1eSPeter Wemm } typenamemap[]  = {
931d8ba45e2SEd Maste     {"file", IFREG},
932d8ba45e2SEd Maste     {"dir", IFDIR},
933d8ba45e2SEd Maste     {"socket", IFSOCK},
934d8ba45e2SEd Maste     {"fifo", IFIFO},
93539bb6d1eSPeter Wemm };
93639bb6d1eSPeter Wemm 
CMDFUNCSTART(newtype)93739bb6d1eSPeter Wemm CMDFUNCSTART(newtype)
93839bb6d1eSPeter Wemm {
93939bb6d1eSPeter Wemm     int type;
94039bb6d1eSPeter Wemm     struct typemap *tp;
94139bb6d1eSPeter Wemm 
94239bb6d1eSPeter Wemm     if (!checkactive())
94339bb6d1eSPeter Wemm 	return 1;
944d8ba45e2SEd Maste     type = DIP(curinode, di_mode) & IFMT;
94539bb6d1eSPeter Wemm     for (tp = typenamemap;
94602c8c118SMarcelo Araujo 	 tp < &typenamemap[nitems(typenamemap)];
94739bb6d1eSPeter Wemm 	 tp++) {
94839bb6d1eSPeter Wemm 	if (!strcmp(argv[1], tp->typename)) {
94939bb6d1eSPeter Wemm 	    printf("setting type to %s\n", tp->typename);
95039bb6d1eSPeter Wemm 	    type = tp->typebits;
95139bb6d1eSPeter Wemm 	    break;
95239bb6d1eSPeter Wemm 	}
95339bb6d1eSPeter Wemm     }
95402c8c118SMarcelo Araujo     if (tp == &typenamemap[nitems(typenamemap)]) {
95539bb6d1eSPeter Wemm 	warnx("type `%s' not known", argv[1]);
95639bb6d1eSPeter Wemm 	warnx("try one of `file', `dir', `socket', `fifo'");
95739bb6d1eSPeter Wemm 	return 1;
95839bb6d1eSPeter Wemm     }
959d8ba45e2SEd Maste     DIP_SET(curinode, di_mode, DIP(curinode, di_mode) & ~IFMT);
960c9eaf226SLukas Ertl     DIP_SET(curinode, di_mode, DIP(curinode, di_mode) | type);
9615cc52631SKirk McKusick     inodirty(&curip);
962280a49ecSJoerg Wunsch     printactive(0);
96339bb6d1eSPeter Wemm     return 0;
96439bb6d1eSPeter Wemm }
96539bb6d1eSPeter Wemm 
CMDFUNCSTART(chmode)96639bb6d1eSPeter Wemm CMDFUNCSTART(chmode)
96739bb6d1eSPeter Wemm {
96839bb6d1eSPeter Wemm     long modebits;
96939bb6d1eSPeter Wemm     char *cp;
97039bb6d1eSPeter Wemm 
97139bb6d1eSPeter Wemm     if (!checkactive())
97239bb6d1eSPeter Wemm 	return 1;
97339bb6d1eSPeter Wemm 
97439bb6d1eSPeter Wemm     modebits = strtol(argv[1], &cp, 8);
97575249b64SIan Dowse     if (cp == argv[1] || *cp != '\0' || (modebits & ~07777)) {
97639bb6d1eSPeter Wemm 	warnx("bad modebits `%s'", argv[1]);
97739bb6d1eSPeter Wemm 	return 1;
97839bb6d1eSPeter Wemm     }
97939bb6d1eSPeter Wemm 
980c9eaf226SLukas Ertl     DIP_SET(curinode, di_mode, DIP(curinode, di_mode) & ~07777);
981c9eaf226SLukas Ertl     DIP_SET(curinode, di_mode, DIP(curinode, di_mode) | modebits);
9825cc52631SKirk McKusick     inodirty(&curip);
983280a49ecSJoerg Wunsch     printactive(0);
984d51bdf32SKirk McKusick     return 0;
98539bb6d1eSPeter Wemm }
98639bb6d1eSPeter Wemm 
CMDFUNCSTART(chaflags)98739bb6d1eSPeter Wemm CMDFUNCSTART(chaflags)
98839bb6d1eSPeter Wemm {
98939bb6d1eSPeter Wemm     u_long flags;
99039bb6d1eSPeter Wemm     char *cp;
99139bb6d1eSPeter Wemm 
99239bb6d1eSPeter Wemm     if (!checkactive())
99339bb6d1eSPeter Wemm 	return 1;
99439bb6d1eSPeter Wemm 
99539bb6d1eSPeter Wemm     flags = strtoul(argv[1], &cp, 0);
99639bb6d1eSPeter Wemm     if (cp == argv[1] || *cp != '\0' ) {
99739bb6d1eSPeter Wemm 	warnx("bad flags `%s'", argv[1]);
99839bb6d1eSPeter Wemm 	return 1;
99939bb6d1eSPeter Wemm     }
100039bb6d1eSPeter Wemm 
100139bb6d1eSPeter Wemm     if (flags > UINT_MAX) {
100239bb6d1eSPeter Wemm 	warnx("flags set beyond 32-bit range of field (%lx)\n", flags);
100339bb6d1eSPeter Wemm 	return(1);
100439bb6d1eSPeter Wemm     }
1005c9eaf226SLukas Ertl     DIP_SET(curinode, di_flags, flags);
10065cc52631SKirk McKusick     inodirty(&curip);
1007280a49ecSJoerg Wunsch     printactive(0);
1008d51bdf32SKirk McKusick     return 0;
100939bb6d1eSPeter Wemm }
101039bb6d1eSPeter Wemm 
CMDFUNCSTART(chgen)101139bb6d1eSPeter Wemm CMDFUNCSTART(chgen)
101239bb6d1eSPeter Wemm {
101339bb6d1eSPeter Wemm     long gen;
101439bb6d1eSPeter Wemm     char *cp;
101539bb6d1eSPeter Wemm 
101639bb6d1eSPeter Wemm     if (!checkactive())
101739bb6d1eSPeter Wemm 	return 1;
101839bb6d1eSPeter Wemm 
101939bb6d1eSPeter Wemm     gen = strtol(argv[1], &cp, 0);
102039bb6d1eSPeter Wemm     if (cp == argv[1] || *cp != '\0' ) {
102139bb6d1eSPeter Wemm 	warnx("bad gen `%s'", argv[1]);
102239bb6d1eSPeter Wemm 	return 1;
102339bb6d1eSPeter Wemm     }
102439bb6d1eSPeter Wemm 
1025d51bdf32SKirk McKusick     if (gen > UINT_MAX) {
1026d51bdf32SKirk McKusick 	warnx("gen set beyond 32-bit range of field (0x%lx), max is 0x%x\n",
1027d51bdf32SKirk McKusick 	    gen, UINT_MAX);
102839bb6d1eSPeter Wemm 	return(1);
102939bb6d1eSPeter Wemm     }
1030c9eaf226SLukas Ertl     DIP_SET(curinode, di_gen, gen);
10315cc52631SKirk McKusick     inodirty(&curip);
1032280a49ecSJoerg Wunsch     printactive(0);
1033d51bdf32SKirk McKusick     return 0;
103439bb6d1eSPeter Wemm }
103539bb6d1eSPeter Wemm 
CMDFUNCSTART(chsize)1036ac4b20a0SKirk McKusick CMDFUNCSTART(chsize)
1037ac4b20a0SKirk McKusick {
1038ac4b20a0SKirk McKusick     off_t size;
1039ac4b20a0SKirk McKusick     char *cp;
1040ac4b20a0SKirk McKusick 
1041ac4b20a0SKirk McKusick     if (!checkactive())
1042ac4b20a0SKirk McKusick 	return 1;
1043ac4b20a0SKirk McKusick 
1044ac4b20a0SKirk McKusick     size = strtoll(argv[1], &cp, 0);
1045ac4b20a0SKirk McKusick     if (cp == argv[1] || *cp != '\0') {
1046ac4b20a0SKirk McKusick 	warnx("bad size `%s'", argv[1]);
1047ac4b20a0SKirk McKusick 	return 1;
1048ac4b20a0SKirk McKusick     }
1049ac4b20a0SKirk McKusick 
1050ac4b20a0SKirk McKusick     if (size < 0) {
1051ac4b20a0SKirk McKusick 	warnx("size set to negative (%jd)\n", (intmax_t)size);
1052ac4b20a0SKirk McKusick 	return(1);
1053ac4b20a0SKirk McKusick     }
1054ac4b20a0SKirk McKusick     DIP_SET(curinode, di_size, size);
10555cc52631SKirk McKusick     inodirty(&curip);
1056ac4b20a0SKirk McKusick     printactive(0);
1057d51bdf32SKirk McKusick     return 0;
1058ac4b20a0SKirk McKusick }
1059ac4b20a0SKirk McKusick 
CMDFUNC(chdb)10607636973cSKirk McKusick CMDFUNC(chdb)
10617636973cSKirk McKusick {
10627636973cSKirk McKusick 	unsigned int idx;
10637636973cSKirk McKusick 	daddr_t bno;
10647636973cSKirk McKusick 	char *cp;
10657636973cSKirk McKusick 
10667636973cSKirk McKusick 	if (!checkactive())
10677636973cSKirk McKusick 		return 1;
10687636973cSKirk McKusick 
10697636973cSKirk McKusick 	idx = strtoull(argv[1], &cp, 0);
10707636973cSKirk McKusick 	if (cp == argv[1] || *cp != '\0') {
10717636973cSKirk McKusick 		warnx("bad pointer idx `%s'", argv[1]);
10727636973cSKirk McKusick 		return 1;
10737636973cSKirk McKusick 	}
10747636973cSKirk McKusick 	bno = strtoll(argv[2], &cp, 0);
10757636973cSKirk McKusick 	if (cp == argv[2] || *cp != '\0') {
10767636973cSKirk McKusick 		warnx("bad block number `%s'", argv[2]);
10777636973cSKirk McKusick 		return 1;
10787636973cSKirk McKusick 	}
10797636973cSKirk McKusick 	if (idx >= UFS_NDADDR) {
10807636973cSKirk McKusick 		warnx("pointer index %d is out of range", idx);
10817636973cSKirk McKusick 		return 1;
10827636973cSKirk McKusick 	}
10837636973cSKirk McKusick 
10847636973cSKirk McKusick 	DIP_SET(curinode, di_db[idx], bno);
10857636973cSKirk McKusick 	inodirty(&curip);
10867636973cSKirk McKusick 	printactive(0);
10877636973cSKirk McKusick 	return 0;
10887636973cSKirk McKusick }
10897636973cSKirk McKusick 
CMDFUNCSTART(linkcount)109039bb6d1eSPeter Wemm CMDFUNCSTART(linkcount)
109139bb6d1eSPeter Wemm {
109239bb6d1eSPeter Wemm     int lcnt;
109339bb6d1eSPeter Wemm     char *cp;
109439bb6d1eSPeter Wemm 
109539bb6d1eSPeter Wemm     if (!checkactive())
109639bb6d1eSPeter Wemm 	return 1;
109739bb6d1eSPeter Wemm 
109839bb6d1eSPeter Wemm     lcnt = strtol(argv[1], &cp, 0);
109939bb6d1eSPeter Wemm     if (cp == argv[1] || *cp != '\0' ) {
110039bb6d1eSPeter Wemm 	warnx("bad link count `%s'", argv[1]);
110139bb6d1eSPeter Wemm 	return 1;
110239bb6d1eSPeter Wemm     }
110339bb6d1eSPeter Wemm     if (lcnt > USHRT_MAX || lcnt < 0) {
110439bb6d1eSPeter Wemm 	warnx("max link count is %d\n", USHRT_MAX);
110539bb6d1eSPeter Wemm 	return 1;
110639bb6d1eSPeter Wemm     }
110739bb6d1eSPeter Wemm 
1108c9eaf226SLukas Ertl     DIP_SET(curinode, di_nlink, lcnt);
11095cc52631SKirk McKusick     inodirty(&curip);
1110280a49ecSJoerg Wunsch     printactive(0);
1111d51bdf32SKirk McKusick     return 0;
111239bb6d1eSPeter Wemm }
111339bb6d1eSPeter Wemm 
CMDFUNCSTART(chowner)111439bb6d1eSPeter Wemm CMDFUNCSTART(chowner)
111539bb6d1eSPeter Wemm {
111639bb6d1eSPeter Wemm     unsigned long uid;
111739bb6d1eSPeter Wemm     char *cp;
111839bb6d1eSPeter Wemm     struct passwd *pwd;
111939bb6d1eSPeter Wemm 
112039bb6d1eSPeter Wemm     if (!checkactive())
112139bb6d1eSPeter Wemm 	return 1;
112239bb6d1eSPeter Wemm 
112339bb6d1eSPeter Wemm     uid = strtoul(argv[1], &cp, 0);
112439bb6d1eSPeter Wemm     if (cp == argv[1] || *cp != '\0' ) {
112539bb6d1eSPeter Wemm 	/* try looking up name */
11260227048aSPhilippe Charnier 	if ((pwd = getpwnam(argv[1]))) {
112739bb6d1eSPeter Wemm 	    uid = pwd->pw_uid;
112839bb6d1eSPeter Wemm 	} else {
112939bb6d1eSPeter Wemm 	    warnx("bad uid `%s'", argv[1]);
113039bb6d1eSPeter Wemm 	    return 1;
113139bb6d1eSPeter Wemm 	}
113239bb6d1eSPeter Wemm     }
113339bb6d1eSPeter Wemm 
1134c9eaf226SLukas Ertl     DIP_SET(curinode, di_uid, uid);
11355cc52631SKirk McKusick     inodirty(&curip);
1136280a49ecSJoerg Wunsch     printactive(0);
1137d51bdf32SKirk McKusick     return 0;
113839bb6d1eSPeter Wemm }
113939bb6d1eSPeter Wemm 
CMDFUNCSTART(chgroup)114039bb6d1eSPeter Wemm CMDFUNCSTART(chgroup)
114139bb6d1eSPeter Wemm {
114239bb6d1eSPeter Wemm     unsigned long gid;
114339bb6d1eSPeter Wemm     char *cp;
114439bb6d1eSPeter Wemm     struct group *grp;
114539bb6d1eSPeter Wemm 
114639bb6d1eSPeter Wemm     if (!checkactive())
114739bb6d1eSPeter Wemm 	return 1;
114839bb6d1eSPeter Wemm 
114939bb6d1eSPeter Wemm     gid = strtoul(argv[1], &cp, 0);
115039bb6d1eSPeter Wemm     if (cp == argv[1] || *cp != '\0' ) {
11510227048aSPhilippe Charnier 	if ((grp = getgrnam(argv[1]))) {
115239bb6d1eSPeter Wemm 	    gid = grp->gr_gid;
115339bb6d1eSPeter Wemm 	} else {
115439bb6d1eSPeter Wemm 	    warnx("bad gid `%s'", argv[1]);
115539bb6d1eSPeter Wemm 	    return 1;
115639bb6d1eSPeter Wemm 	}
115739bb6d1eSPeter Wemm     }
115839bb6d1eSPeter Wemm 
1159c9eaf226SLukas Ertl     DIP_SET(curinode, di_gid, gid);
11605cc52631SKirk McKusick     inodirty(&curip);
1161280a49ecSJoerg Wunsch     printactive(0);
1162d51bdf32SKirk McKusick     return 0;
116339bb6d1eSPeter Wemm }
116439bb6d1eSPeter Wemm 
116539bb6d1eSPeter Wemm int
dotime(char * name,time_t * secp,int32_t * nsecp)11661c85e6a3SKirk McKusick dotime(char *name, time_t *secp, int32_t *nsecp)
116739bb6d1eSPeter Wemm {
116839bb6d1eSPeter Wemm     char *p, *val;
116939bb6d1eSPeter Wemm     struct tm t;
117039bb6d1eSPeter Wemm     int32_t nsec;
117139bb6d1eSPeter Wemm     p = strchr(name, '.');
117239bb6d1eSPeter Wemm     if (p) {
117339bb6d1eSPeter Wemm 	*p = '\0';
117439bb6d1eSPeter Wemm 	nsec = strtoul(++p, &val, 0);
117539bb6d1eSPeter Wemm 	if (val == p || *val != '\0' || nsec >= 1000000000 || nsec < 0) {
117639bb6d1eSPeter Wemm 		warnx("invalid nanoseconds");
117739bb6d1eSPeter Wemm 		goto badformat;
117839bb6d1eSPeter Wemm 	}
117939bb6d1eSPeter Wemm     } else
118039bb6d1eSPeter Wemm 	nsec = 0;
118139bb6d1eSPeter Wemm     if (strlen(name) != 14) {
118239bb6d1eSPeter Wemm badformat:
118339bb6d1eSPeter Wemm 	warnx("date format: YYYYMMDDHHMMSS[.nsec]");
118439bb6d1eSPeter Wemm 	return 1;
118539bb6d1eSPeter Wemm     }
11861c85e6a3SKirk McKusick     *nsecp = nsec;
118739bb6d1eSPeter Wemm 
118839bb6d1eSPeter Wemm     for (p = name; *p; p++)
118939bb6d1eSPeter Wemm 	if (*p < '0' || *p > '9')
119039bb6d1eSPeter Wemm 	    goto badformat;
119139bb6d1eSPeter Wemm 
119239bb6d1eSPeter Wemm     p = name;
119339bb6d1eSPeter Wemm #define VAL() ((*p++) - '0')
119439bb6d1eSPeter Wemm     t.tm_year = VAL();
119539bb6d1eSPeter Wemm     t.tm_year = VAL() + t.tm_year * 10;
119639bb6d1eSPeter Wemm     t.tm_year = VAL() + t.tm_year * 10;
119739bb6d1eSPeter Wemm     t.tm_year = VAL() + t.tm_year * 10 - 1900;
119839bb6d1eSPeter Wemm     t.tm_mon = VAL();
119939bb6d1eSPeter Wemm     t.tm_mon = VAL() + t.tm_mon * 10 - 1;
120039bb6d1eSPeter Wemm     t.tm_mday = VAL();
120139bb6d1eSPeter Wemm     t.tm_mday = VAL() + t.tm_mday * 10;
120239bb6d1eSPeter Wemm     t.tm_hour = VAL();
120339bb6d1eSPeter Wemm     t.tm_hour = VAL() + t.tm_hour * 10;
120439bb6d1eSPeter Wemm     t.tm_min = VAL();
120539bb6d1eSPeter Wemm     t.tm_min = VAL() + t.tm_min * 10;
120639bb6d1eSPeter Wemm     t.tm_sec = VAL();
120739bb6d1eSPeter Wemm     t.tm_sec = VAL() + t.tm_sec * 10;
120839bb6d1eSPeter Wemm     t.tm_isdst = -1;
120939bb6d1eSPeter Wemm 
12101c85e6a3SKirk McKusick     *secp = mktime(&t);
12111c85e6a3SKirk McKusick     if (*secp == -1) {
121239bb6d1eSPeter Wemm 	warnx("date/time out of range");
121339bb6d1eSPeter Wemm 	return 1;
121439bb6d1eSPeter Wemm     }
121539bb6d1eSPeter Wemm     return 0;
121639bb6d1eSPeter Wemm }
121739bb6d1eSPeter Wemm 
CMDFUNCSTART(chbtime)121896dd6360SCeri Davies CMDFUNCSTART(chbtime)
121996dd6360SCeri Davies {
122096dd6360SCeri Davies     time_t secs;
122196dd6360SCeri Davies     int32_t nsecs;
122296dd6360SCeri Davies 
122396dd6360SCeri Davies     if (dotime(argv[1], &secs, &nsecs))
122496dd6360SCeri Davies 	return 1;
122596dd6360SCeri Davies     if (sblock.fs_magic == FS_UFS1_MAGIC)
122696dd6360SCeri Davies 	return 1;
122796dd6360SCeri Davies     curinode->dp2.di_birthtime = _time_to_time64(secs);
122896dd6360SCeri Davies     curinode->dp2.di_birthnsec = nsecs;
12295cc52631SKirk McKusick     inodirty(&curip);
123096dd6360SCeri Davies     printactive(0);
123196dd6360SCeri Davies     return 0;
123296dd6360SCeri Davies }
123396dd6360SCeri Davies 
CMDFUNCSTART(chmtime)123439bb6d1eSPeter Wemm CMDFUNCSTART(chmtime)
123539bb6d1eSPeter Wemm {
12361c85e6a3SKirk McKusick     time_t secs;
12371c85e6a3SKirk McKusick     int32_t nsecs;
12381c85e6a3SKirk McKusick 
12391c85e6a3SKirk McKusick     if (dotime(argv[1], &secs, &nsecs))
124039bb6d1eSPeter Wemm 	return 1;
12411c85e6a3SKirk McKusick     if (sblock.fs_magic == FS_UFS1_MAGIC)
12421c85e6a3SKirk McKusick 	curinode->dp1.di_mtime = _time_to_time32(secs);
12431c85e6a3SKirk McKusick     else
12441c85e6a3SKirk McKusick 	curinode->dp2.di_mtime = _time_to_time64(secs);
1245c9eaf226SLukas Ertl     DIP_SET(curinode, di_mtimensec, nsecs);
12465cc52631SKirk McKusick     inodirty(&curip);
1247280a49ecSJoerg Wunsch     printactive(0);
124839bb6d1eSPeter Wemm     return 0;
124939bb6d1eSPeter Wemm }
125039bb6d1eSPeter Wemm 
CMDFUNCSTART(chatime)125139bb6d1eSPeter Wemm CMDFUNCSTART(chatime)
125239bb6d1eSPeter Wemm {
12531c85e6a3SKirk McKusick     time_t secs;
12541c85e6a3SKirk McKusick     int32_t nsecs;
12551c85e6a3SKirk McKusick 
12561c85e6a3SKirk McKusick     if (dotime(argv[1], &secs, &nsecs))
125739bb6d1eSPeter Wemm 	return 1;
12581c85e6a3SKirk McKusick     if (sblock.fs_magic == FS_UFS1_MAGIC)
12591c85e6a3SKirk McKusick 	curinode->dp1.di_atime = _time_to_time32(secs);
12601c85e6a3SKirk McKusick     else
12611c85e6a3SKirk McKusick 	curinode->dp2.di_atime = _time_to_time64(secs);
1262c9eaf226SLukas Ertl     DIP_SET(curinode, di_atimensec, nsecs);
12635cc52631SKirk McKusick     inodirty(&curip);
1264280a49ecSJoerg Wunsch     printactive(0);
126539bb6d1eSPeter Wemm     return 0;
126639bb6d1eSPeter Wemm }
126739bb6d1eSPeter Wemm 
CMDFUNCSTART(chctime)126839bb6d1eSPeter Wemm CMDFUNCSTART(chctime)
126939bb6d1eSPeter Wemm {
12701c85e6a3SKirk McKusick     time_t secs;
12711c85e6a3SKirk McKusick     int32_t nsecs;
12721c85e6a3SKirk McKusick 
12731c85e6a3SKirk McKusick     if (dotime(argv[1], &secs, &nsecs))
127439bb6d1eSPeter Wemm 	return 1;
12751c85e6a3SKirk McKusick     if (sblock.fs_magic == FS_UFS1_MAGIC)
12761c85e6a3SKirk McKusick 	curinode->dp1.di_ctime = _time_to_time32(secs);
12771c85e6a3SKirk McKusick     else
12781c85e6a3SKirk McKusick 	curinode->dp2.di_ctime = _time_to_time64(secs);
1279c9eaf226SLukas Ertl     DIP_SET(curinode, di_ctimensec, nsecs);
12805cc52631SKirk McKusick     inodirty(&curip);
1281280a49ecSJoerg Wunsch     printactive(0);
128239bb6d1eSPeter Wemm     return 0;
128339bb6d1eSPeter Wemm }
1284