Deleted Added
full compact
fsdb.c (122621) fsdb.c (136322)
1/* $NetBSD: fsdb.c,v 1.2 1995/10/08 23:18:10 thorpej Exp $ */
2
3/*
4 * Copyright (c) 1995 John T. Kohl
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#ifndef lint
32static const char rcsid[] =
1/* $NetBSD: fsdb.c,v 1.2 1995/10/08 23:18:10 thorpej Exp $ */
2
3/*
4 * Copyright (c) 1995 John T. Kohl
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#ifndef lint
32static const char rcsid[] =
33 "$FreeBSD: head/sbin/fsdb/fsdb.c 122621 2003-11-13 19:08:43Z johan $";
33 "$FreeBSD: head/sbin/fsdb/fsdb.c 136322 2004-10-09 15:56:34Z le $";
34#endif /* not lint */
35
36#include <sys/param.h>
37#include <sys/time.h>
38#include <ctype.h>
39#include <err.h>
40#include <grp.h>
41#include <histedit.h>
42#include <pwd.h>
43#include <string.h>
44#include <timeconv.h>
45
46#include <ufs/ufs/dinode.h>
47#include <ufs/ufs/dir.h>
48#include <ufs/ffs/fs.h>
49
50#include "fsdb.h"
51#include "fsck.h"
52
53static void usage(void) __dead2;
54int cmdloop(void);
55
56static void
57usage(void)
58{
59 fprintf(stderr, "usage: fsdb [-d] [-f] [-r] fsname\n");
60 exit(1);
61}
62
63int returntosingle;
64char nflag;
65
66/*
67 * We suck in lots of fsck code, and just pick & choose the stuff we want.
68 *
69 * fsreadfd is set up to read from the file system, fswritefd to write to
70 * the file system.
71 */
72int
73main(int argc, char *argv[])
74{
75 int ch, rval;
76 char *fsys = NULL;
77
78 while (-1 != (ch = getopt(argc, argv, "fdr"))) {
79 switch (ch) {
80 case 'f':
81 /* The -f option is left for historical
82 * reasons and has no meaning.
83 */
84 break;
85 case 'd':
86 debug++;
87 break;
88 case 'r':
89 nflag++; /* "no" in fsck, readonly for us */
90 break;
91 default:
92 usage();
93 }
94 }
95 argc -= optind;
96 argv += optind;
97 if (argc != 1)
98 usage();
99 else
100 fsys = argv[0];
101
102 sblock_init();
103 if (!setup(fsys))
104 errx(1, "cannot set up file system `%s'", fsys);
105 printf("%s file system `%s'\nLast Mounted on %s\n",
106 nflag? "Examining": "Editing", fsys, sblock.fs_fsmnt);
107 rval = cmdloop();
108 if (!nflag) {
109 sblock.fs_clean = 0; /* mark it dirty */
110 sbdirty();
111 ckfini(0);
112 printf("*** FILE SYSTEM MARKED DIRTY\n");
113 printf("*** BE SURE TO RUN FSCK TO CLEAN UP ANY DAMAGE\n");
114 printf("*** IF IT WAS MOUNTED, RE-MOUNT WITH -u -o reload\n");
115 }
116 exit(rval);
117}
118
119#define CMDFUNC(func) int func(int argc, char *argv[])
120#define CMDFUNCSTART(func) int func(int argc, char *argv[])
121
122CMDFUNC(helpfn);
123CMDFUNC(focus); /* focus on inode */
124CMDFUNC(active); /* print active inode */
125CMDFUNC(blocks); /* print blocks for active inode */
126CMDFUNC(focusname); /* focus by name */
127CMDFUNC(zapi); /* clear inode */
128CMDFUNC(uplink); /* incr link */
129CMDFUNC(downlink); /* decr link */
130CMDFUNC(linkcount); /* set link count */
131CMDFUNC(quit); /* quit */
132CMDFUNC(ls); /* list directory */
133CMDFUNC(rm); /* remove name */
134CMDFUNC(ln); /* add name */
135CMDFUNC(newtype); /* change type */
136CMDFUNC(chmode); /* change mode */
137CMDFUNC(chlen); /* change length */
138CMDFUNC(chaflags); /* change flags */
139CMDFUNC(chgen); /* change generation */
140CMDFUNC(chowner); /* change owner */
141CMDFUNC(chgroup); /* Change group */
142CMDFUNC(back); /* pop back to last ino */
143CMDFUNC(chmtime); /* Change mtime */
144CMDFUNC(chctime); /* Change ctime */
145CMDFUNC(chatime); /* Change atime */
146CMDFUNC(chinum); /* Change inode # of dirent */
147CMDFUNC(chname); /* Change dirname of dirent */
148
149struct cmdtable cmds[] = {
150 { "help", "Print out help", 1, 1, FL_RO, helpfn },
151 { "?", "Print out help", 1, 1, FL_RO, helpfn },
152 { "inode", "Set active inode to INUM", 2, 2, FL_RO, focus },
153 { "clri", "Clear inode INUM", 2, 2, FL_WR, zapi },
154 { "lookup", "Set active inode by looking up NAME", 2, 2, FL_RO, focusname },
155 { "cd", "Set active inode by looking up NAME", 2, 2, FL_RO, focusname },
156 { "back", "Go to previous active inode", 1, 1, FL_RO, back },
157 { "active", "Print active inode", 1, 1, FL_RO, active },
158 { "print", "Print active inode", 1, 1, FL_RO, active },
159 { "blocks", "Print block numbers of active inode", 1, 1, FL_RO, blocks },
160 { "uplink", "Increment link count", 1, 1, FL_WR, uplink },
161 { "downlink", "Decrement link count", 1, 1, FL_WR, downlink },
162 { "linkcount", "Set link count to COUNT", 2, 2, FL_WR, linkcount },
163 { "ls", "List current inode as directory", 1, 1, FL_RO, ls },
164 { "rm", "Remove NAME from current inode directory", 2, 2, FL_WR, rm },
165 { "del", "Remove NAME from current inode directory", 2, 2, FL_WR, rm },
166 { "ln", "Hardlink INO into current inode directory as NAME", 3, 3, FL_WR, ln },
167 { "chinum", "Change dir entry number INDEX to INUM", 3, 3, FL_WR, chinum },
168 { "chname", "Change dir entry number INDEX to NAME", 3, 3, FL_WR, chname },
169 { "chtype", "Change type of current inode to TYPE", 2, 2, FL_WR, newtype },
170 { "chmod", "Change mode of current inode to MODE", 2, 2, FL_WR, chmode },
171 { "chlen", "Change length of current inode to LENGTH", 2, 2, FL_WR, chlen },
172 { "chown", "Change owner of current inode to OWNER", 2, 2, FL_WR, chowner },
173 { "chgrp", "Change group of current inode to GROUP", 2, 2, FL_WR, chgroup },
174 { "chflags", "Change flags of current inode to FLAGS", 2, 2, FL_WR, chaflags },
175 { "chgen", "Change generation number of current inode to GEN", 2, 2, FL_WR, chgen },
176 { "mtime", "Change mtime of current inode to MTIME", 2, 2, FL_WR, chmtime },
177 { "ctime", "Change ctime of current inode to CTIME", 2, 2, FL_WR, chctime },
178 { "atime", "Change atime of current inode to ATIME", 2, 2, FL_WR, chatime },
179 { "quit", "Exit", 1, 1, FL_RO, quit },
180 { "q", "Exit", 1, 1, FL_RO, quit },
181 { "exit", "Exit", 1, 1, FL_RO, quit },
34#endif /* not lint */
35
36#include <sys/param.h>
37#include <sys/time.h>
38#include <ctype.h>
39#include <err.h>
40#include <grp.h>
41#include <histedit.h>
42#include <pwd.h>
43#include <string.h>
44#include <timeconv.h>
45
46#include <ufs/ufs/dinode.h>
47#include <ufs/ufs/dir.h>
48#include <ufs/ffs/fs.h>
49
50#include "fsdb.h"
51#include "fsck.h"
52
53static void usage(void) __dead2;
54int cmdloop(void);
55
56static void
57usage(void)
58{
59 fprintf(stderr, "usage: fsdb [-d] [-f] [-r] fsname\n");
60 exit(1);
61}
62
63int returntosingle;
64char nflag;
65
66/*
67 * We suck in lots of fsck code, and just pick & choose the stuff we want.
68 *
69 * fsreadfd is set up to read from the file system, fswritefd to write to
70 * the file system.
71 */
72int
73main(int argc, char *argv[])
74{
75 int ch, rval;
76 char *fsys = NULL;
77
78 while (-1 != (ch = getopt(argc, argv, "fdr"))) {
79 switch (ch) {
80 case 'f':
81 /* The -f option is left for historical
82 * reasons and has no meaning.
83 */
84 break;
85 case 'd':
86 debug++;
87 break;
88 case 'r':
89 nflag++; /* "no" in fsck, readonly for us */
90 break;
91 default:
92 usage();
93 }
94 }
95 argc -= optind;
96 argv += optind;
97 if (argc != 1)
98 usage();
99 else
100 fsys = argv[0];
101
102 sblock_init();
103 if (!setup(fsys))
104 errx(1, "cannot set up file system `%s'", fsys);
105 printf("%s file system `%s'\nLast Mounted on %s\n",
106 nflag? "Examining": "Editing", fsys, sblock.fs_fsmnt);
107 rval = cmdloop();
108 if (!nflag) {
109 sblock.fs_clean = 0; /* mark it dirty */
110 sbdirty();
111 ckfini(0);
112 printf("*** FILE SYSTEM MARKED DIRTY\n");
113 printf("*** BE SURE TO RUN FSCK TO CLEAN UP ANY DAMAGE\n");
114 printf("*** IF IT WAS MOUNTED, RE-MOUNT WITH -u -o reload\n");
115 }
116 exit(rval);
117}
118
119#define CMDFUNC(func) int func(int argc, char *argv[])
120#define CMDFUNCSTART(func) int func(int argc, char *argv[])
121
122CMDFUNC(helpfn);
123CMDFUNC(focus); /* focus on inode */
124CMDFUNC(active); /* print active inode */
125CMDFUNC(blocks); /* print blocks for active inode */
126CMDFUNC(focusname); /* focus by name */
127CMDFUNC(zapi); /* clear inode */
128CMDFUNC(uplink); /* incr link */
129CMDFUNC(downlink); /* decr link */
130CMDFUNC(linkcount); /* set link count */
131CMDFUNC(quit); /* quit */
132CMDFUNC(ls); /* list directory */
133CMDFUNC(rm); /* remove name */
134CMDFUNC(ln); /* add name */
135CMDFUNC(newtype); /* change type */
136CMDFUNC(chmode); /* change mode */
137CMDFUNC(chlen); /* change length */
138CMDFUNC(chaflags); /* change flags */
139CMDFUNC(chgen); /* change generation */
140CMDFUNC(chowner); /* change owner */
141CMDFUNC(chgroup); /* Change group */
142CMDFUNC(back); /* pop back to last ino */
143CMDFUNC(chmtime); /* Change mtime */
144CMDFUNC(chctime); /* Change ctime */
145CMDFUNC(chatime); /* Change atime */
146CMDFUNC(chinum); /* Change inode # of dirent */
147CMDFUNC(chname); /* Change dirname of dirent */
148
149struct cmdtable cmds[] = {
150 { "help", "Print out help", 1, 1, FL_RO, helpfn },
151 { "?", "Print out help", 1, 1, FL_RO, helpfn },
152 { "inode", "Set active inode to INUM", 2, 2, FL_RO, focus },
153 { "clri", "Clear inode INUM", 2, 2, FL_WR, zapi },
154 { "lookup", "Set active inode by looking up NAME", 2, 2, FL_RO, focusname },
155 { "cd", "Set active inode by looking up NAME", 2, 2, FL_RO, focusname },
156 { "back", "Go to previous active inode", 1, 1, FL_RO, back },
157 { "active", "Print active inode", 1, 1, FL_RO, active },
158 { "print", "Print active inode", 1, 1, FL_RO, active },
159 { "blocks", "Print block numbers of active inode", 1, 1, FL_RO, blocks },
160 { "uplink", "Increment link count", 1, 1, FL_WR, uplink },
161 { "downlink", "Decrement link count", 1, 1, FL_WR, downlink },
162 { "linkcount", "Set link count to COUNT", 2, 2, FL_WR, linkcount },
163 { "ls", "List current inode as directory", 1, 1, FL_RO, ls },
164 { "rm", "Remove NAME from current inode directory", 2, 2, FL_WR, rm },
165 { "del", "Remove NAME from current inode directory", 2, 2, FL_WR, rm },
166 { "ln", "Hardlink INO into current inode directory as NAME", 3, 3, FL_WR, ln },
167 { "chinum", "Change dir entry number INDEX to INUM", 3, 3, FL_WR, chinum },
168 { "chname", "Change dir entry number INDEX to NAME", 3, 3, FL_WR, chname },
169 { "chtype", "Change type of current inode to TYPE", 2, 2, FL_WR, newtype },
170 { "chmod", "Change mode of current inode to MODE", 2, 2, FL_WR, chmode },
171 { "chlen", "Change length of current inode to LENGTH", 2, 2, FL_WR, chlen },
172 { "chown", "Change owner of current inode to OWNER", 2, 2, FL_WR, chowner },
173 { "chgrp", "Change group of current inode to GROUP", 2, 2, FL_WR, chgroup },
174 { "chflags", "Change flags of current inode to FLAGS", 2, 2, FL_WR, chaflags },
175 { "chgen", "Change generation number of current inode to GEN", 2, 2, FL_WR, chgen },
176 { "mtime", "Change mtime of current inode to MTIME", 2, 2, FL_WR, chmtime },
177 { "ctime", "Change ctime of current inode to CTIME", 2, 2, FL_WR, chctime },
178 { "atime", "Change atime of current inode to ATIME", 2, 2, FL_WR, chatime },
179 { "quit", "Exit", 1, 1, FL_RO, quit },
180 { "q", "Exit", 1, 1, FL_RO, quit },
181 { "exit", "Exit", 1, 1, FL_RO, quit },
182 { NULL, 0, 0, 0 },
182 { NULL, 0, 0, 0, 0, NULL },
183};
184
185int
186helpfn(int argc, char *argv[])
187{
188 struct cmdtable *cmdtp;
189
190 printf("Commands are:\n%-10s %5s %5s %s\n",
191 "command", "min argc", "max argc", "what");
192
193 for (cmdtp = cmds; cmdtp->cmd; cmdtp++)
194 printf("%-10s %5u %5u %s\n",
195 cmdtp->cmd, cmdtp->minargc, cmdtp->maxargc, cmdtp->helptxt);
196 return 0;
197}
198
199char *
200prompt(EditLine *el)
201{
202 static char pstring[64];
203 snprintf(pstring, sizeof(pstring), "fsdb (inum: %d)> ", curinum);
204 return pstring;
205}
206
207
208int
209cmdloop(void)
210{
211 char *line;
212 const char *elline;
213 int cmd_argc, rval = 0, known;
214#define scratch known
215 char **cmd_argv;
216 struct cmdtable *cmdp;
217 History *hist;
218 EditLine *elptr;
219 HistEvent he;
220
221 curinode = ginode(ROOTINO);
222 curinum = ROOTINO;
223 printactive(0);
224
225 hist = history_init();
226 history(hist, &he, H_EVENT, 100); /* 100 elt history buffer */
227
228 elptr = el_init("fsdb", stdin, stdout, stderr);
229 el_set(elptr, EL_EDITOR, "emacs");
230 el_set(elptr, EL_PROMPT, prompt);
231 el_set(elptr, EL_HIST, history, hist);
232 el_source(elptr, NULL);
233
234 while ((elline = el_gets(elptr, &scratch)) != NULL && scratch != 0) {
235 if (debug)
236 printf("command `%s'\n", elline);
237
238 history(hist, &he, H_ENTER, elline);
239
240 line = strdup(elline);
241 cmd_argv = crack(line, &cmd_argc);
242 /*
243 * el_parse returns -1 to signal that it's not been handled
244 * internally.
245 */
246 if (el_parse(elptr, cmd_argc, cmd_argv) != -1)
247 continue;
248 if (cmd_argc) {
249 known = 0;
250 for (cmdp = cmds; cmdp->cmd; cmdp++) {
251 if (!strcmp(cmdp->cmd, cmd_argv[0])) {
252 if ((cmdp->flags & FL_WR) == FL_WR && nflag)
253 warnx("`%s' requires write access", cmd_argv[0]),
254 rval = 1;
255 else if (cmd_argc >= cmdp->minargc &&
256 cmd_argc <= cmdp->maxargc)
257 rval = (*cmdp->handler)(cmd_argc, cmd_argv);
258 else if (cmd_argc >= cmdp->minargc) {
259 strcpy(line, elline);
260 cmd_argv = recrack(line, &cmd_argc, cmdp->maxargc);
261 rval = (*cmdp->handler)(cmd_argc, cmd_argv);
262 } else
263 rval = argcount(cmdp, cmd_argc, cmd_argv);
264 known = 1;
265 break;
266 }
267 }
268 if (!known)
269 warnx("unknown command `%s'", cmd_argv[0]), rval = 1;
270 } else
271 rval = 0;
272 free(line);
273 if (rval < 0)
274 /* user typed "quit" */
275 return 0;
276 if (rval)
277 warnx("rval was %d", rval);
278 }
279 el_end(elptr);
280 history_end(hist);
281 return rval;
282}
283
284union dinode *curinode;
285ino_t curinum, ocurrent;
286
287#define GETINUM(ac,inum) inum = strtoul(argv[ac], &cp, 0); \
288 if (inum < ROOTINO || inum > maxino || cp == argv[ac] || *cp != '\0' ) { \
289 printf("inode %d out of range; range is [%d,%d]\n", \
290 inum, ROOTINO, maxino); \
291 return 1; \
292 }
293
294/*
295 * Focus on given inode number
296 */
297CMDFUNCSTART(focus)
298{
299 ino_t inum;
300 char *cp;
301
302 GETINUM(1,inum);
303 curinode = ginode(inum);
304 ocurrent = curinum;
305 curinum = inum;
306 printactive(0);
307 return 0;
308}
309
310CMDFUNCSTART(back)
311{
312 curinum = ocurrent;
313 curinode = ginode(curinum);
314 printactive(0);
315 return 0;
316}
317
318CMDFUNCSTART(zapi)
319{
320 ino_t inum;
321 union dinode *dp;
322 char *cp;
323
324 GETINUM(1,inum);
325 dp = ginode(inum);
326 clearinode(dp);
327 inodirty();
328 if (curinode) /* re-set after potential change */
329 curinode = ginode(curinum);
330 return 0;
331}
332
333CMDFUNCSTART(active)
334{
335 printactive(0);
336 return 0;
337}
338
339CMDFUNCSTART(blocks)
340{
341 printactive(1);
342 return 0;
343}
344
345CMDFUNCSTART(quit)
346{
347 return -1;
348}
349
350CMDFUNCSTART(uplink)
351{
352 if (!checkactive())
353 return 1;
183};
184
185int
186helpfn(int argc, char *argv[])
187{
188 struct cmdtable *cmdtp;
189
190 printf("Commands are:\n%-10s %5s %5s %s\n",
191 "command", "min argc", "max argc", "what");
192
193 for (cmdtp = cmds; cmdtp->cmd; cmdtp++)
194 printf("%-10s %5u %5u %s\n",
195 cmdtp->cmd, cmdtp->minargc, cmdtp->maxargc, cmdtp->helptxt);
196 return 0;
197}
198
199char *
200prompt(EditLine *el)
201{
202 static char pstring[64];
203 snprintf(pstring, sizeof(pstring), "fsdb (inum: %d)> ", curinum);
204 return pstring;
205}
206
207
208int
209cmdloop(void)
210{
211 char *line;
212 const char *elline;
213 int cmd_argc, rval = 0, known;
214#define scratch known
215 char **cmd_argv;
216 struct cmdtable *cmdp;
217 History *hist;
218 EditLine *elptr;
219 HistEvent he;
220
221 curinode = ginode(ROOTINO);
222 curinum = ROOTINO;
223 printactive(0);
224
225 hist = history_init();
226 history(hist, &he, H_EVENT, 100); /* 100 elt history buffer */
227
228 elptr = el_init("fsdb", stdin, stdout, stderr);
229 el_set(elptr, EL_EDITOR, "emacs");
230 el_set(elptr, EL_PROMPT, prompt);
231 el_set(elptr, EL_HIST, history, hist);
232 el_source(elptr, NULL);
233
234 while ((elline = el_gets(elptr, &scratch)) != NULL && scratch != 0) {
235 if (debug)
236 printf("command `%s'\n", elline);
237
238 history(hist, &he, H_ENTER, elline);
239
240 line = strdup(elline);
241 cmd_argv = crack(line, &cmd_argc);
242 /*
243 * el_parse returns -1 to signal that it's not been handled
244 * internally.
245 */
246 if (el_parse(elptr, cmd_argc, cmd_argv) != -1)
247 continue;
248 if (cmd_argc) {
249 known = 0;
250 for (cmdp = cmds; cmdp->cmd; cmdp++) {
251 if (!strcmp(cmdp->cmd, cmd_argv[0])) {
252 if ((cmdp->flags & FL_WR) == FL_WR && nflag)
253 warnx("`%s' requires write access", cmd_argv[0]),
254 rval = 1;
255 else if (cmd_argc >= cmdp->minargc &&
256 cmd_argc <= cmdp->maxargc)
257 rval = (*cmdp->handler)(cmd_argc, cmd_argv);
258 else if (cmd_argc >= cmdp->minargc) {
259 strcpy(line, elline);
260 cmd_argv = recrack(line, &cmd_argc, cmdp->maxargc);
261 rval = (*cmdp->handler)(cmd_argc, cmd_argv);
262 } else
263 rval = argcount(cmdp, cmd_argc, cmd_argv);
264 known = 1;
265 break;
266 }
267 }
268 if (!known)
269 warnx("unknown command `%s'", cmd_argv[0]), rval = 1;
270 } else
271 rval = 0;
272 free(line);
273 if (rval < 0)
274 /* user typed "quit" */
275 return 0;
276 if (rval)
277 warnx("rval was %d", rval);
278 }
279 el_end(elptr);
280 history_end(hist);
281 return rval;
282}
283
284union dinode *curinode;
285ino_t curinum, ocurrent;
286
287#define GETINUM(ac,inum) inum = strtoul(argv[ac], &cp, 0); \
288 if (inum < ROOTINO || inum > maxino || cp == argv[ac] || *cp != '\0' ) { \
289 printf("inode %d out of range; range is [%d,%d]\n", \
290 inum, ROOTINO, maxino); \
291 return 1; \
292 }
293
294/*
295 * Focus on given inode number
296 */
297CMDFUNCSTART(focus)
298{
299 ino_t inum;
300 char *cp;
301
302 GETINUM(1,inum);
303 curinode = ginode(inum);
304 ocurrent = curinum;
305 curinum = inum;
306 printactive(0);
307 return 0;
308}
309
310CMDFUNCSTART(back)
311{
312 curinum = ocurrent;
313 curinode = ginode(curinum);
314 printactive(0);
315 return 0;
316}
317
318CMDFUNCSTART(zapi)
319{
320 ino_t inum;
321 union dinode *dp;
322 char *cp;
323
324 GETINUM(1,inum);
325 dp = ginode(inum);
326 clearinode(dp);
327 inodirty();
328 if (curinode) /* re-set after potential change */
329 curinode = ginode(curinum);
330 return 0;
331}
332
333CMDFUNCSTART(active)
334{
335 printactive(0);
336 return 0;
337}
338
339CMDFUNCSTART(blocks)
340{
341 printactive(1);
342 return 0;
343}
344
345CMDFUNCSTART(quit)
346{
347 return -1;
348}
349
350CMDFUNCSTART(uplink)
351{
352 if (!checkactive())
353 return 1;
354 DIP(curinode, di_nlink) += 1;
354 DIP_SET(curinode, di_nlink, DIP(curinode, di_nlink) + 1);
355 printf("inode %d link count now %d\n", curinum, DIP(curinode, di_nlink));
356 inodirty();
357 return 0;
358}
359
360CMDFUNCSTART(downlink)
361{
362 if (!checkactive())
363 return 1;
355 printf("inode %d link count now %d\n", curinum, DIP(curinode, di_nlink));
356 inodirty();
357 return 0;
358}
359
360CMDFUNCSTART(downlink)
361{
362 if (!checkactive())
363 return 1;
364 DIP(curinode, di_nlink) -= 1;
364 DIP_SET(curinode, di_nlink, DIP(curinode, di_nlink) - 1);
365 printf("inode %d link count now %d\n", curinum, DIP(curinode, di_nlink));
366 inodirty();
367 return 0;
368}
369
370const char *typename[] = {
371 "unknown",
372 "fifo",
373 "char special",
374 "unregistered #3",
375 "directory",
376 "unregistered #5",
377 "blk special",
378 "unregistered #7",
379 "regular",
380 "unregistered #9",
381 "symlink",
382 "unregistered #11",
383 "socket",
384 "unregistered #13",
385 "whiteout",
386};
387
388int slot;
389
390int
391scannames(struct inodesc *idesc)
392{
393 struct direct *dirp = idesc->id_dirp;
394
395 printf("slot %d ino %d reclen %d: %s, `%.*s'\n",
396 slot++, dirp->d_ino, dirp->d_reclen, typename[dirp->d_type],
397 dirp->d_namlen, dirp->d_name);
398 return (KEEPON);
399}
400
401CMDFUNCSTART(ls)
402{
403 struct inodesc idesc;
404 checkactivedir(); /* let it go on anyway */
405
406 slot = 0;
407 idesc.id_number = curinum;
408 idesc.id_func = scannames;
409 idesc.id_type = DATA;
410 idesc.id_fix = IGNORE;
411 ckinode(curinode, &idesc);
412 curinode = ginode(curinum);
413
414 return 0;
415}
416
417int findino(struct inodesc *idesc); /* from fsck */
418static int dolookup(char *name);
419
420static int
421dolookup(char *name)
422{
423 struct inodesc idesc;
424
425 if (!checkactivedir())
426 return 0;
427 idesc.id_number = curinum;
428 idesc.id_func = findino;
429 idesc.id_name = name;
430 idesc.id_type = DATA;
431 idesc.id_fix = IGNORE;
432 if (ckinode(curinode, &idesc) & FOUND) {
433 curinum = idesc.id_parent;
434 curinode = ginode(curinum);
435 printactive(0);
436 return 1;
437 } else {
438 warnx("name `%s' not found in current inode directory", name);
439 return 0;
440 }
441}
442
443CMDFUNCSTART(focusname)
444{
445 char *p, *val;
446
447 if (!checkactive())
448 return 1;
449
450 ocurrent = curinum;
451
452 if (argv[1][0] == '/') {
453 curinum = ROOTINO;
454 curinode = ginode(ROOTINO);
455 } else {
456 if (!checkactivedir())
457 return 1;
458 }
459 for (p = argv[1]; p != NULL;) {
460 while ((val = strsep(&p, "/")) != NULL && *val == '\0');
461 if (val) {
462 printf("component `%s': ", val);
463 fflush(stdout);
464 if (!dolookup(val)) {
465 curinode = ginode(curinum);
466 return(1);
467 }
468 }
469 }
470 return 0;
471}
472
473CMDFUNCSTART(ln)
474{
475 ino_t inum;
476 int rval;
477 char *cp;
478
479 GETINUM(1,inum);
480
481 if (!checkactivedir())
482 return 1;
483 rval = makeentry(curinum, inum, argv[2]);
484 if (rval)
485 printf("Ino %d entered as `%s'\n", inum, argv[2]);
486 else
487 printf("could not enter name? weird.\n");
488 curinode = ginode(curinum);
489 return rval;
490}
491
492CMDFUNCSTART(rm)
493{
494 int rval;
495
496 if (!checkactivedir())
497 return 1;
498 rval = changeino(curinum, argv[1], 0);
499 if (rval & ALTERED) {
500 printf("Name `%s' removed\n", argv[1]);
501 return 0;
502 } else {
503 printf("could not remove name ('%s')? weird.\n", argv[1]);
504 return 1;
505 }
506}
507
508long slotcount, desired;
509
510int
511chinumfunc(struct inodesc *idesc)
512{
513 struct direct *dirp = idesc->id_dirp;
514
515 if (slotcount++ == desired) {
516 dirp->d_ino = idesc->id_parent;
517 return STOP|ALTERED|FOUND;
518 }
519 return KEEPON;
520}
521
522CMDFUNCSTART(chinum)
523{
524 char *cp;
525 ino_t inum;
526 struct inodesc idesc;
527
528 slotcount = 0;
529 if (!checkactivedir())
530 return 1;
531 GETINUM(2,inum);
532
533 desired = strtol(argv[1], &cp, 0);
534 if (cp == argv[1] || *cp != '\0' || desired < 0) {
535 printf("invalid slot number `%s'\n", argv[1]);
536 return 1;
537 }
538
539 idesc.id_number = curinum;
540 idesc.id_func = chinumfunc;
541 idesc.id_fix = IGNORE;
542 idesc.id_type = DATA;
543 idesc.id_parent = inum; /* XXX convenient hiding place */
544
545 if (ckinode(curinode, &idesc) & FOUND)
546 return 0;
547 else {
548 warnx("no %sth slot in current directory", argv[1]);
549 return 1;
550 }
551}
552
553int
554chnamefunc(struct inodesc *idesc)
555{
556 struct direct *dirp = idesc->id_dirp;
557 struct direct testdir;
558
559 if (slotcount++ == desired) {
560 /* will name fit? */
561 testdir.d_namlen = strlen(idesc->id_name);
562 if (DIRSIZ(NEWDIRFMT, &testdir) <= dirp->d_reclen) {
563 dirp->d_namlen = testdir.d_namlen;
564 strcpy(dirp->d_name, idesc->id_name);
565 return STOP|ALTERED|FOUND;
566 } else
567 return STOP|FOUND; /* won't fit, so give up */
568 }
569 return KEEPON;
570}
571
572CMDFUNCSTART(chname)
573{
574 int rval;
575 char *cp;
576 struct inodesc idesc;
577
578 slotcount = 0;
579 if (!checkactivedir())
580 return 1;
581
582 desired = strtoul(argv[1], &cp, 0);
583 if (cp == argv[1] || *cp != '\0') {
584 printf("invalid slot number `%s'\n", argv[1]);
585 return 1;
586 }
587
588 idesc.id_number = curinum;
589 idesc.id_func = chnamefunc;
590 idesc.id_fix = IGNORE;
591 idesc.id_type = DATA;
592 idesc.id_name = argv[2];
593
594 rval = ckinode(curinode, &idesc);
595 if ((rval & (FOUND|ALTERED)) == (FOUND|ALTERED))
596 return 0;
597 else if (rval & FOUND) {
598 warnx("new name `%s' does not fit in slot %s\n", argv[2], argv[1]);
599 return 1;
600 } else {
601 warnx("no %sth slot in current directory", argv[1]);
602 return 1;
603 }
604}
605
606struct typemap {
607 const char *typename;
608 int typebits;
609} typenamemap[] = {
610 {"file", IFREG},
611 {"dir", IFDIR},
612 {"socket", IFSOCK},
613 {"fifo", IFIFO},
614};
615
616CMDFUNCSTART(newtype)
617{
618 int type;
619 struct typemap *tp;
620
621 if (!checkactive())
622 return 1;
623 type = DIP(curinode, di_mode) & IFMT;
624 for (tp = typenamemap;
625 tp < &typenamemap[sizeof(typenamemap)/sizeof(*typenamemap)];
626 tp++) {
627 if (!strcmp(argv[1], tp->typename)) {
628 printf("setting type to %s\n", tp->typename);
629 type = tp->typebits;
630 break;
631 }
632 }
633 if (tp == &typenamemap[sizeof(typenamemap)/sizeof(*typenamemap)]) {
634 warnx("type `%s' not known", argv[1]);
635 warnx("try one of `file', `dir', `socket', `fifo'");
636 return 1;
637 }
365 printf("inode %d link count now %d\n", curinum, DIP(curinode, di_nlink));
366 inodirty();
367 return 0;
368}
369
370const char *typename[] = {
371 "unknown",
372 "fifo",
373 "char special",
374 "unregistered #3",
375 "directory",
376 "unregistered #5",
377 "blk special",
378 "unregistered #7",
379 "regular",
380 "unregistered #9",
381 "symlink",
382 "unregistered #11",
383 "socket",
384 "unregistered #13",
385 "whiteout",
386};
387
388int slot;
389
390int
391scannames(struct inodesc *idesc)
392{
393 struct direct *dirp = idesc->id_dirp;
394
395 printf("slot %d ino %d reclen %d: %s, `%.*s'\n",
396 slot++, dirp->d_ino, dirp->d_reclen, typename[dirp->d_type],
397 dirp->d_namlen, dirp->d_name);
398 return (KEEPON);
399}
400
401CMDFUNCSTART(ls)
402{
403 struct inodesc idesc;
404 checkactivedir(); /* let it go on anyway */
405
406 slot = 0;
407 idesc.id_number = curinum;
408 idesc.id_func = scannames;
409 idesc.id_type = DATA;
410 idesc.id_fix = IGNORE;
411 ckinode(curinode, &idesc);
412 curinode = ginode(curinum);
413
414 return 0;
415}
416
417int findino(struct inodesc *idesc); /* from fsck */
418static int dolookup(char *name);
419
420static int
421dolookup(char *name)
422{
423 struct inodesc idesc;
424
425 if (!checkactivedir())
426 return 0;
427 idesc.id_number = curinum;
428 idesc.id_func = findino;
429 idesc.id_name = name;
430 idesc.id_type = DATA;
431 idesc.id_fix = IGNORE;
432 if (ckinode(curinode, &idesc) & FOUND) {
433 curinum = idesc.id_parent;
434 curinode = ginode(curinum);
435 printactive(0);
436 return 1;
437 } else {
438 warnx("name `%s' not found in current inode directory", name);
439 return 0;
440 }
441}
442
443CMDFUNCSTART(focusname)
444{
445 char *p, *val;
446
447 if (!checkactive())
448 return 1;
449
450 ocurrent = curinum;
451
452 if (argv[1][0] == '/') {
453 curinum = ROOTINO;
454 curinode = ginode(ROOTINO);
455 } else {
456 if (!checkactivedir())
457 return 1;
458 }
459 for (p = argv[1]; p != NULL;) {
460 while ((val = strsep(&p, "/")) != NULL && *val == '\0');
461 if (val) {
462 printf("component `%s': ", val);
463 fflush(stdout);
464 if (!dolookup(val)) {
465 curinode = ginode(curinum);
466 return(1);
467 }
468 }
469 }
470 return 0;
471}
472
473CMDFUNCSTART(ln)
474{
475 ino_t inum;
476 int rval;
477 char *cp;
478
479 GETINUM(1,inum);
480
481 if (!checkactivedir())
482 return 1;
483 rval = makeentry(curinum, inum, argv[2]);
484 if (rval)
485 printf("Ino %d entered as `%s'\n", inum, argv[2]);
486 else
487 printf("could not enter name? weird.\n");
488 curinode = ginode(curinum);
489 return rval;
490}
491
492CMDFUNCSTART(rm)
493{
494 int rval;
495
496 if (!checkactivedir())
497 return 1;
498 rval = changeino(curinum, argv[1], 0);
499 if (rval & ALTERED) {
500 printf("Name `%s' removed\n", argv[1]);
501 return 0;
502 } else {
503 printf("could not remove name ('%s')? weird.\n", argv[1]);
504 return 1;
505 }
506}
507
508long slotcount, desired;
509
510int
511chinumfunc(struct inodesc *idesc)
512{
513 struct direct *dirp = idesc->id_dirp;
514
515 if (slotcount++ == desired) {
516 dirp->d_ino = idesc->id_parent;
517 return STOP|ALTERED|FOUND;
518 }
519 return KEEPON;
520}
521
522CMDFUNCSTART(chinum)
523{
524 char *cp;
525 ino_t inum;
526 struct inodesc idesc;
527
528 slotcount = 0;
529 if (!checkactivedir())
530 return 1;
531 GETINUM(2,inum);
532
533 desired = strtol(argv[1], &cp, 0);
534 if (cp == argv[1] || *cp != '\0' || desired < 0) {
535 printf("invalid slot number `%s'\n", argv[1]);
536 return 1;
537 }
538
539 idesc.id_number = curinum;
540 idesc.id_func = chinumfunc;
541 idesc.id_fix = IGNORE;
542 idesc.id_type = DATA;
543 idesc.id_parent = inum; /* XXX convenient hiding place */
544
545 if (ckinode(curinode, &idesc) & FOUND)
546 return 0;
547 else {
548 warnx("no %sth slot in current directory", argv[1]);
549 return 1;
550 }
551}
552
553int
554chnamefunc(struct inodesc *idesc)
555{
556 struct direct *dirp = idesc->id_dirp;
557 struct direct testdir;
558
559 if (slotcount++ == desired) {
560 /* will name fit? */
561 testdir.d_namlen = strlen(idesc->id_name);
562 if (DIRSIZ(NEWDIRFMT, &testdir) <= dirp->d_reclen) {
563 dirp->d_namlen = testdir.d_namlen;
564 strcpy(dirp->d_name, idesc->id_name);
565 return STOP|ALTERED|FOUND;
566 } else
567 return STOP|FOUND; /* won't fit, so give up */
568 }
569 return KEEPON;
570}
571
572CMDFUNCSTART(chname)
573{
574 int rval;
575 char *cp;
576 struct inodesc idesc;
577
578 slotcount = 0;
579 if (!checkactivedir())
580 return 1;
581
582 desired = strtoul(argv[1], &cp, 0);
583 if (cp == argv[1] || *cp != '\0') {
584 printf("invalid slot number `%s'\n", argv[1]);
585 return 1;
586 }
587
588 idesc.id_number = curinum;
589 idesc.id_func = chnamefunc;
590 idesc.id_fix = IGNORE;
591 idesc.id_type = DATA;
592 idesc.id_name = argv[2];
593
594 rval = ckinode(curinode, &idesc);
595 if ((rval & (FOUND|ALTERED)) == (FOUND|ALTERED))
596 return 0;
597 else if (rval & FOUND) {
598 warnx("new name `%s' does not fit in slot %s\n", argv[2], argv[1]);
599 return 1;
600 } else {
601 warnx("no %sth slot in current directory", argv[1]);
602 return 1;
603 }
604}
605
606struct typemap {
607 const char *typename;
608 int typebits;
609} typenamemap[] = {
610 {"file", IFREG},
611 {"dir", IFDIR},
612 {"socket", IFSOCK},
613 {"fifo", IFIFO},
614};
615
616CMDFUNCSTART(newtype)
617{
618 int type;
619 struct typemap *tp;
620
621 if (!checkactive())
622 return 1;
623 type = DIP(curinode, di_mode) & IFMT;
624 for (tp = typenamemap;
625 tp < &typenamemap[sizeof(typenamemap)/sizeof(*typenamemap)];
626 tp++) {
627 if (!strcmp(argv[1], tp->typename)) {
628 printf("setting type to %s\n", tp->typename);
629 type = tp->typebits;
630 break;
631 }
632 }
633 if (tp == &typenamemap[sizeof(typenamemap)/sizeof(*typenamemap)]) {
634 warnx("type `%s' not known", argv[1]);
635 warnx("try one of `file', `dir', `socket', `fifo'");
636 return 1;
637 }
638 DIP(curinode, di_mode) &= ~IFMT;
639 DIP(curinode, di_mode) |= type;
638 DIP_SET(curinode, di_mode, DIP(curinode, di_mode) & ~IFMT);
639 DIP_SET(curinode, di_mode, DIP(curinode, di_mode) | type);
640 inodirty();
641 printactive(0);
642 return 0;
643}
644
645CMDFUNCSTART(chlen)
646{
647 int rval = 1;
648 long len;
649 char *cp;
650
651 if (!checkactive())
652 return 1;
653
654 len = strtol(argv[1], &cp, 0);
655 if (cp == argv[1] || *cp != '\0' || len < 0) {
656 warnx("bad length `%s'", argv[1]);
657 return 1;
658 }
659
640 inodirty();
641 printactive(0);
642 return 0;
643}
644
645CMDFUNCSTART(chlen)
646{
647 int rval = 1;
648 long len;
649 char *cp;
650
651 if (!checkactive())
652 return 1;
653
654 len = strtol(argv[1], &cp, 0);
655 if (cp == argv[1] || *cp != '\0' || len < 0) {
656 warnx("bad length `%s'", argv[1]);
657 return 1;
658 }
659
660 DIP(curinode, di_size) = len;
660 DIP_SET(curinode, di_size, len);
661 inodirty();
662 printactive(0);
663 return rval;
664}
665
666CMDFUNCSTART(chmode)
667{
668 int rval = 1;
669 long modebits;
670 char *cp;
671
672 if (!checkactive())
673 return 1;
674
675 modebits = strtol(argv[1], &cp, 8);
676 if (cp == argv[1] || *cp != '\0' || (modebits & ~07777)) {
677 warnx("bad modebits `%s'", argv[1]);
678 return 1;
679 }
680
661 inodirty();
662 printactive(0);
663 return rval;
664}
665
666CMDFUNCSTART(chmode)
667{
668 int rval = 1;
669 long modebits;
670 char *cp;
671
672 if (!checkactive())
673 return 1;
674
675 modebits = strtol(argv[1], &cp, 8);
676 if (cp == argv[1] || *cp != '\0' || (modebits & ~07777)) {
677 warnx("bad modebits `%s'", argv[1]);
678 return 1;
679 }
680
681 DIP(curinode, di_mode) &= ~07777;
682 DIP(curinode, di_mode) |= modebits;
681 DIP_SET(curinode, di_mode, DIP(curinode, di_mode) & ~07777);
682 DIP_SET(curinode, di_mode, DIP(curinode, di_mode) | modebits);
683 inodirty();
684 printactive(0);
685 return rval;
686}
687
688CMDFUNCSTART(chaflags)
689{
690 int rval = 1;
691 u_long flags;
692 char *cp;
693
694 if (!checkactive())
695 return 1;
696
697 flags = strtoul(argv[1], &cp, 0);
698 if (cp == argv[1] || *cp != '\0' ) {
699 warnx("bad flags `%s'", argv[1]);
700 return 1;
701 }
702
703 if (flags > UINT_MAX) {
704 warnx("flags set beyond 32-bit range of field (%lx)\n", flags);
705 return(1);
706 }
683 inodirty();
684 printactive(0);
685 return rval;
686}
687
688CMDFUNCSTART(chaflags)
689{
690 int rval = 1;
691 u_long flags;
692 char *cp;
693
694 if (!checkactive())
695 return 1;
696
697 flags = strtoul(argv[1], &cp, 0);
698 if (cp == argv[1] || *cp != '\0' ) {
699 warnx("bad flags `%s'", argv[1]);
700 return 1;
701 }
702
703 if (flags > UINT_MAX) {
704 warnx("flags set beyond 32-bit range of field (%lx)\n", flags);
705 return(1);
706 }
707 DIP(curinode, di_flags) = flags;
707 DIP_SET(curinode, di_flags, flags);
708 inodirty();
709 printactive(0);
710 return rval;
711}
712
713CMDFUNCSTART(chgen)
714{
715 int rval = 1;
716 long gen;
717 char *cp;
718
719 if (!checkactive())
720 return 1;
721
722 gen = strtol(argv[1], &cp, 0);
723 if (cp == argv[1] || *cp != '\0' ) {
724 warnx("bad gen `%s'", argv[1]);
725 return 1;
726 }
727
728 if (gen > INT_MAX || gen < INT_MIN) {
729 warnx("gen set beyond 32-bit range of field (%lx)\n", gen);
730 return(1);
731 }
708 inodirty();
709 printactive(0);
710 return rval;
711}
712
713CMDFUNCSTART(chgen)
714{
715 int rval = 1;
716 long gen;
717 char *cp;
718
719 if (!checkactive())
720 return 1;
721
722 gen = strtol(argv[1], &cp, 0);
723 if (cp == argv[1] || *cp != '\0' ) {
724 warnx("bad gen `%s'", argv[1]);
725 return 1;
726 }
727
728 if (gen > INT_MAX || gen < INT_MIN) {
729 warnx("gen set beyond 32-bit range of field (%lx)\n", gen);
730 return(1);
731 }
732 DIP(curinode, di_gen) = gen;
732 DIP_SET(curinode, di_gen, gen);
733 inodirty();
734 printactive(0);
735 return rval;
736}
737
738CMDFUNCSTART(linkcount)
739{
740 int rval = 1;
741 int lcnt;
742 char *cp;
743
744 if (!checkactive())
745 return 1;
746
747 lcnt = strtol(argv[1], &cp, 0);
748 if (cp == argv[1] || *cp != '\0' ) {
749 warnx("bad link count `%s'", argv[1]);
750 return 1;
751 }
752 if (lcnt > USHRT_MAX || lcnt < 0) {
753 warnx("max link count is %d\n", USHRT_MAX);
754 return 1;
755 }
756
733 inodirty();
734 printactive(0);
735 return rval;
736}
737
738CMDFUNCSTART(linkcount)
739{
740 int rval = 1;
741 int lcnt;
742 char *cp;
743
744 if (!checkactive())
745 return 1;
746
747 lcnt = strtol(argv[1], &cp, 0);
748 if (cp == argv[1] || *cp != '\0' ) {
749 warnx("bad link count `%s'", argv[1]);
750 return 1;
751 }
752 if (lcnt > USHRT_MAX || lcnt < 0) {
753 warnx("max link count is %d\n", USHRT_MAX);
754 return 1;
755 }
756
757 DIP(curinode, di_nlink) = lcnt;
757 DIP_SET(curinode, di_nlink, lcnt);
758 inodirty();
759 printactive(0);
760 return rval;
761}
762
763CMDFUNCSTART(chowner)
764{
765 int rval = 1;
766 unsigned long uid;
767 char *cp;
768 struct passwd *pwd;
769
770 if (!checkactive())
771 return 1;
772
773 uid = strtoul(argv[1], &cp, 0);
774 if (cp == argv[1] || *cp != '\0' ) {
775 /* try looking up name */
776 if ((pwd = getpwnam(argv[1]))) {
777 uid = pwd->pw_uid;
778 } else {
779 warnx("bad uid `%s'", argv[1]);
780 return 1;
781 }
782 }
783
758 inodirty();
759 printactive(0);
760 return rval;
761}
762
763CMDFUNCSTART(chowner)
764{
765 int rval = 1;
766 unsigned long uid;
767 char *cp;
768 struct passwd *pwd;
769
770 if (!checkactive())
771 return 1;
772
773 uid = strtoul(argv[1], &cp, 0);
774 if (cp == argv[1] || *cp != '\0' ) {
775 /* try looking up name */
776 if ((pwd = getpwnam(argv[1]))) {
777 uid = pwd->pw_uid;
778 } else {
779 warnx("bad uid `%s'", argv[1]);
780 return 1;
781 }
782 }
783
784 DIP(curinode, di_uid) = uid;
784 DIP_SET(curinode, di_uid, uid);
785 inodirty();
786 printactive(0);
787 return rval;
788}
789
790CMDFUNCSTART(chgroup)
791{
792 int rval = 1;
793 unsigned long gid;
794 char *cp;
795 struct group *grp;
796
797 if (!checkactive())
798 return 1;
799
800 gid = strtoul(argv[1], &cp, 0);
801 if (cp == argv[1] || *cp != '\0' ) {
802 if ((grp = getgrnam(argv[1]))) {
803 gid = grp->gr_gid;
804 } else {
805 warnx("bad gid `%s'", argv[1]);
806 return 1;
807 }
808 }
809
785 inodirty();
786 printactive(0);
787 return rval;
788}
789
790CMDFUNCSTART(chgroup)
791{
792 int rval = 1;
793 unsigned long gid;
794 char *cp;
795 struct group *grp;
796
797 if (!checkactive())
798 return 1;
799
800 gid = strtoul(argv[1], &cp, 0);
801 if (cp == argv[1] || *cp != '\0' ) {
802 if ((grp = getgrnam(argv[1]))) {
803 gid = grp->gr_gid;
804 } else {
805 warnx("bad gid `%s'", argv[1]);
806 return 1;
807 }
808 }
809
810 DIP(curinode, di_gid) = gid;
810 DIP_SET(curinode, di_gid, gid);
811 inodirty();
812 printactive(0);
813 return rval;
814}
815
816int
817dotime(char *name, time_t *secp, int32_t *nsecp)
818{
819 char *p, *val;
820 struct tm t;
821 int32_t nsec;
822 p = strchr(name, '.');
823 if (p) {
824 *p = '\0';
825 nsec = strtoul(++p, &val, 0);
826 if (val == p || *val != '\0' || nsec >= 1000000000 || nsec < 0) {
827 warnx("invalid nanoseconds");
828 goto badformat;
829 }
830 } else
831 nsec = 0;
832 if (strlen(name) != 14) {
833badformat:
834 warnx("date format: YYYYMMDDHHMMSS[.nsec]");
835 return 1;
836 }
837 *nsecp = nsec;
838
839 for (p = name; *p; p++)
840 if (*p < '0' || *p > '9')
841 goto badformat;
842
843 p = name;
844#define VAL() ((*p++) - '0')
845 t.tm_year = VAL();
846 t.tm_year = VAL() + t.tm_year * 10;
847 t.tm_year = VAL() + t.tm_year * 10;
848 t.tm_year = VAL() + t.tm_year * 10 - 1900;
849 t.tm_mon = VAL();
850 t.tm_mon = VAL() + t.tm_mon * 10 - 1;
851 t.tm_mday = VAL();
852 t.tm_mday = VAL() + t.tm_mday * 10;
853 t.tm_hour = VAL();
854 t.tm_hour = VAL() + t.tm_hour * 10;
855 t.tm_min = VAL();
856 t.tm_min = VAL() + t.tm_min * 10;
857 t.tm_sec = VAL();
858 t.tm_sec = VAL() + t.tm_sec * 10;
859 t.tm_isdst = -1;
860
861 *secp = mktime(&t);
862 if (*secp == -1) {
863 warnx("date/time out of range");
864 return 1;
865 }
866 return 0;
867}
868
869CMDFUNCSTART(chmtime)
870{
871 time_t secs;
872 int32_t nsecs;
873
874 if (dotime(argv[1], &secs, &nsecs))
875 return 1;
876 if (sblock.fs_magic == FS_UFS1_MAGIC)
877 curinode->dp1.di_mtime = _time_to_time32(secs);
878 else
879 curinode->dp2.di_mtime = _time_to_time64(secs);
811 inodirty();
812 printactive(0);
813 return rval;
814}
815
816int
817dotime(char *name, time_t *secp, int32_t *nsecp)
818{
819 char *p, *val;
820 struct tm t;
821 int32_t nsec;
822 p = strchr(name, '.');
823 if (p) {
824 *p = '\0';
825 nsec = strtoul(++p, &val, 0);
826 if (val == p || *val != '\0' || nsec >= 1000000000 || nsec < 0) {
827 warnx("invalid nanoseconds");
828 goto badformat;
829 }
830 } else
831 nsec = 0;
832 if (strlen(name) != 14) {
833badformat:
834 warnx("date format: YYYYMMDDHHMMSS[.nsec]");
835 return 1;
836 }
837 *nsecp = nsec;
838
839 for (p = name; *p; p++)
840 if (*p < '0' || *p > '9')
841 goto badformat;
842
843 p = name;
844#define VAL() ((*p++) - '0')
845 t.tm_year = VAL();
846 t.tm_year = VAL() + t.tm_year * 10;
847 t.tm_year = VAL() + t.tm_year * 10;
848 t.tm_year = VAL() + t.tm_year * 10 - 1900;
849 t.tm_mon = VAL();
850 t.tm_mon = VAL() + t.tm_mon * 10 - 1;
851 t.tm_mday = VAL();
852 t.tm_mday = VAL() + t.tm_mday * 10;
853 t.tm_hour = VAL();
854 t.tm_hour = VAL() + t.tm_hour * 10;
855 t.tm_min = VAL();
856 t.tm_min = VAL() + t.tm_min * 10;
857 t.tm_sec = VAL();
858 t.tm_sec = VAL() + t.tm_sec * 10;
859 t.tm_isdst = -1;
860
861 *secp = mktime(&t);
862 if (*secp == -1) {
863 warnx("date/time out of range");
864 return 1;
865 }
866 return 0;
867}
868
869CMDFUNCSTART(chmtime)
870{
871 time_t secs;
872 int32_t nsecs;
873
874 if (dotime(argv[1], &secs, &nsecs))
875 return 1;
876 if (sblock.fs_magic == FS_UFS1_MAGIC)
877 curinode->dp1.di_mtime = _time_to_time32(secs);
878 else
879 curinode->dp2.di_mtime = _time_to_time64(secs);
880 DIP(curinode, di_mtimensec) = nsecs;
880 DIP_SET(curinode, di_mtimensec, nsecs);
881 inodirty();
882 printactive(0);
883 return 0;
884}
885
886CMDFUNCSTART(chatime)
887{
888 time_t secs;
889 int32_t nsecs;
890
891 if (dotime(argv[1], &secs, &nsecs))
892 return 1;
893 if (sblock.fs_magic == FS_UFS1_MAGIC)
894 curinode->dp1.di_atime = _time_to_time32(secs);
895 else
896 curinode->dp2.di_atime = _time_to_time64(secs);
881 inodirty();
882 printactive(0);
883 return 0;
884}
885
886CMDFUNCSTART(chatime)
887{
888 time_t secs;
889 int32_t nsecs;
890
891 if (dotime(argv[1], &secs, &nsecs))
892 return 1;
893 if (sblock.fs_magic == FS_UFS1_MAGIC)
894 curinode->dp1.di_atime = _time_to_time32(secs);
895 else
896 curinode->dp2.di_atime = _time_to_time64(secs);
897 DIP(curinode, di_atimensec) = nsecs;
897 DIP_SET(curinode, di_atimensec, nsecs);
898 inodirty();
899 printactive(0);
900 return 0;
901}
902
903CMDFUNCSTART(chctime)
904{
905 time_t secs;
906 int32_t nsecs;
907
908 if (dotime(argv[1], &secs, &nsecs))
909 return 1;
910 if (sblock.fs_magic == FS_UFS1_MAGIC)
911 curinode->dp1.di_ctime = _time_to_time32(secs);
912 else
913 curinode->dp2.di_ctime = _time_to_time64(secs);
898 inodirty();
899 printactive(0);
900 return 0;
901}
902
903CMDFUNCSTART(chctime)
904{
905 time_t secs;
906 int32_t nsecs;
907
908 if (dotime(argv[1], &secs, &nsecs))
909 return 1;
910 if (sblock.fs_magic == FS_UFS1_MAGIC)
911 curinode->dp1.di_ctime = _time_to_time32(secs);
912 else
913 curinode->dp2.di_ctime = _time_to_time64(secs);
914 DIP(curinode, di_ctimensec) = nsecs;
914 DIP_SET(curinode, di_ctimensec, nsecs);
915 inodirty();
916 printactive(0);
917 return 0;
918}
915 inodirty();
916 printactive(0);
917 return 0;
918}