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