Bug Summary

File:src/sbin/fsdb/fsdb.c
Warning:line 284, column 4
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name fsdb.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sbin/fsdb/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/sbin/fsdb/../../sbin/fsck -I /usr/src/sbin/fsdb/../../sbin/fsck_ffs -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/sbin/fsdb/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/sbin/fsdb/fsdb.c
1/* $OpenBSD: fsdb.c,v 1.34 2021/01/27 05:03:25 deraadt 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
56extern char *__progname; /* from crt0.o */
57
58int main(int, char *[]);
59static void usage(void);
60static int cmdloop(void);
61static int helpfn(int, char *[]);
62static char *prompt(EditLine *);
63static int scannames(struct inodesc *);
64static int dolookup(char *);
65static int chinumfunc(struct inodesc *);
66static int chnamefunc(struct inodesc *);
67static int dotime(char *, time_t *, int32_t *);
68
69int returntosingle = 0;
70union dinode *curinode;
71ino_t curinum;
72
73struct inostatlist *inostathead;
74
75struct bufarea bufhead; /* head of list of other blks in filesys */
76struct bufarea sblk; /* file system superblock */
77struct bufarea asblk; /* alternate file system superblock */
78struct bufarea *pdirbp; /* current directory contents */
79struct bufarea *pbp; /* current inode block */
80
81struct dups *duplist; /* head of dup list */
82struct dups *muldup; /* end of unique duplicate dup block numbers */
83
84struct zlncnt *zlnhead; /* head of zero link count list */
85
86struct inoinfo **inphead, **inpsort;
87
88extern long numdirs, listmax, inplast;
89
90long secsize; /* actual disk sector size */
91char nflag; /* assume a no response */
92char yflag; /* assume a yes response */
93daddr_t bflag; /* location of alternate super block */
94int debug; /* output debugging info */
95int cvtlevel; /* convert to newer file system format */
96char usedsoftdep; /* just fix soft dependency inconsistencies */
97int preen; /* just fix normal inconsistencies */
98char resolved; /* cleared if unresolved changes => not clean */
99char havesb; /* superblock has been read */
100char skipclean; /* skip clean file systems if preening */
101int fsmodified; /* 1 => write done to file system */
102int fsreadfd; /* file descriptor for reading file system */
103int fswritefd; /* file descriptor for writing file system */
104int rerun; /* rerun fsck. Only used in non-preen mode */
105
106daddr_t maxfsblock; /* number of blocks in the file system */
107char *blockmap; /* ptr to primary blk allocation map */
108ino_t maxino; /* number of inodes in file system */
109ino_t lastino; /* last inode in use */
110
111ino_t lfdir; /* lost & found directory inode number */
112
113daddr_t n_blks; /* number of blocks in use */
114int64_t n_files; /* number of files in use */
115
116struct ufs1_dinode ufs1_zino;
117struct ufs2_dinode ufs2_zino;
118
119
120static void
121usage(void)
122{
123 fprintf(stderr(&__sF[2]), "usage: %s [-d] -f fsname\n", __progname);
124 exit(1);
125}
126
127/*
128 * We suck in lots of fsck code, and just pick & choose the stuff we want.
129 *
130 * fsreadfd is set up to read from the file system, fswritefd to write to
131 * the file system.
132 */
133int
134main(int argc, char *argv[])
135{
136 int ch, rval;
137 char *fsys = NULL((void *)0);
138
139 while (-1 != (ch = getopt(argc, argv, "f:d"))) {
1
Assuming the condition is true
2
Loop condition is true. Entering loop body
5
Assuming the condition is false
6
Loop condition is false. Execution continues on line 151
140 switch (ch) {
3
Control jumps to 'case 102:' at line 141
141 case 'f':
142 fsys = optarg;
143 break;
4
Execution continues on line 139
144 case 'd':
145 debug++;
146 break;
147 default:
148 usage();
149 }
150 }
151 if (fsys == NULL((void *)0))
7
Assuming 'fsys' is not equal to NULL
8
Taking false branch
152 usage();
153 if (!setup(fsys, 1))
9
Assuming the condition is false
10
Taking false branch
154 errx(1, "cannot set up file system `%s'", fsys);
155 printf("Editing file system `%s'\nLast Mounted on %s\n", fsys,
156 sblock(*sblk.b_un.b_fs).fs_fsmnt);
157 rval = cmdloop();
11
Calling 'cmdloop'
158 sblock(*sblk.b_un.b_fs).fs_clean = 0; /* mark it dirty */
159 sbdirty()sblk.b_dirty = 1;
160 ckfini(0);
161 printf("*** FILE SYSTEM MARKED DIRTY\n");
162 printf("*** BE SURE TO RUN FSCK TO CLEAN UP ANY DAMAGE\n");
163 printf("*** IF IT WAS MOUNTED, RE-MOUNT WITH -u -o reload\n");
164 exit(rval);
165}
166
167#define CMDFUNC(func)static int func(int argc, char *argv[]) static int func(int argc, char *argv[])
168#define CMDFUNCSTART(func)static int func(int argc, char *argv[]) static int func(int argc, char *argv[])
169
170CMDFUNC(helpfn)static int helpfn(int argc, char *argv[]);
171CMDFUNC(focus)static int focus(int argc, char *argv[]); /* focus on inode */
172CMDFUNC(active)static int active(int argc, char *argv[]); /* print active inode */
173CMDFUNC(focusname)static int focusname(int argc, char *argv[]); /* focus by name */
174CMDFUNC(zapi)static int zapi(int argc, char *argv[]); /* clear inode */
175CMDFUNC(uplink)static int uplink(int argc, char *argv[]); /* incr link */
176CMDFUNC(downlink)static int downlink(int argc, char *argv[]); /* decr link */
177CMDFUNC(linkcount)static int linkcount(int argc, char *argv[]); /* set link count */
178CMDFUNC(quit)static int quit(int argc, char *argv[]); /* quit */
179CMDFUNC(ls)static int ls(int argc, char *argv[]); /* list directory */
180CMDFUNC(rm)static int rm(int argc, char *argv[]); /* remove name */
181CMDFUNC(ln)static int ln(int argc, char *argv[]); /* add name */
182CMDFUNC(newtype)static int newtype(int argc, char *argv[]); /* change type */
183CMDFUNC(chmode)static int chmode(int argc, char *argv[]); /* change mode */
184CMDFUNC(chlen)static int chlen(int argc, char *argv[]); /* change length */
185CMDFUNC(chaflags)static int chaflags(int argc, char *argv[]); /* change flags */
186CMDFUNC(chgen)static int chgen(int argc, char *argv[]); /* change generation */
187CMDFUNC(chowner)static int chowner(int argc, char *argv[]); /* change owner */
188CMDFUNC(chgroup)static int chgroup(int argc, char *argv[]); /* Change group */
189CMDFUNC(back)static int back(int argc, char *argv[]); /* pop back to last ino */
190CMDFUNC(chmtime)static int chmtime(int argc, char *argv[]); /* Change mtime */
191CMDFUNC(chctime)static int chctime(int argc, char *argv[]); /* Change ctime */
192CMDFUNC(chatime)static int chatime(int argc, char *argv[]); /* Change atime */
193CMDFUNC(chinum)static int chinum(int argc, char *argv[]); /* Change inode # of dirent */
194CMDFUNC(chname)static int chname(int argc, char *argv[]); /* Change dirname of dirent */
195
196static struct cmdtable cmds[] = {
197 { "help", "Print out help", 1, 1, helpfn },
198 { "?", "Print out help", 1, 1, helpfn },
199 { "inode", "Set active inode to INUM", 2, 2, focus },
200 { "clri", "Clear inode INUM", 2, 2, zapi },
201 { "lookup", "Set active inode by looking up NAME", 2, 2, focusname },
202 { "cd", "Set active inode by looking up NAME", 2, 2, focusname },
203 { "back", "Go to previous active inode", 1, 1, back },
204 { "active", "Print active inode", 1, 1, active },
205 { "print", "Print active inode", 1, 1, active },
206 { "uplink", "Increment link count", 1, 1, uplink },
207 { "downlink", "Decrement link count", 1, 1, downlink },
208 { "linkcount", "Set link count to COUNT", 2, 2, linkcount },
209 { "ls", "List current inode as directory", 1, 1, ls },
210 { "rm", "Remove NAME from current inode directory", 2, 2, rm },
211 { "del", "Remove NAME from current inode directory", 2, 2, rm },
212 { "ln", "Hardlink INO into current inode directory as NAME", 3, 3, ln },
213 { "chinum", "Change dir entry number INDEX to INUM", 3, 3, chinum },
214 { "chname", "Change dir entry number INDEX to NAME", 3, 3, chname },
215 { "chtype", "Change type of current inode to TYPE", 2, 2, newtype },
216 { "chmod", "Change mode of current inode to MODE", 2, 2, chmode },
217 { "chown", "Change owner of current inode to OWNER", 2, 2, chowner },
218 { "chlen", "Change length of current inode to LENGTH", 2, 2, chlen },
219 { "chgrp", "Change group of current inode to GROUP", 2, 2, chgroup },
220 { "chflags", "Change flags of current inode to FLAGS", 2, 2, chaflags },
221 { "chgen", "Change generation number of current inode to GEN", 2, 2, chgen },
222 { "mtime", "Change mtime of current inode to MTIME", 2, 2, chmtime },
223 { "ctime", "Change ctime of current inode to CTIME", 2, 2, chctime },
224 { "atime", "Change atime of current inode to ATIME", 2, 2, chatime },
225 { "quit", "Exit", 1, 1, quit },
226 { "q", "Exit", 1, 1, quit },
227 { "exit", "Exit", 1, 1, quit },
228 { NULL((void *)0), 0, 0, 0 },
229};
230
231static int
232helpfn(int argc, char *argv[])
233{
234 struct cmdtable *cmdtp;
235
236 printf("Commands are:\n%-10s %5s %5s %s\n",
237 "command", "min argc", "max argc", "what");
238
239 for (cmdtp = cmds; cmdtp->cmd; cmdtp++)
240 printf("%-10s %5u %5u %s\n",
241 cmdtp->cmd, cmdtp->minargc, cmdtp->maxargc, cmdtp->helptxt);
242 return 0;
243}
244
245static char *
246prompt(EditLine *el)
247{
248 static char pstring[64];
249
250 snprintf(pstring, sizeof(pstring), "fsdb (inum: %llu)> ",
251 (unsigned long long)curinum);
252 return pstring;
253}
254
255
256static int
257cmdloop(void)
258{
259 char *line = NULL((void *)0);
260 const char *elline;
261 int cmd_argc, rval = 0, known;
262#define scratchknown known
263 char **cmd_argv;
264 struct cmdtable *cmdp;
265 History *hist;
266 EditLine *elptr;
267 HistEvent hev;
268
269 curinode = ginode(ROOTINO((ufsino_t)2));
270 curinum = ROOTINO((ufsino_t)2);
271 printactive();
272
273 hist = history_init();
274 history(hist, &hev, H_SETSIZE1, 100); /* 100 elt history buffer */
275
276 elptr = el_init(__progname, stdin(&__sF[0]), stdout(&__sF[1]), stderr(&__sF[2]));
277 el_set(elptr, EL_EDITOR2, "emacs");
278 el_set(elptr, EL_PROMPT0, prompt);
279 el_set(elptr, EL_HIST10, history, hist);
280 el_source(elptr, NULL((void *)0));
281
282 while ((elline = el_gets(elptr, &scratchknown)) != NULL((void *)0) && scratchknown != 0) {
12
Assuming the condition is true
13
Assuming 'known' is not equal to 0
14
Loop condition is true. Entering loop body
25
Assuming the condition is true
26
Assuming 'known' is not equal to 0
27
Loop condition is true. Entering loop body
283 if (debug)
15
Assuming 'debug' is 0
16
Taking false branch
28
Assuming 'debug' is not equal to 0
29
Taking true branch
284 printf("command `%s'\n", line);
30
Use of memory after it is freed
285
286 history(hist, &hev, H_ENTER10, elline);
287
288 line = strdup(elline);
17
Memory is allocated
289 if (line == NULL((void *)0))
18
Assuming 'line' is not equal to NULL
19
Taking false branch
290 errx(1, "out of memory");
291 cmd_argv = crack(line, &cmd_argc);
292 if (cmd_argc) {
20
Assuming 'cmd_argc' is 0
21
Taking false branch
293 /*
294 * el_parse returns -1 to signal that it's not been handled
295 * internally.
296 */
297 if (el_parse(elptr, cmd_argc, (const char **)cmd_argv) != -1)
298 continue;
299 known = 0;
300 for (cmdp = cmds; cmdp->cmd; cmdp++) {
301 if (!strcmp(cmdp->cmd, cmd_argv[0])) {
302 if (cmd_argc >= cmdp->minargc &&
303 cmd_argc <= cmdp->maxargc)
304 rval = (*cmdp->handler)(cmd_argc,
305 cmd_argv);
306 else
307 rval = argcount(cmdp,
308 cmd_argc, cmd_argv);
309 known = 1;
310 break;
311 }
312 }
313 if (!known) {
314 warnx("unknown command `%s'", cmd_argv[0]);
315 rval = 1;
316 }
317 } else
318 rval = 0;
319 free(line);
22
Memory is released
320 if (rval
22.1
'rval' is >= 0
< 0)
23
Taking false branch
321 return rval;
322 if (rval
23.1
'rval' is 0
)
24
Taking false branch
323 warnx("rval was %d", rval);
324 }
325 el_end(elptr);
326 history_end(hist);
327 return rval;
328}
329
330static ino_t ocurrent;
331
332#define GETINUM(ac,inum)inum = strtoull(argv[ac], &cp, 0); if (inum < ((ufsino_t
)2) || inum > maxino || cp == argv[ac] || *cp != '\0' ) { printf
("inode %llu out of range; range is [%llu,%llu]\n", (unsigned
long long)inum, (unsigned long long)((ufsino_t)2), (unsigned
long long)maxino); return 1; }
inum = strtoull(argv[ac], &cp, 0); \
333 if (inum < ROOTINO((ufsino_t)2) || inum > maxino || cp == argv[ac] || *cp != '\0' ) { \
334 printf("inode %llu out of range; range is [%llu,%llu]\n", \
335 (unsigned long long)inum, (unsigned long long)ROOTINO((ufsino_t)2), \
336 (unsigned long long)maxino); \
337 return 1; \
338 }
339
340/*
341 * Focus on given inode number
342 */
343CMDFUNCSTART(focus)static int focus(int argc, char *argv[])
344{
345 ino_t inum;
346 char *cp;
347
348 GETINUM(1,inum)inum = strtoull(argv[1], &cp, 0); if (inum < ((ufsino_t
)2) || inum > maxino || cp == argv[1] || *cp != '\0' ) { printf
("inode %llu out of range; range is [%llu,%llu]\n", (unsigned
long long)inum, (unsigned long long)((ufsino_t)2), (unsigned
long long)maxino); return 1; }
;
349 curinode = ginode(inum);
350 ocurrent = curinum;
351 curinum = inum;
352 printactive();
353 return 0;
354}
355
356CMDFUNCSTART(back)static int back(int argc, char *argv[])
357{
358 curinum = ocurrent;
359 curinode = ginode(curinum);
360 printactive();
361 return 0;
362}
363
364CMDFUNCSTART(zapi)static int zapi(int argc, char *argv[])
365{
366 ino_t inum;
367 union dinode *dp;
368 char *cp;
369
370 GETINUM(1,inum)inum = strtoull(argv[1], &cp, 0); if (inum < ((ufsino_t
)2) || inum > maxino || cp == argv[1] || *cp != '\0' ) { printf
("inode %llu out of range; range is [%llu,%llu]\n", (unsigned
long long)inum, (unsigned long long)((ufsino_t)2), (unsigned
long long)maxino); return 1; }
;
371 dp = ginode(inum);
372 clearinode(dp)if ((*sblk.b_un.b_fs).fs_magic == 0x011954) { (dp)->dp1 = ufs1_zino
; } else { (dp)->dp2 = ufs2_zino; }
;
373 inodirty();
374 if (curinode) /* re-set after potential change */
375 curinode = ginode(curinum);
376 return 0;
377}
378
379CMDFUNCSTART(active)static int active(int argc, char *argv[])
380{
381 printactive();
382 return 0;
383}
384
385
386CMDFUNCSTART(quit)static int quit(int argc, char *argv[])
387{
388 return -1;
389}
390
391CMDFUNCSTART(uplink)static int uplink(int argc, char *argv[])
392{
393 if (!checkactive())
394 return 1;
395 DIP_SET(curinode, di_nlink, DIP(curinode, di_nlink) + 1)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)->
dp1.di_nlink = ((((*sblk.b_un.b_fs).fs_magic == 0x011954) ? (
curinode)->dp1.di_nlink : (curinode)->dp2.di_nlink) + 1
); else (curinode)->dp2.di_nlink = ((((*sblk.b_un.b_fs).fs_magic
== 0x011954) ? (curinode)->dp1.di_nlink : (curinode)->
dp2.di_nlink) + 1); } while (0)
;
396 printf("inode %llu link count now %d\n",
397 (unsigned long long)curinum, DIP(curinode, di_nlink)(((*sblk.b_un.b_fs).fs_magic == 0x011954) ? (curinode)->dp1
.di_nlink : (curinode)->dp2.di_nlink)
);
398 inodirty();
399 return 0;
400}
401
402CMDFUNCSTART(downlink)static int downlink(int argc, char *argv[])
403{
404 if (!checkactive())
405 return 1;
406 DIP_SET(curinode, di_nlink, DIP(curinode, di_nlink) - 1)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)->
dp1.di_nlink = ((((*sblk.b_un.b_fs).fs_magic == 0x011954) ? (
curinode)->dp1.di_nlink : (curinode)->dp2.di_nlink) - 1
); else (curinode)->dp2.di_nlink = ((((*sblk.b_un.b_fs).fs_magic
== 0x011954) ? (curinode)->dp1.di_nlink : (curinode)->
dp2.di_nlink) - 1); } while (0)
;
407 printf("inode %llu link count now %d\n",
408 (unsigned long long)curinum, DIP(curinode, di_nlink)(((*sblk.b_un.b_fs).fs_magic == 0x011954) ? (curinode)->dp1
.di_nlink : (curinode)->dp2.di_nlink)
);
409 inodirty();
410 return 0;
411}
412
413static const char *typename[] = {
414 "unknown",
415 "fifo",
416 "char special",
417 "unregistered #3",
418 "directory",
419 "unregistered #5",
420 "blk special",
421 "unregistered #7",
422 "regular",
423 "unregistered #9",
424 "symlink",
425 "unregistered #11",
426 "socket",
427 "unregistered #13",
428 "whiteout",
429};
430
431static int slot;
432
433static int
434scannames(struct inodesc *idesc)
435{
436 struct direct *dirp = idesc->id_dirp;
437
438 printf("slot %d ino %llu reclen %d: %s, `%.*s'\n",
439 slot++, (unsigned long long)dirp->d_ino, dirp->d_reclen,
440 typename[dirp->d_type], dirp->d_namlen, dirp->d_name);
441 return (KEEPON0x04);
442}
443
444CMDFUNCSTART(ls)static int ls(int argc, char *argv[])
445{
446 struct inodesc idesc;
447 checkactivedir(); /* let it go on anyway */
448
449 slot = 0;
450 idesc.id_number = curinum;
451 idesc.id_func = scannames;
452 idesc.id_type = DATA1;
453 idesc.id_fix = IGNORE;
454 ckinode(curinode, &idesc);
455 curinode = ginode(curinum);
456
457 return 0;
458}
459
460static int
461dolookup(char *name)
462{
463 struct inodesc idesc;
464
465 if (!checkactivedir())
466 return 0;
467 idesc.id_number = curinum;
468 idesc.id_func = findino;
469 idesc.id_name = name;
470 idesc.id_type = DATA1;
471 idesc.id_fix = IGNORE;
472 if (ckinode(curinode, &idesc) & FOUND0x10) {
473 curinum = idesc.id_parent;
474 curinode = ginode(curinum);
475 printactive();
476 return 1;
477 } else {
478 warnx("name `%s' not found in current inode directory", name);
479 return 0;
480 }
481}
482
483CMDFUNCSTART(focusname)static int focusname(int argc, char *argv[])
484{
485 char *p, *val;
486
487 if (!checkactive())
488 return 1;
489
490 ocurrent = curinum;
491
492 if (argv[1][0] == '/') {
493 curinum = ROOTINO((ufsino_t)2);
494 curinode = ginode(ROOTINO((ufsino_t)2));
495 } else {
496 if (!checkactivedir())
497 return 1;
498 }
499 for (p = argv[1]; p != NULL((void *)0);) {
500 while ((val = strsep(&p, "/")) != NULL((void *)0) && *val == '\0')
501 continue;
502 if (val) {
503 printf("component `%s': ", val);
504 fflush(stdout(&__sF[1]));
505 if (!dolookup(val)) {
506 curinode = ginode(curinum);
507 return(1);
508 }
509 }
510 }
511 return 0;
512}
513
514CMDFUNCSTART(ln)static int ln(int argc, char *argv[])
515{
516 ino_t inum;
517 int rval;
518 char *cp;
519
520 GETINUM(1,inum)inum = strtoull(argv[1], &cp, 0); if (inum < ((ufsino_t
)2) || inum > maxino || cp == argv[1] || *cp != '\0' ) { printf
("inode %llu out of range; range is [%llu,%llu]\n", (unsigned
long long)inum, (unsigned long long)((ufsino_t)2), (unsigned
long long)maxino); return 1; }
;
521
522 if (!checkactivedir())
523 return 1;
524 rval = makeentry(curinum, inum, argv[2]);
525 if (rval)
526 printf("Ino %llu entered as `%s'\n",
527 (unsigned long long)inum, argv[2]);
528 else
529 printf("could not enter name? weird.\n");
530 curinode = ginode(curinum);
531 return rval;
532}
533
534CMDFUNCSTART(rm)static int rm(int argc, char *argv[])
535{
536 int rval;
537
538 if (!checkactivedir())
539 return 1;
540 rval = changeino(curinum, argv[1], 0);
541 if (rval & ALTERED0x08) {
542 printf("Name `%s' removed\n", argv[1]);
543 return 0;
544 } else {
545 printf("could not remove name? weird.\n");
546 return 1;
547 }
548}
549
550static long slotcount, desired;
551
552static int
553chinumfunc(struct inodesc *idesc)
554{
555 struct direct *dirp = idesc->id_dirp;
556
557 if (slotcount++ == desired) {
558 dirp->d_ino = idesc->id_parent;
559 return STOP0x01|ALTERED0x08|FOUND0x10;
560 }
561 return KEEPON0x04;
562}
563
564CMDFUNCSTART(chinum)static int chinum(int argc, char *argv[])
565{
566 char *cp;
567 ino_t inum;
568 struct inodesc idesc;
569
570 slotcount = 0;
571 if (!checkactivedir())
572 return 1;
573 GETINUM(2,inum)inum = strtoull(argv[2], &cp, 0); if (inum < ((ufsino_t
)2) || inum > maxino || cp == argv[2] || *cp != '\0' ) { printf
("inode %llu out of range; range is [%llu,%llu]\n", (unsigned
long long)inum, (unsigned long long)((ufsino_t)2), (unsigned
long long)maxino); return 1; }
;
574
575 desired = strtol(argv[1], &cp, 0);
576 if (cp == argv[1] || *cp != '\0' || desired < 0) {
577 printf("invalid slot number `%s'\n", argv[1]);
578 return 1;
579 }
580
581 idesc.id_number = curinum;
582 idesc.id_func = chinumfunc;
583 idesc.id_fix = IGNORE;
584 idesc.id_type = DATA1;
585 idesc.id_parent = inum; /* XXX convenient hiding place */
586
587 if (ckinode(curinode, &idesc) & FOUND0x10)
588 return 0;
589 else {
590 warnx("no %sth slot in current directory", argv[1]);
591 return 1;
592 }
593}
594
595static int
596chnamefunc(struct inodesc *idesc)
597{
598 struct direct *dirp = idesc->id_dirp;
599 struct direct testdir;
600
601 if (slotcount++ == desired) {
602 /* will name fit? */
603 testdir.d_namlen = strlen(idesc->id_name);
604 if (DIRSIZ(NEWDIRFMT, &testdir)((0) ? ((sizeof(struct direct) - (255 +1)) + (((&testdir)
->d_type+1 + 3) &~ 3)) : ((sizeof(struct direct) - (255
+1)) + (((&testdir)->d_namlen+1 + 3) &~ 3)))
<= dirp->d_reclen) {
605 dirp->d_namlen = testdir.d_namlen;
606 strlcpy(dirp->d_name, idesc->id_name, sizeof dirp->d_name);
607 return STOP0x01|ALTERED0x08|FOUND0x10;
608 } else
609 return STOP0x01|FOUND0x10; /* won't fit, so give up */
610 }
611 return KEEPON0x04;
612}
613
614CMDFUNCSTART(chname)static int chname(int argc, char *argv[])
615{
616 int rval;
617 char *cp;
618 struct inodesc idesc;
619
620 slotcount = 0;
621 if (!checkactivedir())
622 return 1;
623
624 desired = strtoul(argv[1], &cp, 0);
625 if (cp == argv[1] || *cp != '\0') {
626 printf("invalid slot number `%s'\n", argv[1]);
627 return 1;
628 }
629
630 idesc.id_number = curinum;
631 idesc.id_func = chnamefunc;
632 idesc.id_fix = IGNORE;
633 idesc.id_type = DATA1;
634 idesc.id_name = argv[2];
635
636 rval = ckinode(curinode, &idesc);
637 if ((rval & (FOUND0x10|ALTERED0x08)) == (FOUND0x10|ALTERED0x08))
638 return 0;
639 else if (rval & FOUND0x10) {
640 warnx("new name `%s' does not fit in slot %s", argv[2], argv[1]);
641 return 1;
642 } else {
643 warnx("no %sth slot in current directory", argv[1]);
644 return 1;
645 }
646}
647
648static struct typemap {
649 const char *typename;
650 int typebits;
651} typenamemap[] = {
652 {"file", IFREG0100000},
653 {"dir", IFDIR0040000},
654 {"socket", IFSOCK0140000},
655 {"fifo", IFIFO0010000},
656};
657
658CMDFUNCSTART(newtype)static int newtype(int argc, char *argv[])
659{
660 int type;
661 struct typemap *tp;
662
663 if (!checkactive())
664 return 1;
665 type = DIP(curinode, di_mode)(((*sblk.b_un.b_fs).fs_magic == 0x011954) ? (curinode)->dp1
.di_mode : (curinode)->dp2.di_mode)
& IFMT0170000;
666 for (tp = typenamemap;
667 tp < &typenamemap[sizeof(typenamemap)/sizeof(*typenamemap)];
668 tp++) {
669 if (!strcmp(argv[1], tp->typename)) {
670 printf("setting type to %s\n", tp->typename);
671 type = tp->typebits;
672 break;
673 }
674 }
675 if (tp == &typenamemap[sizeof(typenamemap)/sizeof(*typenamemap)]) {
676 warnx("type `%s' not known", argv[1]);
677 warnx("try one of `file', `dir', `socket', `fifo'");
678 return 1;
679 }
680 DIP_SET(curinode, di_mode, DIP(curinode, di_mode) & ~IFMT)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)->
dp1.di_mode = ((((*sblk.b_un.b_fs).fs_magic == 0x011954) ? (curinode
)->dp1.di_mode : (curinode)->dp2.di_mode) & ~0170000
); else (curinode)->dp2.di_mode = ((((*sblk.b_un.b_fs).fs_magic
== 0x011954) ? (curinode)->dp1.di_mode : (curinode)->dp2
.di_mode) & ~0170000); } while (0)
;
681 DIP_SET(curinode, di_mode, DIP(curinode, di_mode) | type)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)->
dp1.di_mode = ((((*sblk.b_un.b_fs).fs_magic == 0x011954) ? (curinode
)->dp1.di_mode : (curinode)->dp2.di_mode) | type); else
(curinode)->dp2.di_mode = ((((*sblk.b_un.b_fs).fs_magic ==
0x011954) ? (curinode)->dp1.di_mode : (curinode)->dp2.
di_mode) | type); } while (0)
;
682 inodirty();
683 printactive();
684 return 0;
685}
686
687CMDFUNCSTART(chmode)static int chmode(int argc, char *argv[])
688{
689 int rval = 1;
690 long modebits;
691 char *cp;
692
693 if (!checkactive())
694 return 1;
695
696 modebits = strtol(argv[1], &cp, 8);
697 if (cp == argv[1] || *cp != '\0' ) {
698 warnx("bad modebits `%s'", argv[1]);
699 return 1;
700 }
701
702 DIP_SET(curinode, di_mode, DIP(curinode, di_mode) & ~07777)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)->
dp1.di_mode = ((((*sblk.b_un.b_fs).fs_magic == 0x011954) ? (curinode
)->dp1.di_mode : (curinode)->dp2.di_mode) & ~07777)
; else (curinode)->dp2.di_mode = ((((*sblk.b_un.b_fs).fs_magic
== 0x011954) ? (curinode)->dp1.di_mode : (curinode)->dp2
.di_mode) & ~07777); } while (0)
;
703 DIP_SET(curinode, di_mode, DIP(curinode, di_mode) | modebits)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)->
dp1.di_mode = ((((*sblk.b_un.b_fs).fs_magic == 0x011954) ? (curinode
)->dp1.di_mode : (curinode)->dp2.di_mode) | modebits); else
(curinode)->dp2.di_mode = ((((*sblk.b_un.b_fs).fs_magic ==
0x011954) ? (curinode)->dp1.di_mode : (curinode)->dp2.
di_mode) | modebits); } while (0)
;
704 inodirty();
705 printactive();
706 return rval;
707}
708
709CMDFUNCSTART(chlen)static int chlen(int argc, char *argv[])
710{
711 int rval = 1;
712 long len;
713 char *cp;
714
715 if (!checkactive())
716 return 1;
717
718 len = strtol(argv[1], &cp, 0);
719 if (cp == argv[1] || *cp != '\0' || len < 0) {
720 warnx("bad length '%s'", argv[1]);
721 return 1;
722 }
723
724 DIP_SET(curinode, di_size, len)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)->
dp1.di_size = (len); else (curinode)->dp2.di_size = (len);
} while (0)
;
725 inodirty();
726 printactive();
727 return rval;
728}
729
730CMDFUNCSTART(chaflags)static int chaflags(int argc, char *argv[])
731{
732 int rval = 1;
733 u_long flags;
734 char *cp;
735
736 if (!checkactive())
737 return 1;
738
739 flags = strtoul(argv[1], &cp, 0);
740 if (cp == argv[1] || *cp != '\0' ) {
741 warnx("bad flags `%s'", argv[1]);
742 return 1;
743 }
744
745 if (flags > UINT_MAX(2147483647 *2U +1U)) {
746 warnx("flags set beyond 32-bit range of field (%lx)", flags);
747 return(1);
748 }
749 DIP_SET(curinode, di_flags, flags)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)->
dp1.di_flags = (flags); else (curinode)->dp2.di_flags = (flags
); } while (0)
;
750 inodirty();
751 printactive();
752 return rval;
753}
754
755CMDFUNCSTART(chgen)static int chgen(int argc, char *argv[])
756{
757 int rval = 1;
758 long long gen;
759 char *cp;
760
761 if (!checkactive())
762 return 1;
763
764 gen = strtoll(argv[1], &cp, 0);
765 if (cp == argv[1] || *cp != '\0' ) {
766 warnx("bad gen `%s'", argv[1]);
767 return 1;
768 }
769
770 if (gen > UINT_MAX(2147483647 *2U +1U) || gen < 0) {
771 warnx("gen set beyond 32-bit range of field (%llx)", gen);
772 return(1);
773 }
774 DIP_SET(curinode, di_gen, gen)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)->
dp1.di_gen = (gen); else (curinode)->dp2.di_gen = (gen); }
while (0)
;
775 inodirty();
776 printactive();
777 return rval;
778}
779
780CMDFUNCSTART(linkcount)static int linkcount(int argc, char *argv[])
781{
782 int rval = 1;
783 int lcnt;
784 char *cp;
785
786 if (!checkactive())
787 return 1;
788
789 lcnt = strtol(argv[1], &cp, 0);
790 if (cp == argv[1] || *cp != '\0' ) {
791 warnx("bad link count `%s'", argv[1]);
792 return 1;
793 }
794 if (lcnt > USHRT_MAX(32767 *2 +1) || lcnt < 0) {
795 warnx("max link count is %d", USHRT_MAX(32767 *2 +1));
796 return 1;
797 }
798
799 DIP_SET(curinode, di_nlink, lcnt)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)->
dp1.di_nlink = (lcnt); else (curinode)->dp2.di_nlink = (lcnt
); } while (0)
;
800 inodirty();
801 printactive();
802 return rval;
803}
804
805CMDFUNCSTART(chowner)static int chowner(int argc, char *argv[])
806{
807 int rval = 1;
808 uid_t uid;
809 char *cp;
810
811 if (!checkactive())
812 return 1;
813
814 uid = strtoul(argv[1], &cp, 0);
815 if (cp == argv[1] || *cp != '\0' ) {
816 /* try looking up name */
817 if (uid_from_user(argv[1], &uid) == -1) {
818 warnx("bad uid `%s'", argv[1]);
819 return 1;
820 }
821 }
822
823 DIP_SET(curinode, di_uid, uid)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)->
dp1.di_uid = (uid); else (curinode)->dp2.di_uid = (uid); }
while (0)
;
824 inodirty();
825 printactive();
826 return rval;
827}
828
829CMDFUNCSTART(chgroup)static int chgroup(int argc, char *argv[])
830{
831 int rval = 1;
832 gid_t gid;
833 char *cp;
834 struct group *grp;
835
836 if (!checkactive())
837 return 1;
838
839 gid = strtoul(argv[1], &cp, 0);
840 if (cp == argv[1] || *cp != '\0' ) {
841 if ((grp = getgrnam(argv[1]))) {
842 gid = grp->gr_gid;
843 } else {
844 warnx("bad gid `%s'", argv[1]);
845 return 1;
846 }
847 }
848
849 DIP_SET(curinode, di_gid, gid)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)->
dp1.di_gid = (gid); else (curinode)->dp2.di_gid = (gid); }
while (0)
;
850 inodirty();
851 printactive();
852 return rval;
853}
854
855static int
856dotime(char *name, time_t *rsec, int32_t *rnsec)
857{
858 char *p, *val;
859 struct tm t;
860 time_t sec;
861 int32_t nsec;
862
863 p = strchr(name, '.');
864 if (p) {
865 *p = '\0';
866 nsec = strtoul(++p, &val, 0);
867 if (val == p || *val != '\0' || nsec >= 1000000000 || nsec < 0) {
868 warnx("invalid nanoseconds");
869 goto badformat;
870 }
871 } else
872 nsec = 0;
873
874 if (strlen(name) != 14) {
875badformat:
876 warnx("date format: YYYYMMDDHHMMSS[.nsec]");
877 return 1;
878 }
879
880 for (p = name; *p; p++)
881 if (*p < '0' || *p > '9')
882 goto badformat;
883
884 p = name;
885#define VAL()((*p++) - '0') ((*p++) - '0')
886 bzero(&t, sizeof t);
887 t.tm_year = VAL()((*p++) - '0');
888 t.tm_year = VAL()((*p++) - '0') + t.tm_year * 10;
889 t.tm_year = VAL()((*p++) - '0') + t.tm_year * 10;
890 t.tm_year = VAL()((*p++) - '0') + t.tm_year * 10 - 1900;
891 t.tm_mon = VAL()((*p++) - '0');
892 t.tm_mon = VAL()((*p++) - '0') + t.tm_mon * 10 - 1;
893 t.tm_mday = VAL()((*p++) - '0');
894 t.tm_mday = VAL()((*p++) - '0') + t.tm_mday * 10;
895 t.tm_hour = VAL()((*p++) - '0');
896 t.tm_hour = VAL()((*p++) - '0') + t.tm_hour * 10;
897 t.tm_min = VAL()((*p++) - '0');
898 t.tm_min = VAL()((*p++) - '0') + t.tm_min * 10;
899 t.tm_sec = VAL()((*p++) - '0');
900 t.tm_sec = VAL()((*p++) - '0') + t.tm_sec * 10;
901 t.tm_isdst = -1;
902
903 sec = mktime(&t);
904 if (sec == -1) {
905 warnx("date/time out of range");
906 return 1;
907 }
908 *rsec = sec;
909 *rnsec = nsec;
910 return 0;
911}
912
913CMDFUNCSTART(chmtime)static int chmtime(int argc, char *argv[])
914{
915 time_t rsec;
916 int32_t nsec;
917
918 if (dotime(argv[1], &rsec, &nsec))
919 return 1;
920 DIP_SET(curinode, di_mtime, rsec)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)->
dp1.di_mtime = (rsec); else (curinode)->dp2.di_mtime = (rsec
); } while (0)
;
921 DIP_SET(curinode, di_mtimensec, nsec)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)->
dp1.di_mtimensec = (nsec); else (curinode)->dp2.di_mtimensec
= (nsec); } while (0)
;
922 inodirty();
923 printactive();
924 return 0;
925}
926
927CMDFUNCSTART(chatime)static int chatime(int argc, char *argv[])
928{
929 time_t rsec;
930 int32_t nsec;
931
932 if (dotime(argv[1], &rsec, &nsec))
933 return 1;
934 DIP_SET(curinode, di_atime, rsec)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)->
dp1.di_atime = (rsec); else (curinode)->dp2.di_atime = (rsec
); } while (0)
;
935 DIP_SET(curinode, di_atimensec, nsec)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)->
dp1.di_atimensec = (nsec); else (curinode)->dp2.di_atimensec
= (nsec); } while (0)
;
936 inodirty();
937 printactive();
938 return 0;
939}
940
941CMDFUNCSTART(chctime)static int chctime(int argc, char *argv[])
942{
943 time_t rsec;
944 int32_t nsec;
945
946 if (dotime(argv[1], &rsec, &nsec))
947 return 1;
948 DIP_SET(curinode, di_ctime, rsec)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)->
dp1.di_ctime = (rsec); else (curinode)->dp2.di_ctime = (rsec
); } while (0)
;
949 DIP_SET(curinode, di_ctimensec, nsec)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)->
dp1.di_ctimensec = (nsec); else (curinode)->dp2.di_ctimensec
= (nsec); } while (0)
;
950 inodirty();
951 printactive();
952 return 0;
953}