1 /* $NetBSD: fsdb.c,v 1.38 2008/08/30 10:46:16 bouyer Exp $ */
4 * Copyright (c) 1996 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
34 __RCSID("$NetBSD: fsdb.c,v 1.38 2008/08/30 10:46:16 bouyer Exp $");
37 #include <sys/types.h>
39 #include <sys/param.h>
41 #include <sys/mount.h>
55 #include <ufs/ufs/dinode.h>
56 #include <ufs/ufs/dir.h>
57 #include <ufs/ffs/fs.h>
58 #include <ufs/ffs/ffs_extern.h>
64 static void usage(void);
65 static int cmdloop(void);
66 static char *prompt(EditLine
*);
67 static int scannames(struct inodesc
*);
68 static int dolookup(char *);
69 static int chinumfunc(struct inodesc
*);
70 static int chnamefunc(struct inodesc
*);
71 static int dotime(char *, int32_t *, int32_t *);
72 static void print_blks32(int32_t *buf
, int size
, uint64_t *blknum
);
73 static void print_blks64(int64_t *buf
, int size
, uint64_t *blknum
);
74 static void print_indirblks32(uint32_t blk
, int ind_level
,
76 static void print_indirblks64(uint64_t blk
, int ind_level
,
78 static int compare_blk32(uint32_t *, uint32_t);
79 static int compare_blk64(uint64_t *, uint64_t);
80 static int founddatablk(uint64_t);
81 static int find_blks32(uint32_t *buf
, int size
, uint32_t *blknum
);
82 static int find_blks64(uint64_t *buf
, int size
, uint64_t *blknum
);
83 static int find_indirblks32(uint32_t blk
, int ind_level
,
85 static int find_indirblks64(uint64_t blk
, int ind_level
,
88 int returntosingle
= 0;
89 union dinode
*curinode
;
95 errx(1, "usage: %s [-dFn] -f <fsname>", getprogname());
98 * We suck in lots of fsck code, and just pick & choose the stuff we want.
100 * fsreadfd is set up to read from the file system, fswritefd to write to
104 main(int argc
, char *argv
[])
112 while ((ch
= getopt(argc
, argv
, "dFf:n")) != -1) {
133 if (setup(fsys
, fsys
) <= 0)
134 errx(1, "cannot set up file system `%s'", fsys
);
135 printf("Editing file system `%s'\nLast Mounted on %s\n", fsys
,
140 sblock
->fs_clean
= 0; /* mark it dirty */
144 printf("*** FILE SYSTEM MARKED DIRTY\n");
145 printf("*** BE SURE TO RUN FSCK TO CLEAN UP ANY DAMAGE\n");
146 printf("*** IF IT WAS MOUNTED, RE-MOUNT WITH -u -o reload\n");
150 #define CMDFUNC(func) static int func (int argc, char *argv[])
151 #define CMDFUNCSTART(func) static int func(argc, argv) \
156 CMDFUNC(focus
); /* focus on inode */
157 CMDFUNC(active
); /* print active inode */
158 CMDFUNC(focusname
); /* focus by name */
159 CMDFUNC(zapi
); /* clear inode */
160 CMDFUNC(uplink
); /* incr link */
161 CMDFUNC(downlink
); /* decr link */
162 CMDFUNC(linkcount
); /* set link count */
163 CMDFUNC(quit
); /* quit */
164 CMDFUNC(ls
); /* list directory */
165 CMDFUNC(blks
); /* list blocks */
166 CMDFUNC(findblk
); /* find block */
167 CMDFUNC(rm
); /* remove name */
168 CMDFUNC(ln
); /* add name */
169 CMDFUNC(newtype
); /* change type */
170 CMDFUNC(chmode
); /* change mode */
171 CMDFUNC(chlen
); /* change length */
172 CMDFUNC(chaflags
); /* change flags */
173 CMDFUNC(chgen
); /* change generation */
174 CMDFUNC(chowner
); /* change owner */
175 CMDFUNC(chgroup
); /* Change group */
176 CMDFUNC(back
); /* pop back to last ino */
177 CMDFUNC(chmtime
); /* Change mtime */
178 CMDFUNC(chctime
); /* Change ctime */
179 CMDFUNC(chatime
); /* Change atime */
180 CMDFUNC(chinum
); /* Change inode # of dirent */
181 CMDFUNC(chname
); /* Change dirname of dirent */
183 static struct cmdtable cmds
[] = {
184 {"help", "Print out help", 1, 1, helpfn
},
185 {"?", "Print out help", 1, 1, helpfn
},
186 {"inode", "Set active inode to INUM", 2, 2, focus
},
187 {"clri", "Clear inode INUM", 2, 2, zapi
},
188 {"lookup", "Set active inode by looking up NAME", 2, 2, focusname
},
189 {"cd", "Set active inode by looking up NAME", 2, 2, focusname
},
190 {"back", "Go to previous active inode", 1, 1, back
},
191 {"active", "Print active inode", 1, 1, active
},
192 {"print", "Print active inode", 1, 1, active
},
193 {"uplink", "Increment link count", 1, 1, uplink
},
194 {"downlink", "Decrement link count", 1, 1, downlink
},
195 {"linkcount", "Set link count to COUNT", 2, 2, linkcount
},
196 {"ls", "List current inode as directory", 1, 1, ls
},
197 {"blks", "List current inode's data blocks", 1, 1, blks
},
198 {"findblk", "Find inode owning disk block(s)", 2, 33, findblk
},
199 {"rm", "Remove NAME from current inode directory", 2, 2, rm
},
200 {"del", "Remove NAME from current inode directory", 2, 2, rm
},
201 {"ln", "Hardlink INO into current inode directory as NAME", 3, 3, ln
},
202 {"chinum", "Change dir entry number INDEX to INUM", 3, 3, chinum
},
203 {"chname", "Change dir entry number INDEX to NAME", 3, 3, chname
},
204 {"chtype", "Change type of current inode to TYPE", 2, 2, newtype
},
205 {"chmod", "Change mode of current inode to MODE", 2, 2, chmode
},
206 {"chown", "Change owner of current inode to OWNER", 2, 2, chowner
},
207 {"chlen", "Change length of current inode to LENGTH", 2, 2, chlen
},
208 {"chgrp", "Change group of current inode to GROUP", 2, 2, chgroup
},
209 {"chflags", "Change flags of current inode to FLAGS", 2, 2, chaflags
},
210 {"chgen", "Change generation number of current inode to GEN", 2, 2,
212 {"mtime", "Change mtime of current inode to MTIME", 2, 2, chmtime
},
213 {"ctime", "Change ctime of current inode to CTIME", 2, 2, chctime
},
214 {"atime", "Change atime of current inode to ATIME", 2, 2, chatime
},
215 {"quit", "Exit", 1, 1, quit
},
216 {"q", "Exit", 1, 1, quit
},
217 {"exit", "Exit", 1, 1, quit
},
222 helpfn(int argc
, char *argv
[])
224 struct cmdtable
*cmdtp
;
226 printf("Commands are:\n%-10s %5s %5s %s\n",
227 "command", "min argc", "max argc", "what");
229 for (cmdtp
= cmds
; cmdtp
->cmd
; cmdtp
++)
230 printf("%-10s %5u %5u %s\n",
231 cmdtp
->cmd
, cmdtp
->minargc
, cmdtp
->maxargc
, cmdtp
->helptxt
);
238 static char pstring
[64];
239 snprintf(pstring
, sizeof(pstring
), "fsdb (inum: %llu)> ",
240 (unsigned long long)curinum
);
250 int cmd_argc
, rval
= 0, known
;
251 #define scratch known
253 struct cmdtable
*cmdp
;
258 curinode
= ginode(ROOTINO
);
262 hist
= history_init();
263 history(hist
, &he
, H_SETSIZE
, 100); /* 100 elt history buffer */
265 elptr
= el_init(getprogname(), stdin
, stdout
, stderr
);
266 el_set(elptr
, EL_EDITOR
, "emacs");
267 el_set(elptr
, EL_PROMPT
, prompt
);
268 el_set(elptr
, EL_HIST
, history
, hist
);
269 el_source(elptr
, NULL
);
271 while ((elline
= el_gets(elptr
, &scratch
)) != NULL
&& scratch
!= 0) {
273 printf("command `%s'\n", elline
);
275 history(hist
, &he
, H_ENTER
, elline
);
277 line
= strdup(elline
);
278 cmd_argv
= crack(line
, &cmd_argc
);
281 * el_parse returns -1 to signal that it's not been
282 * handled internally.
284 if (el_parse(elptr
, cmd_argc
,
285 (const char **)cmd_argv
) != -1)
288 for (cmdp
= cmds
; cmdp
->cmd
; cmdp
++) {
289 if (!strcmp(cmdp
->cmd
, cmd_argv
[0])) {
290 if (cmd_argc
>= cmdp
->minargc
&&
291 cmd_argc
<= cmdp
->maxargc
)
293 (*cmdp
->handler
)(cmd_argc
,
296 rval
= argcount(cmdp
, cmd_argc
,
303 warnx("unknown command `%s'", cmd_argv
[0]),
311 warnx("rval was %d", rval
);
318 static ino_t ocurrent
;
320 #define GETINUM(ac,inum) inum = strtoull(argv[ac], &cp, 0); \
321 if (inum < ROOTINO || inum >= maxino || cp == argv[ac] || *cp != '\0' ) { \
322 printf("inode %llu out of range; range is [%llu,%llu]\n", \
323 (unsigned long long)inum, (unsigned long long)ROOTINO, \
324 (unsigned long long)maxino); \
329 * Focus on given inode number
337 curinode
= ginode(inum
);
347 curinode
= ginode(curinum
);
362 if (curinode
) /* re-set after potential change */
363 curinode
= ginode(curinum
);
384 nlink
= iswap16(DIP(curinode
, nlink
));
386 DIP_SET(curinode
, nlink
, iswap16(nlink
));
387 printf("inode %llu link count now %d\n", (unsigned long long)curinum
,
393 CMDFUNCSTART(downlink
)
399 nlink
= iswap16(DIP(curinode
, nlink
));
401 DIP_SET(curinode
, nlink
, iswap16(nlink
));
402 printf("inode %llu link count now %d\n", (unsigned long long)curinum
,
408 static const char *typename
[] = {
429 scannames(struct inodesc
*idesc
)
431 struct direct
*dirp
= idesc
->id_dirp
;
433 printf("slot %d ino %d reclen %d: %s, `%.*s'\n",
434 slot
++, iswap32(dirp
->d_ino
), iswap16(dirp
->d_reclen
),
435 typename
[dirp
->d_type
],
436 dirp
->d_namlen
, dirp
->d_name
);
442 struct inodesc idesc
;
443 checkactivedir(); /* let it go on anyway */
446 idesc
.id_number
= curinum
;
447 idesc
.id_func
= scannames
;
448 idesc
.id_type
= DATA
;
449 idesc
.id_fix
= IGNORE
;
450 ckinode(curinode
, &idesc
);
451 curinode
= ginode(curinum
);
461 warnx("no current inode");
464 type
= iswap16(DIP(curinode
, mode
)) & IFMT
;
465 if (type
!= IFDIR
&& type
!= IFREG
) {
466 warnx("inode %llu not a file or directory",
467 (unsigned long long)curinum
);
471 printf("I=%llu %lld blocks\n", (unsigned long long)curinum
,
472 (long long)(iswap64(curinode
->dp2
.di_blocks
)));
474 printf("I=%llu %d blocks\n", (unsigned long long)curinum
,
475 iswap32(curinode
->dp1
.di_blocks
));
477 printf("Direct blocks:\n");
479 print_blks64(curinode
->dp2
.di_db
, NDADDR
, &blkno
);
481 print_blks32(curinode
->dp1
.di_db
, NDADDR
, &blkno
);
484 for (i
= 0; i
< NIADDR
; i
++)
485 print_indirblks64(iswap64(curinode
->dp2
.di_ib
[i
]), i
,
488 for (i
= 0; i
< NIADDR
; i
++)
489 print_indirblks32(iswap32(curinode
->dp1
.di_ib
[i
]), i
,
495 static int findblk_numtofind
;
496 static int wantedblksize
;
497 CMDFUNCSTART(findblk
)
499 ino_t inum
, inosused
;
500 uint32_t *wantedblk32
= NULL
;
501 uint64_t *wantedblk64
= NULL
;
502 struct cg
*cgp
= cgrp
;
506 wantedblksize
= (argc
- 1);
508 wantedblk64
= malloc(sizeof(uint64_t) * wantedblksize
);
509 if (wantedblk64
== NULL
) {
513 memset(wantedblk64
, 0, sizeof(uint64_t) * wantedblksize
);
514 for (i
= 1; i
< argc
; i
++)
516 dbtofsb(sblock
, strtoull(argv
[i
], NULL
, 0));
518 wantedblk32
= malloc(sizeof(uint32_t) * wantedblksize
);
519 if (wantedblk32
== NULL
) {
523 memset(wantedblk32
, 0, sizeof(uint32_t) * wantedblksize
);
524 for (i
= 1; i
< argc
; i
++)
526 dbtofsb(sblock
, strtoull(argv
[i
], NULL
, 0));
528 findblk_numtofind
= wantedblksize
;
529 for (c
= 0; c
< sblock
->fs_ncg
; c
++) {
530 inum
= c
* sblock
->fs_ipg
;
531 getblk(&cgblk
, cgtod(sblock
, c
), sblock
->fs_cgsize
);
532 memcpy(cgp
, cgblk
.b_un
.b_cg
, sblock
->fs_cgsize
);
534 ffs_cg_swap(cgblk
.b_un
.b_cg
, cgp
, sblock
);
536 inosused
= cgp
->cg_initediblk
;
538 inosused
= sblock
->fs_ipg
;
539 for (; inosused
> 0; inum
++, inosused
--) {
542 if (is_ufs2
? compare_blk64(wantedblk64
,
543 ino_to_fsba(sblock
, inum
)) :
544 compare_blk32(wantedblk32
,
545 ino_to_fsba(sblock
, inum
))) {
546 printf("block %llu: inode block (%llu-%llu)\n",
547 (unsigned long long)fsbtodb(sblock
,
548 ino_to_fsba(sblock
, inum
)),
550 (inum
/ INOPB(sblock
)) * INOPB(sblock
),
552 (inum
/ INOPB(sblock
) + 1) * INOPB(sblock
));
554 if (findblk_numtofind
== 0)
558 curinode
= ginode(inum
);
559 switch (iswap16(DIP(curinode
, mode
)) & IFMT
) {
562 if (DIP(curinode
, blocks
) == 0)
567 uint64_t size
= iswap64(DIP(curinode
, size
));
569 size
< (uint64_t)sblock
->fs_maxsymlinklen
&&
570 DIP(curinode
, blocks
) == 0)
579 find_blks64(curinode
->dp2
.di_db
, NDADDR
,
581 find_blks32(curinode
->dp1
.di_db
, NDADDR
,
584 for (i
= 0; i
< NIADDR
; i
++) {
586 compare_blk64(wantedblk64
,
587 iswap64(curinode
->dp2
.di_ib
[i
])) :
588 compare_blk32(wantedblk32
,
589 iswap32(curinode
->dp1
.di_ib
[i
])))
590 if (founddatablk(is_ufs2
?
591 iswap64(curinode
->dp2
.di_ib
[i
]) :
592 iswap32(curinode
->dp1
.di_ib
[i
])))
594 if (is_ufs2
? (curinode
->dp2
.di_ib
[i
] != 0) :
595 (curinode
->dp1
.di_ib
[i
] != 0))
598 iswap64(curinode
->dp2
.di_ib
[i
]),
601 iswap32(curinode
->dp1
.di_ib
[i
]),
613 curinode
= ginode(curinum
);
618 compare_blk32(uint32_t *wantedblk
, uint32_t curblk
)
621 for (i
= 0; i
< wantedblksize
; i
++) {
622 if (wantedblk
[i
] != 0 && wantedblk
[i
] == curblk
) {
631 compare_blk64(uint64_t *wantedblk
, uint64_t curblk
)
634 for (i
= 0; i
< wantedblksize
; i
++) {
635 if (wantedblk
[i
] != 0 && wantedblk
[i
] == curblk
) {
644 founddatablk(uint64_t blk
)
646 printf("%llu: data block of inode %llu\n",
647 (unsigned long long)fsbtodb(sblock
, blk
),
648 (unsigned long long)curinum
);
650 if (findblk_numtofind
== 0)
656 find_blks32(uint32_t *buf
, int size
, uint32_t *wantedblk
)
659 for(blk
= 0; blk
< size
; blk
++) {
662 if (compare_blk32(wantedblk
, iswap32(buf
[blk
]))) {
663 if (founddatablk(iswap32(buf
[blk
])))
671 find_indirblks32(uint32_t blk
, int ind_level
, uint32_t *wantedblk
)
673 #define MAXNINDIR (MAXBSIZE / sizeof(uint32_t))
674 uint32_t idblk
[MAXNINDIR
];
677 bread(fsreadfd
, (char *)idblk
, fsbtodb(sblock
, blk
),
678 (int)sblock
->fs_bsize
);
679 if (ind_level
<= 0) {
680 if (find_blks32(idblk
,
681 sblock
->fs_bsize
/ sizeof(uint32_t), wantedblk
))
685 for (i
= 0; i
< sblock
->fs_bsize
/ sizeof(uint32_t); i
++) {
686 if (compare_blk32(wantedblk
, iswap32(idblk
[i
]))) {
687 if (founddatablk(iswap32(idblk
[i
])))
691 if (find_indirblks32(iswap32(idblk
[i
]),
692 ind_level
, wantedblk
))
702 find_blks64(uint64_t *buf
, int size
, uint64_t *wantedblk
)
705 for(blk
= 0; blk
< size
; blk
++) {
708 if (compare_blk64(wantedblk
, iswap64(buf
[blk
]))) {
709 if (founddatablk(iswap64(buf
[blk
])))
717 find_indirblks64(uint64_t blk
, int ind_level
, uint64_t *wantedblk
)
719 #define MAXNINDIR (MAXBSIZE / sizeof(uint64_t))
720 uint64_t idblk
[MAXNINDIR
];
723 bread(fsreadfd
, (char *)idblk
, fsbtodb(sblock
, blk
),
724 (int)sblock
->fs_bsize
);
725 if (ind_level
<= 0) {
726 if (find_blks64(idblk
,
727 sblock
->fs_bsize
/ sizeof(uint64_t), wantedblk
))
731 for (i
= 0; i
< sblock
->fs_bsize
/ sizeof(uint64_t); i
++) {
732 if (compare_blk64(wantedblk
, iswap64(idblk
[i
]))) {
733 if (founddatablk(iswap64(idblk
[i
])))
737 if (find_indirblks64(iswap64(idblk
[i
]),
738 ind_level
, wantedblk
))
747 #define CHARS_PER_LINES 70
750 print_blks32(int32_t *buf
, int size
, uint64_t *blknum
)
753 char prbuf
[CHARS_PER_LINES
+1];
757 for(blk
= 0; blk
< size
; blk
++, (*blknum
)++) {
760 snprintf(prbuf
, CHARS_PER_LINES
, "%d ", iswap32(buf
[blk
]));
761 if ((chars
+ strlen(prbuf
)) > CHARS_PER_LINES
) {
766 printf("%" PRIu64
": ", *blknum
);
768 chars
+= strlen(prbuf
);
774 print_blks64(int64_t *buf
, int size
, uint64_t *blknum
)
777 char prbuf
[CHARS_PER_LINES
+1];
781 for(blk
= 0; blk
< size
; blk
++, (*blknum
)++) {
784 snprintf(prbuf
, CHARS_PER_LINES
, "%lld ",
785 (long long)iswap64(buf
[blk
]));
786 if ((chars
+ strlen(prbuf
)) > CHARS_PER_LINES
) {
791 printf("%" PRIu64
": ", *blknum
);
793 chars
+= strlen(prbuf
);
798 #undef CHARS_PER_LINES
801 print_indirblks32(uint32_t blk
, int ind_level
, uint64_t *blknum
)
803 #define MAXNINDIR (MAXBSIZE / sizeof(int32_t))
804 const int ptrperblk_shift
= sblock
->fs_bshift
- 2;
805 const int ptrperblk
= 1 << ptrperblk_shift
;
806 int32_t idblk
[MAXNINDIR
];
810 *blknum
+= (uint64_t)ptrperblk
<< (ptrperblk_shift
* ind_level
);
814 printf("Indirect block %lld (level %d):\n", (long long)blk
,
816 bread(fsreadfd
, (char *)idblk
, fsbtodb(sblock
, blk
),
817 (int)sblock
->fs_bsize
);
818 if (ind_level
<= 0) {
819 print_blks32(idblk
, ptrperblk
, blknum
);
822 for (i
= 0; i
< ptrperblk
; i
++)
823 print_indirblks32(iswap32(idblk
[i
]), ind_level
, blknum
);
829 print_indirblks64(uint64_t blk
, int ind_level
, uint64_t *blknum
)
831 #define MAXNINDIR (MAXBSIZE / sizeof(int64_t))
832 const int ptrperblk_shift
= sblock
->fs_bshift
- 3;
833 const int ptrperblk
= 1 << ptrperblk_shift
;
834 int64_t idblk
[MAXNINDIR
];
838 *blknum
+= (uint64_t)ptrperblk
<< (ptrperblk_shift
* ind_level
);
842 printf("Indirect block %lld (level %d):\n", (long long)blk
,
844 bread(fsreadfd
, (char *)idblk
, fsbtodb(sblock
, blk
),
845 (int)sblock
->fs_bsize
);
846 if (ind_level
<= 0) {
847 print_blks64(idblk
, ptrperblk
, blknum
);
850 for (i
= 0; i
< ptrperblk
; i
++)
851 print_indirblks64(iswap64(idblk
[i
]), ind_level
, blknum
);
859 struct inodesc idesc
;
861 if (!checkactivedir())
863 idesc
.id_number
= curinum
;
864 idesc
.id_func
= findino
;
865 idesc
.id_name
= name
;
866 idesc
.id_type
= DATA
;
867 idesc
.id_fix
= IGNORE
;
868 if (ckinode(curinode
, &idesc
) & FOUND
) {
869 curinum
= idesc
.id_parent
;
870 curinode
= ginode(curinum
);
874 warnx("name `%s' not found in current inode directory", name
);
879 CMDFUNCSTART(focusname
)
888 if (argv
[1][0] == '/') {
890 curinode
= ginode(ROOTINO
);
892 if (!checkactivedir())
895 for (p
= argv
[1]; p
!= NULL
;) {
896 while ((val
= strsep(&p
, "/")) != NULL
&& *val
== '\0');
898 printf("component `%s': ", val
);
900 if (!dolookup(val
)) {
901 curinode
= ginode(curinum
);
917 if (!checkactivedir())
919 rval
= makeentry(curinum
, inum
, argv
[2]);
921 printf("Ino %llu entered as `%s'\n", (unsigned long long)inum
,
924 printf("could not enter name? weird.\n");
925 curinode
= ginode(curinum
);
933 if (!checkactivedir())
935 rval
= changeino(curinum
, argv
[1], 0);
936 if (rval
& ALTERED
) {
937 printf("Name `%s' removed\n", argv
[1]);
940 printf("could not remove name? weird.\n");
945 static long slotcount
, desired
;
948 chinumfunc(struct inodesc
*idesc
)
950 struct direct
*dirp
= idesc
->id_dirp
;
952 if (slotcount
++ == desired
) {
953 dirp
->d_ino
= iswap32(idesc
->id_parent
);
954 return STOP
| ALTERED
| FOUND
;
963 struct inodesc idesc
;
966 if (!checkactivedir())
970 desired
= strtol(argv
[1], &cp
, 0);
971 if (cp
== argv
[1] || *cp
!= '\0' || desired
< 0) {
972 printf("invalid slot number `%s'\n", argv
[1]);
975 idesc
.id_number
= curinum
;
976 idesc
.id_func
= chinumfunc
;
977 idesc
.id_fix
= IGNORE
;
978 idesc
.id_type
= DATA
;
979 idesc
.id_parent
= inum
; /* XXX convenient hiding place */
981 if (ckinode(curinode
, &idesc
) & FOUND
)
984 warnx("no %sth slot in current directory", argv
[1]);
990 chnamefunc(struct inodesc
*idesc
)
992 struct direct
*dirp
= idesc
->id_dirp
;
993 struct direct testdir
;
995 if (slotcount
++ == desired
) {
997 testdir
.d_namlen
= strlen(idesc
->id_name
);
998 if (DIRSIZ(NEWDIRFMT
, &testdir
, 0) <= iswap16(dirp
->d_reclen
)) {
999 dirp
->d_namlen
= testdir
.d_namlen
;
1000 strlcpy(dirp
->d_name
, idesc
->id_name
,
1001 sizeof(dirp
->d_name
));
1002 return STOP
| ALTERED
| FOUND
;
1004 return STOP
| FOUND
; /* won't fit, so give up */
1009 CMDFUNCSTART(chname
)
1013 struct inodesc idesc
;
1016 if (!checkactivedir())
1019 desired
= strtoul(argv
[1], &cp
, 0);
1020 if (cp
== argv
[1] || *cp
!= '\0') {
1021 printf("invalid slot number `%s'\n", argv
[1]);
1024 idesc
.id_number
= curinum
;
1025 idesc
.id_func
= chnamefunc
;
1026 idesc
.id_fix
= IGNORE
;
1027 idesc
.id_type
= DATA
;
1028 idesc
.id_name
= argv
[2];
1030 rval
= ckinode(curinode
, &idesc
);
1031 if ((rval
& (FOUND
| ALTERED
)) == (FOUND
| ALTERED
))
1035 warnx("new name `%s' does not fit in slot %s",
1039 warnx("no %sth slot in current directory", argv
[1]);
1044 static struct typemap
{
1045 const char *typename
;
1050 { "socket", IFSOCK
},
1054 CMDFUNCSTART(newtype
)
1062 mode
= iswap16(DIP(curinode
, mode
));
1064 for (tp
= typenamemap
;
1065 tp
< &typenamemap
[sizeof(typenamemap
) / sizeof(*typenamemap
)];
1067 if (!strcmp(argv
[1], tp
->typename
)) {
1068 printf("setting type to %s\n", tp
->typename
);
1069 type
= tp
->typebits
;
1073 if (tp
== &typenamemap
[sizeof(typenamemap
) / sizeof(*typenamemap
)]) {
1074 warnx("type `%s' not known", argv
[1]);
1075 warnx("try one of `file', `dir', `socket', `fifo'");
1078 DIP_SET(curinode
, mode
, iswap16((mode
& ~IFMT
) | type
));
1084 CMDFUNCSTART(chmode
)
1093 modebits
= strtol(argv
[1], &cp
, 8);
1094 if (cp
== argv
[1] || *cp
!= '\0') {
1095 warnx("bad modebits `%s'", argv
[1]);
1098 mode
= iswap16(DIP(curinode
, mode
));
1099 DIP_SET(curinode
, mode
, iswap16((mode
& ~07777) | modebits
));
1113 len
= strtol(argv
[1], &cp
, 0);
1114 if (cp
== argv
[1] || *cp
!= '\0' || len
< 0) {
1115 warnx("bad length '%s'", argv
[1]);
1118 DIP_SET(curinode
, size
, iswap64(len
));
1124 CMDFUNCSTART(chaflags
)
1132 flags
= strtoul(argv
[1], &cp
, 0);
1133 if (cp
== argv
[1] || *cp
!= '\0') {
1134 warnx("bad flags `%s'", argv
[1]);
1137 if (flags
> UINT_MAX
) {
1138 warnx("flags set beyond 32-bit range of field (0x%lx)",
1142 DIP_SET(curinode
, flags
, iswap32(flags
));
1156 gen
= strtol(argv
[1], &cp
, 0);
1157 if (cp
== argv
[1] || *cp
!= '\0') {
1158 warnx("bad gen `%s'", argv
[1]);
1161 if (gen
> INT_MAX
|| gen
< INT_MIN
) {
1162 warnx("gen set beyond 32-bit range of field (0x%lx)", gen
);
1165 DIP_SET(curinode
, gen
, iswap32(gen
));
1171 CMDFUNCSTART(linkcount
)
1179 lcnt
= strtol(argv
[1], &cp
, 0);
1180 if (cp
== argv
[1] || *cp
!= '\0') {
1181 warnx("bad link count `%s'", argv
[1]);
1184 if (lcnt
> USHRT_MAX
|| lcnt
< 0) {
1185 warnx("max link count is %d", USHRT_MAX
);
1188 DIP_SET(curinode
, nlink
, iswap16(lcnt
));
1194 CMDFUNCSTART(chowner
)
1203 uid
= strtoul(argv
[1], &cp
, 0);
1204 if (cp
== argv
[1] || *cp
!= '\0') {
1205 /* try looking up name */
1206 if ((pwd
= getpwnam(argv
[1])) != 0) {
1209 warnx("bad uid `%s'", argv
[1]);
1213 if (!is_ufs2
&& sblock
->fs_old_inodefmt
< FS_44INODEFMT
)
1214 curinode
->dp1
.di_ouid
= iswap32(uid
);
1216 DIP_SET(curinode
, uid
, iswap32(uid
));
1222 CMDFUNCSTART(chgroup
)
1231 gid
= strtoul(argv
[1], &cp
, 0);
1232 if (cp
== argv
[1] || *cp
!= '\0') {
1233 if ((grp
= getgrnam(argv
[1])) != 0) {
1236 warnx("bad gid `%s'", argv
[1]);
1240 if (sblock
->fs_old_inodefmt
< FS_44INODEFMT
)
1241 curinode
->dp1
.di_ogid
= iswap32(gid
);
1243 DIP_SET(curinode
, gid
, iswap32(gid
));
1250 dotime(char *name
, int32_t *rsec
, int32_t *rnsec
)
1256 p
= strchr(name
, '.');
1259 nsec
= strtoul(++p
, &val
, 0);
1260 if (val
== p
|| *val
!= '\0' || nsec
>= 1000000000 || nsec
< 0) {
1261 warnx("invalid nanoseconds");
1266 if (strlen(name
) != 14) {
1268 warnx("date format: YYYYMMDDHHMMSS[.nsec]");
1271 for (p
= name
; *p
; p
++)
1272 if (*p
< '0' || *p
> '9')
1276 #define VAL() ((*p++) - '0')
1278 t
.tm_year
= VAL() + t
.tm_year
* 10;
1279 t
.tm_year
= VAL() + t
.tm_year
* 10;
1280 t
.tm_year
= VAL() + t
.tm_year
* 10 - 1900;
1282 t
.tm_mon
= VAL() + t
.tm_mon
* 10 - 1;
1284 t
.tm_mday
= VAL() + t
.tm_mday
* 10;
1286 t
.tm_hour
= VAL() + t
.tm_hour
* 10;
1288 t
.tm_min
= VAL() + t
.tm_min
* 10;
1290 t
.tm_sec
= VAL() + t
.tm_sec
* 10;
1295 warnx("date/time out of range");
1298 *rsec
= iswap32(sec
);
1299 *rnsec
= iswap32(nsec
);
1303 CMDFUNCSTART(chmtime
)
1307 if (dotime(argv
[1], &rsec
, &nsec
))
1309 DIP_SET(curinode
, mtime
, rsec
);
1310 DIP_SET(curinode
, mtimensec
, nsec
);
1316 CMDFUNCSTART(chatime
)
1320 if (dotime(argv
[1], &rsec
, &nsec
))
1322 DIP_SET(curinode
, atime
, rsec
);
1323 DIP_SET(curinode
, atimensec
, nsec
);
1329 CMDFUNCSTART(chctime
)
1333 if (dotime(argv
[1], &rsec
, &nsec
))
1335 DIP_SET(curinode
, ctime
, rsec
);
1336 DIP_SET(curinode
, ctimensec
, nsec
);