xref: /openbsd/sbin/fsdb/fsdb.c (revision da5362d5)
1*da5362d5Sguenther /*	$OpenBSD: fsdb.c,v 1.36 2024/01/09 03:16:00 guenther Exp $	*/
200829d25Smillert /*	$NetBSD: fsdb.c,v 1.7 1997/01/11 06:50:53 lukem Exp $	*/
3df930be7Sderaadt 
4be0fe854Sniklas /*-
5be0fe854Sniklas  * Copyright (c) 1996 The NetBSD Foundation, Inc.
6df930be7Sderaadt  * All rights reserved.
7df930be7Sderaadt  *
8be0fe854Sniklas  * This code is derived from software contributed to The NetBSD Foundation
9be0fe854Sniklas  * by John T. Kohl.
10be0fe854Sniklas  *
11df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
12df930be7Sderaadt  * modification, are permitted provided that the following conditions
13df930be7Sderaadt  * are met:
14df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
15df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
16df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
17df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
18df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
19df930be7Sderaadt  *
20be0fe854Sniklas  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21be0fe854Sniklas  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22be0fe854Sniklas  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23be0fe854Sniklas  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
24be0fe854Sniklas  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25be0fe854Sniklas  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26be0fe854Sniklas  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27be0fe854Sniklas  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28be0fe854Sniklas  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29be0fe854Sniklas  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30df930be7Sderaadt  * POSSIBILITY OF SUCH DAMAGE.
31df930be7Sderaadt  */
32df930be7Sderaadt 
33df930be7Sderaadt #include <sys/stat.h>
34df930be7Sderaadt #include <sys/time.h>
35df930be7Sderaadt #include <sys/mount.h>
36df930be7Sderaadt #include <ctype.h>
3700829d25Smillert #include <err.h>
38df930be7Sderaadt #include <fcntl.h>
39df930be7Sderaadt #include <grp.h>
40df930be7Sderaadt #include <histedit.h>
41df930be7Sderaadt #include <limits.h>
42df930be7Sderaadt #include <pwd.h>
43df930be7Sderaadt #include <stdio.h>
44df930be7Sderaadt #include <stdlib.h>
45df930be7Sderaadt #include <string.h>
46df930be7Sderaadt #include <unistd.h>
47df930be7Sderaadt 
48df930be7Sderaadt #include <ufs/ufs/dinode.h>
49df930be7Sderaadt #include <ufs/ufs/dir.h>
50df930be7Sderaadt #include <ufs/ffs/fs.h>
51df930be7Sderaadt 
52df930be7Sderaadt #include "fsdb.h"
53df930be7Sderaadt #include "fsck.h"
5400829d25Smillert #include "extern.h"
55df930be7Sderaadt 
56df930be7Sderaadt extern char *__progname;	/* from crt0.o */
57df930be7Sderaadt 
58c72b5b24Smillert int main(int, char *[]);
59c72b5b24Smillert static void usage(void);
60c72b5b24Smillert static int cmdloop(void);
61c72b5b24Smillert static int helpfn(int, char *[]);
62c72b5b24Smillert static char *prompt(EditLine *);
63c72b5b24Smillert static int scannames(struct inodesc *);
64c72b5b24Smillert static int dolookup(char *);
65c72b5b24Smillert static int chinumfunc(struct inodesc *);
66c72b5b24Smillert static int chnamefunc(struct inodesc *);
67904f6f58Sotto static int dotime(char *, time_t *, int32_t *);
68df930be7Sderaadt 
6900829d25Smillert int returntosingle = 0;
70c913562aSmillert union dinode *curinode;
7100829d25Smillert ino_t curinum;
7200829d25Smillert 
730986c204Sderaadt struct inostatlist *inostathead;
740986c204Sderaadt 
750986c204Sderaadt struct bufarea bufhead;		/* head of list of other blks in filesys */
760986c204Sderaadt struct bufarea sblk;		/* file system superblock */
770986c204Sderaadt struct bufarea asblk;		/* alternate file system superblock */
780986c204Sderaadt struct bufarea *pdirbp;		/* current directory contents */
790986c204Sderaadt struct bufarea *pbp;		/* current inode block */
800986c204Sderaadt 
810986c204Sderaadt struct dups *duplist;		/* head of dup list */
820986c204Sderaadt struct dups *muldup;		/* end of unique duplicate dup block numbers */
830986c204Sderaadt 
840986c204Sderaadt struct zlncnt *zlnhead;		/* head of zero link count list */
850986c204Sderaadt 
860986c204Sderaadt struct inoinfo **inphead, **inpsort;
870986c204Sderaadt 
880986c204Sderaadt extern long numdirs, listmax, inplast;
890986c204Sderaadt 
900986c204Sderaadt long	secsize;		/* actual disk sector size */
910986c204Sderaadt char	nflag;			/* assume a no response */
920986c204Sderaadt char	yflag;			/* assume a yes response */
930986c204Sderaadt daddr_t	bflag;			/* location of alternate super block */
940986c204Sderaadt int	debug;			/* output debugging info */
950986c204Sderaadt int	cvtlevel;		/* convert to newer file system format */
960986c204Sderaadt char    usedsoftdep;            /* just fix soft dependency inconsistencies */
970986c204Sderaadt int	preen;			/* just fix normal inconsistencies */
980986c204Sderaadt char    resolved;               /* cleared if unresolved changes => not clean */
990986c204Sderaadt char	havesb;			/* superblock has been read */
1000986c204Sderaadt char	skipclean;		/* skip clean file systems if preening */
1010986c204Sderaadt int	fsmodified;		/* 1 => write done to file system */
1020986c204Sderaadt int	fsreadfd;		/* file descriptor for reading file system */
1030986c204Sderaadt int	fswritefd;		/* file descriptor for writing file system */
1040986c204Sderaadt int	rerun;			/* rerun fsck.  Only used in non-preen mode */
1050986c204Sderaadt 
1060986c204Sderaadt daddr_t	maxfsblock;		/* number of blocks in the file system */
1070986c204Sderaadt char	*blockmap;		/* ptr to primary blk allocation map */
1080986c204Sderaadt ino_t	maxino;			/* number of inodes in file system */
1090986c204Sderaadt ino_t	lastino;		/* last inode in use */
1100986c204Sderaadt 
1110986c204Sderaadt ino_t	lfdir;			/* lost & found directory inode number */
1120986c204Sderaadt 
1130986c204Sderaadt daddr_t	n_blks;			/* number of blocks in use */
1140986c204Sderaadt int64_t	n_files;		/* number of files in use */
1150986c204Sderaadt 
1160986c204Sderaadt struct ufs1_dinode ufs1_zino;
1170986c204Sderaadt struct ufs2_dinode ufs2_zino;
1180986c204Sderaadt 
1190986c204Sderaadt 
12000829d25Smillert static void
usage(void)1218809fabbSderaadt usage(void)
122df930be7Sderaadt {
1233fd4512fSjmc 	fprintf(stderr, "usage: %s [-d] -f fsname\n", __progname);
124209724cbSalex 	exit(1);
125df930be7Sderaadt }
126df930be7Sderaadt 
127df930be7Sderaadt /*
128df930be7Sderaadt  * We suck in lots of fsck code, and just pick & choose the stuff we want.
129df930be7Sderaadt  *
130df930be7Sderaadt  * fsreadfd is set up to read from the file system, fswritefd to write to
131df930be7Sderaadt  * the file system.
132df930be7Sderaadt  */
133f3bae140Sderaadt int
main(int argc,char * argv[])1348809fabbSderaadt main(int argc, char *argv[])
135df930be7Sderaadt {
136df930be7Sderaadt 	int ch, rval;
137df930be7Sderaadt 	char *fsys = NULL;
138df930be7Sderaadt 
139df930be7Sderaadt 	while (-1 != (ch = getopt(argc, argv, "f:d"))) {
140df930be7Sderaadt 		switch (ch) {
141df930be7Sderaadt 		case 'f':
142df930be7Sderaadt 			fsys = optarg;
143df930be7Sderaadt 			break;
144df930be7Sderaadt 		case 'd':
145df930be7Sderaadt 			debug++;
146df930be7Sderaadt 			break;
147df930be7Sderaadt 		default:
148df930be7Sderaadt 			usage();
149df930be7Sderaadt 		}
150df930be7Sderaadt 	}
151df930be7Sderaadt 	if (fsys == NULL)
152df930be7Sderaadt 		usage();
153f0bf880cStb 	if (!setup(fsys, 1))
154df930be7Sderaadt 		errx(1, "cannot set up file system `%s'", fsys);
155df930be7Sderaadt 	printf("Editing file system `%s'\nLast Mounted on %s\n", fsys,
156df930be7Sderaadt 	    sblock.fs_fsmnt);
157df930be7Sderaadt 	rval = cmdloop();
158df930be7Sderaadt 	sblock.fs_clean = 0;		/* mark it dirty */
159df930be7Sderaadt 	sbdirty();
160df930be7Sderaadt 	ckfini(0);
161df930be7Sderaadt 	printf("*** FILE SYSTEM MARKED DIRTY\n");
162df930be7Sderaadt 	printf("*** BE SURE TO RUN FSCK TO CLEAN UP ANY DAMAGE\n");
163df930be7Sderaadt 	printf("*** IF IT WAS MOUNTED, RE-MOUNT WITH -u -o reload\n");
164df930be7Sderaadt 	exit(rval);
165df930be7Sderaadt }
166df930be7Sderaadt 
167c72b5b24Smillert #define CMDFUNC(func) static int func(int argc, char *argv[])
1688809fabbSderaadt #define CMDFUNCSTART(func) static int func(int argc, char *argv[])
169df930be7Sderaadt 
170df930be7Sderaadt CMDFUNC(helpfn);
171df930be7Sderaadt CMDFUNC(focus);				/* focus on inode */
172df930be7Sderaadt CMDFUNC(active);			/* print active inode */
173df930be7Sderaadt CMDFUNC(focusname);			/* focus by name */
174df930be7Sderaadt CMDFUNC(zapi);				/* clear inode */
175df930be7Sderaadt CMDFUNC(uplink);			/* incr link */
176df930be7Sderaadt CMDFUNC(downlink);			/* decr link */
177df930be7Sderaadt CMDFUNC(linkcount);			/* set link count */
178df930be7Sderaadt CMDFUNC(quit);				/* quit */
179df930be7Sderaadt CMDFUNC(ls);				/* list directory */
180df930be7Sderaadt CMDFUNC(rm);				/* remove name */
181df930be7Sderaadt CMDFUNC(ln);				/* add name */
182df930be7Sderaadt CMDFUNC(newtype);			/* change type */
183df930be7Sderaadt CMDFUNC(chmode);			/* change mode */
18400829d25Smillert CMDFUNC(chlen);				/* change length */
185df930be7Sderaadt CMDFUNC(chaflags);			/* change flags */
186df930be7Sderaadt CMDFUNC(chgen);				/* change generation */
187df930be7Sderaadt CMDFUNC(chowner);			/* change owner */
188df930be7Sderaadt CMDFUNC(chgroup);			/* Change group */
189df930be7Sderaadt CMDFUNC(back);				/* pop back to last ino */
190df930be7Sderaadt CMDFUNC(chmtime);			/* Change mtime */
191df930be7Sderaadt CMDFUNC(chctime);			/* Change ctime */
192df930be7Sderaadt CMDFUNC(chatime);			/* Change atime */
193df930be7Sderaadt CMDFUNC(chinum);			/* Change inode # of dirent */
194df930be7Sderaadt CMDFUNC(chname);			/* Change dirname of dirent */
195df930be7Sderaadt 
19600829d25Smillert static struct cmdtable cmds[] = {
197df930be7Sderaadt 	{ "help", "Print out help", 1, 1, helpfn },
198df930be7Sderaadt 	{ "?", "Print out help", 1, 1, helpfn },
199df930be7Sderaadt 	{ "inode", "Set active inode to INUM", 2, 2, focus },
200df930be7Sderaadt 	{ "clri", "Clear inode INUM", 2, 2, zapi },
201df930be7Sderaadt 	{ "lookup", "Set active inode by looking up NAME", 2, 2, focusname },
202df930be7Sderaadt 	{ "cd", "Set active inode by looking up NAME", 2, 2, focusname },
203df930be7Sderaadt 	{ "back", "Go to previous active inode", 1, 1, back },
204df930be7Sderaadt 	{ "active", "Print active inode", 1, 1, active },
205df930be7Sderaadt 	{ "print", "Print active inode", 1, 1, active },
206df930be7Sderaadt 	{ "uplink", "Increment link count", 1, 1, uplink },
207df930be7Sderaadt 	{ "downlink", "Decrement link count", 1, 1, downlink },
208df930be7Sderaadt 	{ "linkcount", "Set link count to COUNT", 2, 2, linkcount },
209df930be7Sderaadt 	{ "ls", "List current inode as directory", 1, 1, ls },
210df930be7Sderaadt 	{ "rm", "Remove NAME from current inode directory", 2, 2, rm },
211df930be7Sderaadt 	{ "del", "Remove NAME from current inode directory", 2, 2, rm },
212df930be7Sderaadt 	{ "ln", "Hardlink INO into current inode directory as NAME", 3, 3, ln },
213df930be7Sderaadt 	{ "chinum", "Change dir entry number INDEX to INUM", 3, 3, chinum },
214df930be7Sderaadt 	{ "chname", "Change dir entry number INDEX to NAME", 3, 3, chname },
215df930be7Sderaadt 	{ "chtype", "Change type of current inode to TYPE", 2, 2, newtype },
216df930be7Sderaadt 	{ "chmod", "Change mode of current inode to MODE", 2, 2, chmode },
217df930be7Sderaadt 	{ "chown", "Change owner of current inode to OWNER", 2, 2, chowner },
21800829d25Smillert 	{ "chlen", "Change length of current inode to LENGTH", 2, 2, chlen },
219df930be7Sderaadt 	{ "chgrp", "Change group of current inode to GROUP", 2, 2, chgroup },
220df930be7Sderaadt 	{ "chflags", "Change flags of current inode to FLAGS", 2, 2, chaflags },
221df930be7Sderaadt 	{ "chgen", "Change generation number of current inode to GEN", 2, 2, chgen },
222df930be7Sderaadt 	{ "mtime", "Change mtime of current inode to MTIME", 2, 2, chmtime },
223df930be7Sderaadt 	{ "ctime", "Change ctime of current inode to CTIME", 2, 2, chctime },
224df930be7Sderaadt 	{ "atime", "Change atime of current inode to ATIME", 2, 2, chatime },
225df930be7Sderaadt 	{ "quit", "Exit", 1, 1, quit },
226df930be7Sderaadt 	{ "q", "Exit", 1, 1, quit },
227df930be7Sderaadt 	{ "exit", "Exit", 1, 1, quit },
228df930be7Sderaadt 	{ NULL, 0, 0, 0 },
229df930be7Sderaadt };
230df930be7Sderaadt 
23100829d25Smillert static int
helpfn(int argc,char * argv[])2328809fabbSderaadt helpfn(int argc, char *argv[])
233df930be7Sderaadt {
234e073c79dSmpech 	struct cmdtable *cmdtp;
235df930be7Sderaadt 
236df930be7Sderaadt 	printf("Commands are:\n%-10s %5s %5s   %s\n",
237df930be7Sderaadt 	    "command", "min argc", "max argc", "what");
238df930be7Sderaadt 
239df930be7Sderaadt 	for (cmdtp = cmds; cmdtp->cmd; cmdtp++)
240df930be7Sderaadt 		printf("%-10s %5u %5u   %s\n",
241df930be7Sderaadt 		    cmdtp->cmd, cmdtp->minargc, cmdtp->maxargc, cmdtp->helptxt);
242df930be7Sderaadt 	return 0;
243df930be7Sderaadt }
244df930be7Sderaadt 
24500829d25Smillert static char *
prompt(EditLine * el)2468809fabbSderaadt prompt(EditLine *el)
247df930be7Sderaadt {
248df930be7Sderaadt 	static char pstring[64];
2498809fabbSderaadt 
2503b92bd08Sderaadt 	snprintf(pstring, sizeof(pstring), "fsdb (inum: %llu)> ",
2513b92bd08Sderaadt 	    (unsigned long long)curinum);
252df930be7Sderaadt 	return pstring;
253df930be7Sderaadt }
254df930be7Sderaadt 
255df930be7Sderaadt 
25600829d25Smillert static int
cmdloop(void)2578809fabbSderaadt cmdloop(void)
258df930be7Sderaadt {
25900829d25Smillert 	char *line = NULL;
260df930be7Sderaadt 	const char *elline;
261df930be7Sderaadt 	int cmd_argc, rval = 0, known;
262df930be7Sderaadt #define scratch known
263df930be7Sderaadt 	char **cmd_argv;
264df930be7Sderaadt 	struct cmdtable *cmdp;
265df930be7Sderaadt 	History *hist;
266df930be7Sderaadt 	EditLine *elptr;
2678b59c5f0Sotto 	HistEvent hev;
268df930be7Sderaadt 
269df930be7Sderaadt 	curinode = ginode(ROOTINO);
270df930be7Sderaadt 	curinum = ROOTINO;
271df930be7Sderaadt 	printactive();
272df930be7Sderaadt 
273df930be7Sderaadt 	hist = history_init();
2748b59c5f0Sotto 	history(hist, &hev, H_SETSIZE, 100);	/* 100 elt history buffer */
275df930be7Sderaadt 
2768b59c5f0Sotto 	elptr = el_init(__progname, stdin, stdout, stderr);
277df930be7Sderaadt 	el_set(elptr, EL_EDITOR, "emacs");
278df930be7Sderaadt 	el_set(elptr, EL_PROMPT, prompt);
279df930be7Sderaadt 	el_set(elptr, EL_HIST, history, hist);
280df930be7Sderaadt 	el_source(elptr, NULL);
281df930be7Sderaadt 
282df930be7Sderaadt 	while ((elline = el_gets(elptr, &scratch)) != NULL && scratch != 0) {
283df930be7Sderaadt 		if (debug)
284aed4bff2Sjsg 			printf("command `%s'\n", elline);
285df930be7Sderaadt 
2868b59c5f0Sotto 		history(hist, &hev, H_ENTER, elline);
287df930be7Sderaadt 
288df930be7Sderaadt 		line = strdup(elline);
289ca198d9fSderaadt 		if (line == NULL)
290ca198d9fSderaadt 			errx(1, "out of memory");
291df930be7Sderaadt 		cmd_argv = crack(line, &cmd_argc);
29200829d25Smillert 		if (cmd_argc) {
293df930be7Sderaadt 			/*
294df930be7Sderaadt 			 * el_parse returns -1 to signal that it's not been handled
295df930be7Sderaadt 			 * internally.
296df930be7Sderaadt 			 */
2978b59c5f0Sotto 			if (el_parse(elptr, cmd_argc, (const char **)cmd_argv) != -1)
298df930be7Sderaadt 				continue;
299df930be7Sderaadt 			known = 0;
300df930be7Sderaadt 			for (cmdp = cmds; cmdp->cmd; cmdp++) {
301df930be7Sderaadt 				if (!strcmp(cmdp->cmd, cmd_argv[0])) {
302df930be7Sderaadt 					if (cmd_argc >= cmdp->minargc &&
303df930be7Sderaadt 					    cmd_argc <= cmdp->maxargc)
3048809fabbSderaadt 						rval = (*cmdp->handler)(cmd_argc,
3058809fabbSderaadt 						    cmd_argv);
306df930be7Sderaadt 					else
3078809fabbSderaadt 						rval = argcount(cmdp,
3088809fabbSderaadt 						    cmd_argc, cmd_argv);
309df930be7Sderaadt 					known = 1;
310df930be7Sderaadt 					break;
311df930be7Sderaadt 				}
312df930be7Sderaadt 			}
3138809fabbSderaadt 			if (!known) {
3148809fabbSderaadt 				warnx("unknown command `%s'", cmd_argv[0]);
3158809fabbSderaadt 				rval = 1;
3168809fabbSderaadt 			}
317df930be7Sderaadt 		} else
318df930be7Sderaadt 			rval = 0;
319df930be7Sderaadt 		free(line);
320df930be7Sderaadt 		if (rval < 0)
321df930be7Sderaadt 			return rval;
322df930be7Sderaadt 		if (rval)
323df930be7Sderaadt 			warnx("rval was %d", rval);
324df930be7Sderaadt 	}
325df930be7Sderaadt 	el_end(elptr);
326df930be7Sderaadt 	history_end(hist);
327df930be7Sderaadt 	return rval;
328df930be7Sderaadt }
329df930be7Sderaadt 
33000829d25Smillert static ino_t ocurrent;
331df930be7Sderaadt 
332520eb379Sotto #define GETINUM(ac,inum)    inum = strtoull(argv[ac], &cp, 0); \
333df930be7Sderaadt 	if (inum < ROOTINO || inum > maxino || cp == argv[ac] || *cp != '\0' ) { \
334520eb379Sotto 		printf("inode %llu out of range; range is [%llu,%llu]\n", \
335520eb379Sotto 		    (unsigned long long)inum, (unsigned long long)ROOTINO, \
336520eb379Sotto 		    (unsigned long long)maxino); \
337df930be7Sderaadt 		return 1; \
338df930be7Sderaadt 	}
339df930be7Sderaadt 
340df930be7Sderaadt /*
341df930be7Sderaadt  * Focus on given inode number
342df930be7Sderaadt  */
CMDFUNCSTART(focus)343df930be7Sderaadt CMDFUNCSTART(focus)
344df930be7Sderaadt {
345df930be7Sderaadt 	ino_t inum;
346df930be7Sderaadt 	char *cp;
347df930be7Sderaadt 
348df930be7Sderaadt 	GETINUM(1,inum);
349df930be7Sderaadt 	curinode = ginode(inum);
350df930be7Sderaadt 	ocurrent = curinum;
351df930be7Sderaadt 	curinum = inum;
352df930be7Sderaadt 	printactive();
353df930be7Sderaadt 	return 0;
354df930be7Sderaadt }
355df930be7Sderaadt 
CMDFUNCSTART(back)356df930be7Sderaadt CMDFUNCSTART(back)
357df930be7Sderaadt {
358df930be7Sderaadt 	curinum = ocurrent;
359df930be7Sderaadt 	curinode = ginode(curinum);
360df930be7Sderaadt 	printactive();
361df930be7Sderaadt 	return 0;
362df930be7Sderaadt }
363df930be7Sderaadt 
CMDFUNCSTART(zapi)364df930be7Sderaadt CMDFUNCSTART(zapi)
365df930be7Sderaadt {
366df930be7Sderaadt 	ino_t inum;
367c913562aSmillert 	union dinode *dp;
368df930be7Sderaadt 	char *cp;
369df930be7Sderaadt 
370df930be7Sderaadt 	GETINUM(1,inum);
371df930be7Sderaadt 	dp = ginode(inum);
372df930be7Sderaadt 	clearinode(dp);
373df930be7Sderaadt 	inodirty();
374df930be7Sderaadt 	if (curinode)			/* re-set after potential change */
375df930be7Sderaadt 		curinode = ginode(curinum);
376df930be7Sderaadt 	return 0;
377df930be7Sderaadt }
378df930be7Sderaadt 
CMDFUNCSTART(active)379df930be7Sderaadt CMDFUNCSTART(active)
380df930be7Sderaadt {
381df930be7Sderaadt 	printactive();
382df930be7Sderaadt 	return 0;
383df930be7Sderaadt }
384df930be7Sderaadt 
385df930be7Sderaadt 
CMDFUNCSTART(quit)386df930be7Sderaadt CMDFUNCSTART(quit)
387df930be7Sderaadt {
388df930be7Sderaadt 	return -1;
389df930be7Sderaadt }
390df930be7Sderaadt 
CMDFUNCSTART(uplink)391df930be7Sderaadt CMDFUNCSTART(uplink)
392df930be7Sderaadt {
393df930be7Sderaadt 	if (!checkactive())
394df930be7Sderaadt 		return 1;
395c913562aSmillert 	DIP_SET(curinode, di_nlink, DIP(curinode, di_nlink) + 1);
3963b92bd08Sderaadt 	printf("inode %llu link count now %d\n",
3973b92bd08Sderaadt 	    (unsigned long long)curinum, DIP(curinode, di_nlink));
398df930be7Sderaadt 	inodirty();
399df930be7Sderaadt 	return 0;
400df930be7Sderaadt }
401df930be7Sderaadt 
CMDFUNCSTART(downlink)402df930be7Sderaadt CMDFUNCSTART(downlink)
403df930be7Sderaadt {
404df930be7Sderaadt 	if (!checkactive())
405df930be7Sderaadt 		return 1;
406c913562aSmillert 	DIP_SET(curinode, di_nlink, DIP(curinode, di_nlink) - 1);
4073b92bd08Sderaadt 	printf("inode %llu link count now %d\n",
4083b92bd08Sderaadt 	    (unsigned long long)curinum, DIP(curinode, di_nlink));
409df930be7Sderaadt 	inodirty();
410df930be7Sderaadt 	return 0;
411df930be7Sderaadt }
412df930be7Sderaadt 
41300829d25Smillert static const char *typename[] = {
414df930be7Sderaadt 	"unknown",
415df930be7Sderaadt 	"fifo",
416df930be7Sderaadt 	"char special",
417df930be7Sderaadt 	"unregistered #3",
418df930be7Sderaadt 	"directory",
419df930be7Sderaadt 	"unregistered #5",
420df930be7Sderaadt 	"blk special",
421df930be7Sderaadt 	"unregistered #7",
422df930be7Sderaadt 	"regular",
423df930be7Sderaadt 	"unregistered #9",
424df930be7Sderaadt 	"symlink",
425df930be7Sderaadt 	"unregistered #11",
426df930be7Sderaadt 	"socket",
427df930be7Sderaadt 	"unregistered #13",
428df930be7Sderaadt 	"whiteout",
429df930be7Sderaadt };
430df930be7Sderaadt 
43100829d25Smillert static int slot;
432df930be7Sderaadt 
43300829d25Smillert static int
scannames(struct inodesc * idesc)4348809fabbSderaadt scannames(struct inodesc *idesc)
435df930be7Sderaadt {
436e073c79dSmpech 	struct direct *dirp = idesc->id_dirp;
437df930be7Sderaadt 
4383b92bd08Sderaadt 	printf("slot %d ino %llu reclen %d: %s, `%.*s'\n",
4393b92bd08Sderaadt 	    slot++, (unsigned long long)dirp->d_ino, dirp->d_reclen,
4403b92bd08Sderaadt 	    typename[dirp->d_type], dirp->d_namlen, dirp->d_name);
441df930be7Sderaadt 	return (KEEPON);
442df930be7Sderaadt }
443df930be7Sderaadt 
CMDFUNCSTART(ls)444df930be7Sderaadt CMDFUNCSTART(ls)
445df930be7Sderaadt {
446df930be7Sderaadt 	struct inodesc idesc;
447df930be7Sderaadt 	checkactivedir();			/* let it go on anyway */
448df930be7Sderaadt 
449df930be7Sderaadt 	slot = 0;
450df930be7Sderaadt 	idesc.id_number = curinum;
451df930be7Sderaadt 	idesc.id_func = scannames;
452df930be7Sderaadt 	idesc.id_type = DATA;
453df930be7Sderaadt 	idesc.id_fix = IGNORE;
454df930be7Sderaadt 	ckinode(curinode, &idesc);
455df930be7Sderaadt 	curinode = ginode(curinum);
456df930be7Sderaadt 
457df930be7Sderaadt 	return 0;
458df930be7Sderaadt }
459df930be7Sderaadt 
460df930be7Sderaadt static int
dolookup(char * name)4618809fabbSderaadt dolookup(char *name)
462df930be7Sderaadt {
463df930be7Sderaadt 	struct inodesc idesc;
464df930be7Sderaadt 
465df930be7Sderaadt 	if (!checkactivedir())
466df930be7Sderaadt 		return 0;
467df930be7Sderaadt 	idesc.id_number = curinum;
468df930be7Sderaadt 	idesc.id_func = findino;
469df930be7Sderaadt 	idesc.id_name = name;
470df930be7Sderaadt 	idesc.id_type = DATA;
471df930be7Sderaadt 	idesc.id_fix = IGNORE;
472df930be7Sderaadt 	if (ckinode(curinode, &idesc) & FOUND) {
473df930be7Sderaadt 		curinum = idesc.id_parent;
474df930be7Sderaadt 		curinode = ginode(curinum);
475df930be7Sderaadt 		printactive();
476df930be7Sderaadt 		return 1;
477df930be7Sderaadt 	} else {
478df930be7Sderaadt 		warnx("name `%s' not found in current inode directory", name);
479df930be7Sderaadt 		return 0;
480df930be7Sderaadt 	}
481df930be7Sderaadt }
482df930be7Sderaadt 
CMDFUNCSTART(focusname)483df930be7Sderaadt CMDFUNCSTART(focusname)
484df930be7Sderaadt {
485df930be7Sderaadt 	char *p, *val;
486df930be7Sderaadt 
487df930be7Sderaadt 	if (!checkactive())
488df930be7Sderaadt 		return 1;
489df930be7Sderaadt 
490df930be7Sderaadt 	ocurrent = curinum;
491df930be7Sderaadt 
492df930be7Sderaadt 	if (argv[1][0] == '/') {
493df930be7Sderaadt 		curinum = ROOTINO;
494df930be7Sderaadt 		curinode = ginode(ROOTINO);
495df930be7Sderaadt 	} else {
496df930be7Sderaadt 		if (!checkactivedir())
497df930be7Sderaadt 		    return 1;
498df930be7Sderaadt 	}
499df930be7Sderaadt 	for (p = argv[1]; p != NULL;) {
5001a14b407Saaron 		while ((val = strsep(&p, "/")) != NULL && *val == '\0')
501252fb110Stedu 			continue;
502df930be7Sderaadt 		if (val) {
503df930be7Sderaadt 			printf("component `%s': ", val);
504df930be7Sderaadt 			fflush(stdout);
505df930be7Sderaadt 			if (!dolookup(val)) {
506df930be7Sderaadt 				curinode = ginode(curinum);
507df930be7Sderaadt 				return(1);
508df930be7Sderaadt 			}
509df930be7Sderaadt 		}
510df930be7Sderaadt 	}
511df930be7Sderaadt 	return 0;
512df930be7Sderaadt }
513df930be7Sderaadt 
CMDFUNCSTART(ln)514df930be7Sderaadt CMDFUNCSTART(ln)
515df930be7Sderaadt {
516df930be7Sderaadt 	ino_t inum;
517df930be7Sderaadt 	int rval;
518df930be7Sderaadt 	char *cp;
519df930be7Sderaadt 
520df930be7Sderaadt 	GETINUM(1,inum);
521df930be7Sderaadt 
522df930be7Sderaadt 	if (!checkactivedir())
523df930be7Sderaadt 		return 1;
524df930be7Sderaadt 	rval = makeentry(curinum, inum, argv[2]);
525df930be7Sderaadt 	if (rval)
5263b92bd08Sderaadt 		printf("Ino %llu entered as `%s'\n",
5273b92bd08Sderaadt 		    (unsigned long long)inum, argv[2]);
528df930be7Sderaadt 	else
529df930be7Sderaadt 		printf("could not enter name? weird.\n");
530df930be7Sderaadt 	curinode = ginode(curinum);
531df930be7Sderaadt 	return rval;
532df930be7Sderaadt }
533df930be7Sderaadt 
CMDFUNCSTART(rm)534df930be7Sderaadt CMDFUNCSTART(rm)
535df930be7Sderaadt {
536df930be7Sderaadt 	int rval;
537df930be7Sderaadt 
538df930be7Sderaadt 	if (!checkactivedir())
539df930be7Sderaadt 		return 1;
540df930be7Sderaadt 	rval = changeino(curinum, argv[1], 0);
541df930be7Sderaadt 	if (rval & ALTERED) {
542df930be7Sderaadt 		printf("Name `%s' removed\n", argv[1]);
543df930be7Sderaadt 		return 0;
544df930be7Sderaadt 	} else {
545df930be7Sderaadt 		printf("could not remove name? weird.\n");
546df930be7Sderaadt 		return 1;
547df930be7Sderaadt 	}
548df930be7Sderaadt }
549df930be7Sderaadt 
55000829d25Smillert static long slotcount, desired;
551df930be7Sderaadt 
55200829d25Smillert static int
chinumfunc(struct inodesc * idesc)5538809fabbSderaadt chinumfunc(struct inodesc *idesc)
554df930be7Sderaadt {
555e073c79dSmpech 	struct direct *dirp = idesc->id_dirp;
556df930be7Sderaadt 
557df930be7Sderaadt 	if (slotcount++ == desired) {
558df930be7Sderaadt 	    dirp->d_ino = idesc->id_parent;
559df930be7Sderaadt 	    return STOP|ALTERED|FOUND;
560df930be7Sderaadt 	}
561df930be7Sderaadt 	return KEEPON;
562df930be7Sderaadt }
563df930be7Sderaadt 
CMDFUNCSTART(chinum)564df930be7Sderaadt CMDFUNCSTART(chinum)
565df930be7Sderaadt {
566df930be7Sderaadt 	char *cp;
567df930be7Sderaadt 	ino_t inum;
568df930be7Sderaadt 	struct inodesc idesc;
569df930be7Sderaadt 
570df930be7Sderaadt 	slotcount = 0;
571df930be7Sderaadt 	if (!checkactivedir())
572df930be7Sderaadt 		return 1;
573df930be7Sderaadt 	GETINUM(2,inum);
574df930be7Sderaadt 
575df930be7Sderaadt 	desired = strtol(argv[1], &cp, 0);
576df930be7Sderaadt 	if (cp == argv[1] || *cp != '\0' || desired < 0) {
577df930be7Sderaadt 		printf("invalid slot number `%s'\n", argv[1]);
578df930be7Sderaadt 		return 1;
579df930be7Sderaadt 	}
580df930be7Sderaadt 
581df930be7Sderaadt 	idesc.id_number = curinum;
582df930be7Sderaadt 	idesc.id_func = chinumfunc;
583df930be7Sderaadt 	idesc.id_fix = IGNORE;
584df930be7Sderaadt 	idesc.id_type = DATA;
585df930be7Sderaadt 	idesc.id_parent = inum;		/* XXX convenient hiding place */
586df930be7Sderaadt 
587df930be7Sderaadt 	if (ckinode(curinode, &idesc) & FOUND)
588df930be7Sderaadt 		return 0;
589df930be7Sderaadt 	else {
590df930be7Sderaadt 		warnx("no %sth slot in current directory", argv[1]);
591df930be7Sderaadt 		return 1;
592df930be7Sderaadt 	}
593df930be7Sderaadt }
594df930be7Sderaadt 
59500829d25Smillert static int
chnamefunc(struct inodesc * idesc)5968809fabbSderaadt chnamefunc(struct inodesc *idesc)
597df930be7Sderaadt {
598e073c79dSmpech 	struct direct *dirp = idesc->id_dirp;
599df930be7Sderaadt 	struct direct testdir;
600df930be7Sderaadt 
601df930be7Sderaadt 	if (slotcount++ == desired) {
602df930be7Sderaadt 		/* will name fit? */
603df930be7Sderaadt 		testdir.d_namlen = strlen(idesc->id_name);
604*da5362d5Sguenther 		if (DIRSIZ(&testdir) <= dirp->d_reclen) {
605df930be7Sderaadt 			dirp->d_namlen = testdir.d_namlen;
6069bf6056aSderaadt 			strlcpy(dirp->d_name, idesc->id_name, sizeof dirp->d_name);
607df930be7Sderaadt 			return STOP|ALTERED|FOUND;
608df930be7Sderaadt 		} else
609df930be7Sderaadt 			return STOP|FOUND;	/* won't fit, so give up */
610df930be7Sderaadt 	}
611df930be7Sderaadt 	return KEEPON;
612df930be7Sderaadt }
613df930be7Sderaadt 
CMDFUNCSTART(chname)614df930be7Sderaadt CMDFUNCSTART(chname)
615df930be7Sderaadt {
616df930be7Sderaadt 	int rval;
617df930be7Sderaadt 	char *cp;
618df930be7Sderaadt 	struct inodesc idesc;
619df930be7Sderaadt 
620df930be7Sderaadt 	slotcount = 0;
621df930be7Sderaadt 	if (!checkactivedir())
622df930be7Sderaadt 		return 1;
623df930be7Sderaadt 
624df930be7Sderaadt 	desired = strtoul(argv[1], &cp, 0);
625df930be7Sderaadt 	if (cp == argv[1] || *cp != '\0') {
626df930be7Sderaadt 		printf("invalid slot number `%s'\n", argv[1]);
627df930be7Sderaadt 		return 1;
628df930be7Sderaadt 	}
629df930be7Sderaadt 
630df930be7Sderaadt 	idesc.id_number = curinum;
631df930be7Sderaadt 	idesc.id_func = chnamefunc;
632df930be7Sderaadt 	idesc.id_fix = IGNORE;
633df930be7Sderaadt 	idesc.id_type = DATA;
634df930be7Sderaadt 	idesc.id_name = argv[2];
635df930be7Sderaadt 
636df930be7Sderaadt 	rval = ckinode(curinode, &idesc);
637df930be7Sderaadt 	if ((rval & (FOUND|ALTERED)) == (FOUND|ALTERED))
638df930be7Sderaadt 		return 0;
639df930be7Sderaadt 	else if (rval & FOUND) {
64046347781Smpech 		warnx("new name `%s' does not fit in slot %s", argv[2], argv[1]);
641df930be7Sderaadt 		return 1;
642df930be7Sderaadt 	} else {
643df930be7Sderaadt 		warnx("no %sth slot in current directory", argv[1]);
644df930be7Sderaadt 		return 1;
645df930be7Sderaadt 	}
646df930be7Sderaadt }
647df930be7Sderaadt 
64800829d25Smillert static struct typemap {
649df930be7Sderaadt 	const char *typename;
650df930be7Sderaadt 	int typebits;
651df930be7Sderaadt } typenamemap[]  = {
652df930be7Sderaadt 	{"file", IFREG},
653df930be7Sderaadt 	{"dir", IFDIR},
654df930be7Sderaadt 	{"socket", IFSOCK},
655df930be7Sderaadt 	{"fifo", IFIFO},
656df930be7Sderaadt };
657df930be7Sderaadt 
CMDFUNCSTART(newtype)658df930be7Sderaadt CMDFUNCSTART(newtype)
659df930be7Sderaadt {
660df930be7Sderaadt 	int type;
661df930be7Sderaadt 	struct typemap *tp;
662df930be7Sderaadt 
663df930be7Sderaadt 	if (!checkactive())
664df930be7Sderaadt 		return 1;
665c913562aSmillert 	type = DIP(curinode, di_mode) & IFMT;
666df930be7Sderaadt 	for (tp = typenamemap;
6673249b019Sotto 	    tp < &typenamemap[sizeof(typenamemap)/sizeof(*typenamemap)];
668df930be7Sderaadt 	    tp++) {
669df930be7Sderaadt 		if (!strcmp(argv[1], tp->typename)) {
670df930be7Sderaadt 			printf("setting type to %s\n", tp->typename);
671df930be7Sderaadt 			type = tp->typebits;
672df930be7Sderaadt 			break;
673df930be7Sderaadt 		}
674df930be7Sderaadt 	}
6753249b019Sotto 	if (tp == &typenamemap[sizeof(typenamemap)/sizeof(*typenamemap)]) {
676df930be7Sderaadt 		warnx("type `%s' not known", argv[1]);
677df930be7Sderaadt 		warnx("try one of `file', `dir', `socket', `fifo'");
678df930be7Sderaadt 		return 1;
679df930be7Sderaadt 	}
680c913562aSmillert 	DIP_SET(curinode, di_mode, DIP(curinode, di_mode) & ~IFMT);
681c913562aSmillert 	DIP_SET(curinode, di_mode, DIP(curinode, di_mode) | type);
682df930be7Sderaadt 	inodirty();
683df930be7Sderaadt 	printactive();
684df930be7Sderaadt 	return 0;
685df930be7Sderaadt }
686df930be7Sderaadt 
CMDFUNCSTART(chmode)687df930be7Sderaadt CMDFUNCSTART(chmode)
688df930be7Sderaadt {
689df930be7Sderaadt 	int rval = 1;
690df930be7Sderaadt 	long modebits;
691df930be7Sderaadt 	char *cp;
692df930be7Sderaadt 
693df930be7Sderaadt 	if (!checkactive())
694df930be7Sderaadt 		return 1;
695df930be7Sderaadt 
696df930be7Sderaadt 	modebits = strtol(argv[1], &cp, 8);
697df930be7Sderaadt 	if (cp == argv[1] || *cp != '\0' ) {
698df930be7Sderaadt 		warnx("bad modebits `%s'", argv[1]);
699df930be7Sderaadt 		return 1;
700df930be7Sderaadt 	}
701df930be7Sderaadt 
702c913562aSmillert 	DIP_SET(curinode, di_mode, DIP(curinode, di_mode) & ~07777);
703c913562aSmillert 	DIP_SET(curinode, di_mode, DIP(curinode, di_mode) | modebits);
704df930be7Sderaadt 	inodirty();
705df930be7Sderaadt 	printactive();
706df930be7Sderaadt 	return rval;
707df930be7Sderaadt }
708df930be7Sderaadt 
CMDFUNCSTART(chlen)70900829d25Smillert CMDFUNCSTART(chlen)
71000829d25Smillert {
71100829d25Smillert 	int rval = 1;
71200829d25Smillert 	long len;
71300829d25Smillert 	char *cp;
71400829d25Smillert 
71500829d25Smillert 	if (!checkactive())
71600829d25Smillert 		return 1;
71700829d25Smillert 
71800829d25Smillert 	len = strtol(argv[1], &cp, 0);
71900829d25Smillert 	if (cp == argv[1] || *cp != '\0' || len < 0) {
72000829d25Smillert 		warnx("bad length '%s'", argv[1]);
72100829d25Smillert 		return 1;
72200829d25Smillert 	}
72300829d25Smillert 
724c913562aSmillert 	DIP_SET(curinode, di_size, len);
72500829d25Smillert 	inodirty();
72600829d25Smillert 	printactive();
72700829d25Smillert 	return rval;
72800829d25Smillert }
72900829d25Smillert 
CMDFUNCSTART(chaflags)730df930be7Sderaadt CMDFUNCSTART(chaflags)
731df930be7Sderaadt {
732df930be7Sderaadt 	int rval = 1;
733df930be7Sderaadt 	u_long flags;
734df930be7Sderaadt 	char *cp;
735df930be7Sderaadt 
736df930be7Sderaadt 	if (!checkactive())
737df930be7Sderaadt 		return 1;
738df930be7Sderaadt 
739df930be7Sderaadt 	flags = strtoul(argv[1], &cp, 0);
740df930be7Sderaadt 	if (cp == argv[1] || *cp != '\0' ) {
741df930be7Sderaadt 		warnx("bad flags `%s'", argv[1]);
742df930be7Sderaadt 		return 1;
743df930be7Sderaadt 	}
744df930be7Sderaadt 
745df930be7Sderaadt 	if (flags > UINT_MAX) {
74646347781Smpech 		warnx("flags set beyond 32-bit range of field (%lx)", flags);
747df930be7Sderaadt 		return(1);
748df930be7Sderaadt 	}
749c913562aSmillert 	DIP_SET(curinode, di_flags, flags);
750df930be7Sderaadt 	inodirty();
751df930be7Sderaadt 	printactive();
752df930be7Sderaadt 	return rval;
753df930be7Sderaadt }
754df930be7Sderaadt 
CMDFUNCSTART(chgen)755df930be7Sderaadt CMDFUNCSTART(chgen)
756df930be7Sderaadt {
757df930be7Sderaadt 	int rval = 1;
758d06c4e1fSotto 	long long gen;
759df930be7Sderaadt 	char *cp;
760df930be7Sderaadt 
761df930be7Sderaadt 	if (!checkactive())
762df930be7Sderaadt 		return 1;
763df930be7Sderaadt 
764d06c4e1fSotto 	gen = strtoll(argv[1], &cp, 0);
765df930be7Sderaadt 	if (cp == argv[1] || *cp != '\0' ) {
766df930be7Sderaadt 		warnx("bad gen `%s'", argv[1]);
767df930be7Sderaadt 		return 1;
768df930be7Sderaadt 	}
769df930be7Sderaadt 
770d06c4e1fSotto 	if (gen > UINT_MAX || gen < 0) {
771d06c4e1fSotto 		warnx("gen set beyond 32-bit range of field (%llx)", gen);
772df930be7Sderaadt 		return(1);
773df930be7Sderaadt 	}
774c913562aSmillert 	DIP_SET(curinode, di_gen, gen);
775df930be7Sderaadt 	inodirty();
776df930be7Sderaadt 	printactive();
777df930be7Sderaadt 	return rval;
778df930be7Sderaadt }
779df930be7Sderaadt 
CMDFUNCSTART(linkcount)780df930be7Sderaadt CMDFUNCSTART(linkcount)
781df930be7Sderaadt {
782df930be7Sderaadt 	int rval = 1;
783df930be7Sderaadt 	int lcnt;
784df930be7Sderaadt 	char *cp;
785df930be7Sderaadt 
786df930be7Sderaadt 	if (!checkactive())
787df930be7Sderaadt 		return 1;
788df930be7Sderaadt 
789df930be7Sderaadt 	lcnt = strtol(argv[1], &cp, 0);
790df930be7Sderaadt 	if (cp == argv[1] || *cp != '\0' ) {
791df930be7Sderaadt 		warnx("bad link count `%s'", argv[1]);
792df930be7Sderaadt 		return 1;
793df930be7Sderaadt 	}
794df930be7Sderaadt 	if (lcnt > USHRT_MAX || lcnt < 0) {
79546347781Smpech 		warnx("max link count is %d", USHRT_MAX);
796df930be7Sderaadt 		return 1;
797df930be7Sderaadt 	}
798df930be7Sderaadt 
799c913562aSmillert 	DIP_SET(curinode, di_nlink, lcnt);
800df930be7Sderaadt 	inodirty();
801df930be7Sderaadt 	printactive();
802df930be7Sderaadt 	return rval;
803df930be7Sderaadt }
804df930be7Sderaadt 
CMDFUNCSTART(chowner)805df930be7Sderaadt CMDFUNCSTART(chowner)
806df930be7Sderaadt {
807df930be7Sderaadt 	int rval = 1;
8087212eb4eSderaadt 	uid_t uid;
809df930be7Sderaadt 	char *cp;
810df930be7Sderaadt 
811df930be7Sderaadt 	if (!checkactive())
812df930be7Sderaadt 		return 1;
813df930be7Sderaadt 
814df930be7Sderaadt 	uid = strtoul(argv[1], &cp, 0);
815df930be7Sderaadt 	if (cp == argv[1] || *cp != '\0' ) {
816df930be7Sderaadt 		/* try looking up name */
817a0f924b8Smillert 		if (uid_from_user(argv[1], &uid) == -1) {
818df930be7Sderaadt 			warnx("bad uid `%s'", argv[1]);
819df930be7Sderaadt 			return 1;
820df930be7Sderaadt 		}
821df930be7Sderaadt 	}
822df930be7Sderaadt 
823c913562aSmillert 	DIP_SET(curinode, di_uid, uid);
824df930be7Sderaadt 	inodirty();
825df930be7Sderaadt 	printactive();
826df930be7Sderaadt 	return rval;
827df930be7Sderaadt }
828df930be7Sderaadt 
CMDFUNCSTART(chgroup)829df930be7Sderaadt CMDFUNCSTART(chgroup)
830df930be7Sderaadt {
831df930be7Sderaadt 	int rval = 1;
8327212eb4eSderaadt 	gid_t gid;
833df930be7Sderaadt 	char *cp;
834df930be7Sderaadt 	struct group *grp;
835df930be7Sderaadt 
836df930be7Sderaadt 	if (!checkactive())
837df930be7Sderaadt 		return 1;
838df930be7Sderaadt 
839df930be7Sderaadt 	gid = strtoul(argv[1], &cp, 0);
840df930be7Sderaadt 	if (cp == argv[1] || *cp != '\0' ) {
84100829d25Smillert 		if ((grp = getgrnam(argv[1]))) {
842df930be7Sderaadt 			gid = grp->gr_gid;
843df930be7Sderaadt 		} else {
844df930be7Sderaadt 			warnx("bad gid `%s'", argv[1]);
845df930be7Sderaadt 			return 1;
846df930be7Sderaadt 		}
847df930be7Sderaadt 	}
848df930be7Sderaadt 
849c913562aSmillert 	DIP_SET(curinode, di_gid, gid);
850df930be7Sderaadt 	inodirty();
851df930be7Sderaadt 	printactive();
852df930be7Sderaadt 	return rval;
853df930be7Sderaadt }
854df930be7Sderaadt 
85500829d25Smillert static int
dotime(char * name,time_t * rsec,int32_t * rnsec)856904f6f58Sotto dotime(char *name, time_t *rsec, int32_t *rnsec)
857df930be7Sderaadt {
858df930be7Sderaadt 	char *p, *val;
859df930be7Sderaadt 	struct tm t;
860904f6f58Sotto 	time_t sec;
861df930be7Sderaadt 	int32_t nsec;
8628809fabbSderaadt 
863df930be7Sderaadt 	p = strchr(name, '.');
864df930be7Sderaadt 	if (p) {
865df930be7Sderaadt 		*p = '\0';
866df930be7Sderaadt 		nsec = strtoul(++p, &val, 0);
867df930be7Sderaadt 		if (val == p || *val != '\0' || nsec >= 1000000000 || nsec < 0) {
868df930be7Sderaadt 			warnx("invalid nanoseconds");
869df930be7Sderaadt 			goto badformat;
870df930be7Sderaadt 		}
871df930be7Sderaadt 	} else
872df930be7Sderaadt 		nsec = 0;
8738809fabbSderaadt 
874df930be7Sderaadt 	if (strlen(name) != 14) {
875df930be7Sderaadt badformat:
876df930be7Sderaadt 		warnx("date format: YYYYMMDDHHMMSS[.nsec]");
877df930be7Sderaadt 		return 1;
878df930be7Sderaadt 	}
879df930be7Sderaadt 
880df930be7Sderaadt 	for (p = name; *p; p++)
881df930be7Sderaadt 		if (*p < '0' || *p > '9')
882df930be7Sderaadt 			    goto badformat;
883df930be7Sderaadt 
884df930be7Sderaadt 	p = name;
885df930be7Sderaadt #define VAL() ((*p++) - '0')
88688d10243Sderaadt 	bzero(&t, sizeof t);
887df930be7Sderaadt 	t.tm_year = VAL();
888df930be7Sderaadt 	t.tm_year = VAL() + t.tm_year * 10;
889df930be7Sderaadt 	t.tm_year = VAL() + t.tm_year * 10;
890df930be7Sderaadt 	t.tm_year = VAL() + t.tm_year * 10 - 1900;
891df930be7Sderaadt 	t.tm_mon = VAL();
892df930be7Sderaadt 	t.tm_mon = VAL() + t.tm_mon * 10 - 1;
893df930be7Sderaadt 	t.tm_mday = VAL();
894df930be7Sderaadt 	t.tm_mday = VAL() + t.tm_mday * 10;
895df930be7Sderaadt 	t.tm_hour = VAL();
896df930be7Sderaadt 	t.tm_hour = VAL() + t.tm_hour * 10;
897df930be7Sderaadt 	t.tm_min = VAL();
898df930be7Sderaadt 	t.tm_min = VAL() + t.tm_min * 10;
899df930be7Sderaadt 	t.tm_sec = VAL();
900df930be7Sderaadt 	t.tm_sec = VAL() + t.tm_sec * 10;
901df930be7Sderaadt 	t.tm_isdst = -1;
902df930be7Sderaadt 
903df930be7Sderaadt 	sec = mktime(&t);
904df930be7Sderaadt 	if (sec == -1) {
905df930be7Sderaadt 		warnx("date/time out of range");
906df930be7Sderaadt 		return 1;
907df930be7Sderaadt 	}
908df930be7Sderaadt 	*rsec = sec;
909df930be7Sderaadt 	*rnsec = nsec;
910df930be7Sderaadt 	return 0;
911df930be7Sderaadt }
912df930be7Sderaadt 
CMDFUNCSTART(chmtime)913df930be7Sderaadt CMDFUNCSTART(chmtime)
914df930be7Sderaadt {
915904f6f58Sotto 	time_t rsec;
916904f6f58Sotto 	int32_t nsec;
917c913562aSmillert 
918c913562aSmillert 	if (dotime(argv[1], &rsec, &nsec))
919df930be7Sderaadt 		return 1;
920c913562aSmillert 	DIP_SET(curinode, di_mtime, rsec);
921c913562aSmillert 	DIP_SET(curinode, di_mtimensec, nsec);
922df930be7Sderaadt 	inodirty();
923df930be7Sderaadt 	printactive();
924df930be7Sderaadt 	return 0;
925df930be7Sderaadt }
926df930be7Sderaadt 
CMDFUNCSTART(chatime)927df930be7Sderaadt CMDFUNCSTART(chatime)
928df930be7Sderaadt {
929904f6f58Sotto 	time_t rsec;
930904f6f58Sotto 	int32_t nsec;
931c913562aSmillert 
932c913562aSmillert 	if (dotime(argv[1], &rsec, &nsec))
933df930be7Sderaadt 		return 1;
934c913562aSmillert 	DIP_SET(curinode, di_atime, rsec);
935c913562aSmillert 	DIP_SET(curinode, di_atimensec, nsec);
936df930be7Sderaadt 	inodirty();
937df930be7Sderaadt 	printactive();
938df930be7Sderaadt 	return 0;
939df930be7Sderaadt }
940df930be7Sderaadt 
CMDFUNCSTART(chctime)941df930be7Sderaadt CMDFUNCSTART(chctime)
942df930be7Sderaadt {
943904f6f58Sotto 	time_t rsec;
944904f6f58Sotto 	int32_t nsec;
945c913562aSmillert 
946c913562aSmillert 	if (dotime(argv[1], &rsec, &nsec))
947df930be7Sderaadt 		return 1;
948c913562aSmillert 	DIP_SET(curinode, di_ctime, rsec);
949c913562aSmillert 	DIP_SET(curinode, di_ctimensec, nsec);
950df930be7Sderaadt 	inodirty();
951df930be7Sderaadt 	printactive();
952df930be7Sderaadt 	return 0;
953df930be7Sderaadt }
954