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