| @@ -1,1141 +1,1141 @@ | | | @@ -1,1141 +1,1141 @@ |
1 | /* $NetBSD: fsdb.c,v 1.40 2011/06/09 19:57:53 christos Exp $ */ | | 1 | /* $NetBSD: fsdb.c,v 1.41 2011/06/09 21:23:30 christos Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 1996 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 1996 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by John T. Kohl. | | 8 | * by John T. Kohl. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 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 | | 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 | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 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 | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 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 | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | #include <sys/cdefs.h> | | 32 | #include <sys/cdefs.h> |
33 | #ifndef lint | | 33 | #ifndef lint |
34 | __RCSID("$NetBSD: fsdb.c,v 1.40 2011/06/09 19:57:53 christos Exp $"); | | 34 | __RCSID("$NetBSD: fsdb.c,v 1.41 2011/06/09 21:23:30 christos Exp $"); |
35 | #endif /* not lint */ | | 35 | #endif /* not lint */ |
36 | | | 36 | |
37 | #include <sys/types.h> | | 37 | #include <sys/types.h> |
38 | #include <sys/stat.h> | | 38 | #include <sys/stat.h> |
39 | #include <sys/param.h> | | 39 | #include <sys/param.h> |
40 | #include <sys/time.h> | | 40 | #include <sys/time.h> |
41 | #include <sys/mount.h> | | 41 | #include <sys/mount.h> |
42 | #include <ctype.h> | | 42 | #include <ctype.h> |
43 | #include <fcntl.h> | | 43 | #include <fcntl.h> |
44 | #include <grp.h> | | 44 | #include <grp.h> |
45 | #include <histedit.h> | | 45 | #include <histedit.h> |
46 | #include <limits.h> | | 46 | #include <limits.h> |
47 | #include <pwd.h> | | 47 | #include <pwd.h> |
48 | #include <stdio.h> | | 48 | #include <stdio.h> |
49 | #include <stdlib.h> | | 49 | #include <stdlib.h> |
50 | #include <string.h> | | 50 | #include <string.h> |
51 | #include <time.h> | | 51 | #include <time.h> |
52 | #include <unistd.h> | | 52 | #include <unistd.h> |
53 | #include <err.h> | | 53 | #include <err.h> |
54 | | | 54 | |
55 | #include <ufs/ufs/dinode.h> | | 55 | #include <ufs/ufs/dinode.h> |
56 | #include <ufs/ufs/dir.h> | | 56 | #include <ufs/ufs/dir.h> |
57 | #include <ufs/ffs/fs.h> | | 57 | #include <ufs/ffs/fs.h> |
58 | #include <ufs/ffs/ffs_extern.h> | | 58 | #include <ufs/ffs/ffs_extern.h> |
59 | | | 59 | |
60 | #include "fsdb.h" | | 60 | #include "fsdb.h" |
61 | #include "fsck.h" | | 61 | #include "fsck.h" |
62 | #include "extern.h" | | 62 | #include "extern.h" |
63 | | | 63 | |
64 | static void usage(void); | | 64 | static void usage(void); |
65 | static int cmdloop(void); | | 65 | static int cmdloop(void); |
66 | static char *prompt(EditLine *); | | 66 | static char *prompt(EditLine *); |
67 | static int scannames(struct inodesc *); | | 67 | static int scannames(struct inodesc *); |
68 | static int dolookup(char *); | | 68 | static int dolookup(char *); |
69 | static int chinumfunc(struct inodesc *); | | 69 | static int chinumfunc(struct inodesc *); |
70 | static int chnamefunc(struct inodesc *); | | 70 | static int chnamefunc(struct inodesc *); |
71 | static int dotime(char *, int32_t *, int32_t *); | | 71 | static int dotime(char *, int32_t *, int32_t *); |
72 | static void print_blks32(int32_t *buf, int size, uint64_t *blknum); | | 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); | | 73 | static void print_blks64(int64_t *buf, int size, uint64_t *blknum); |
74 | static void print_indirblks32(uint32_t blk, int ind_level, | | 74 | static void print_indirblks32(uint32_t blk, int ind_level, |
75 | uint64_t *blknum); | | 75 | uint64_t *blknum); |
76 | static void print_indirblks64(uint64_t blk, int ind_level, | | 76 | static void print_indirblks64(uint64_t blk, int ind_level, |
77 | uint64_t *blknum); | | 77 | uint64_t *blknum); |
78 | static int compare_blk32(uint32_t *, uint32_t); | | 78 | static int compare_blk32(uint32_t *, uint32_t); |
79 | static int compare_blk64(uint64_t *, uint64_t); | | 79 | static int compare_blk64(uint64_t *, uint64_t); |
80 | static int founddatablk(uint64_t); | | 80 | static int founddatablk(uint64_t); |
81 | static int find_blks32(uint32_t *buf, int size, uint32_t *blknum); | | 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); | | 82 | static int find_blks64(uint64_t *buf, int size, uint64_t *blknum); |
83 | static int find_indirblks32(uint32_t blk, int ind_level, | | 83 | static int find_indirblks32(uint32_t blk, int ind_level, |
84 | uint32_t *blknum); | | 84 | uint32_t *blknum); |
85 | static int find_indirblks64(uint64_t blk, int ind_level, | | 85 | static int find_indirblks64(uint64_t blk, int ind_level, |
86 | uint64_t *blknum); | | 86 | uint64_t *blknum); |
87 | | | 87 | |
88 | union dinode *curinode; | | 88 | union dinode *curinode; |
89 | ino_t curinum; | | 89 | ino_t curinum; |
90 | | | 90 | |
91 | static void | | 91 | static void |
92 | usage(void) | | 92 | usage(void) |
93 | { | | 93 | { |
94 | errx(1, "usage: %s [-dFn] -f <fsname>", getprogname()); | | 94 | errx(1, "usage: %s [-dFn] -f <fsname>", getprogname()); |
95 | } | | 95 | } |
96 | /* | | 96 | /* |
97 | * We suck in lots of fsck code, and just pick & choose the stuff we want. | | 97 | * We suck in lots of fsck code, and just pick & choose the stuff we want. |
98 | * | | 98 | * |
99 | * fsreadfd is set up to read from the file system, fswritefd to write to | | 99 | * fsreadfd is set up to read from the file system, fswritefd to write to |
100 | * the file system. | | 100 | * the file system. |
101 | */ | | 101 | */ |
102 | int | | 102 | int |
103 | main(int argc, char *argv[]) | | 103 | main(int argc, char *argv[]) |
104 | { | | 104 | { |
105 | int ch, rval; | | 105 | int ch, rval; |
106 | char *fsys = NULL; | | 106 | char *fsys = NULL; |
107 | | | 107 | |
108 | forceimage = 0; | | 108 | forceimage = 0; |
109 | debug = 0; | | 109 | debug = 0; |
110 | isappleufs = 0; | | 110 | isappleufs = 0; |
111 | while ((ch = getopt(argc, argv, "dFf:n")) != -1) { | | 111 | while ((ch = getopt(argc, argv, "dFf:n")) != -1) { |
112 | switch (ch) { | | 112 | switch (ch) { |
113 | case 'd': | | 113 | case 'd': |
114 | debug++; | | 114 | debug++; |
115 | break; | | 115 | break; |
116 | case 'F': | | 116 | case 'F': |
117 | forceimage = 1; | | 117 | forceimage = 1; |
118 | break; | | 118 | break; |
119 | case 'f': | | 119 | case 'f': |
120 | fsys = optarg; | | 120 | fsys = optarg; |
121 | break; | | 121 | break; |
122 | case 'n': | | 122 | case 'n': |
123 | nflag++; | | 123 | nflag++; |
124 | break; | | 124 | break; |
125 | default: | | 125 | default: |
126 | usage(); | | 126 | usage(); |
127 | } | | 127 | } |
128 | } | | 128 | } |
129 | if (fsys == NULL) | | 129 | if (fsys == NULL) |
130 | usage(); | | 130 | usage(); |
131 | endian = 0; | | 131 | endian = 0; |
132 | if (setup(fsys, fsys) <= 0) | | 132 | if (setup(fsys, fsys) <= 0) |
133 | errx(1, "cannot set up file system `%s'", fsys); | | 133 | errx(1, "cannot set up file system `%s'", fsys); |
134 | printf("Editing file system `%s'\nLast Mounted on %s\n", fsys, | | 134 | printf("Editing file system `%s'\nLast Mounted on %s\n", fsys, |
135 | sblock->fs_fsmnt); | | 135 | sblock->fs_fsmnt); |
136 | rval = cmdloop(); | | 136 | rval = cmdloop(); |
137 | if (nflag) | | 137 | if (nflag) |
138 | exit(rval); | | 138 | exit(rval); |
139 | sblock->fs_clean = 0; /* mark it dirty */ | | 139 | sblock->fs_clean = 0; /* mark it dirty */ |
140 | sbdirty(); | | 140 | sbdirty(); |
141 | markclean = 0; | | 141 | markclean = 0; |
142 | ckfini(); | | 142 | ckfini(1); |
143 | printf("*** FILE SYSTEM MARKED DIRTY\n"); | | 143 | printf("*** FILE SYSTEM MARKED DIRTY\n"); |
144 | printf("*** BE SURE TO RUN FSCK TO CLEAN UP ANY DAMAGE\n"); | | 144 | printf("*** BE SURE TO RUN FSCK TO CLEAN UP ANY DAMAGE\n"); |
145 | printf("*** IF IT WAS MOUNTED, RE-MOUNT WITH -u -o reload\n"); | | 145 | printf("*** IF IT WAS MOUNTED, RE-MOUNT WITH -u -o reload\n"); |
146 | exit(rval); | | 146 | exit(rval); |
147 | } | | 147 | } |
148 | | | 148 | |
149 | #define CMDFUNC(func) static int func (int argc, char *argv[]) | | 149 | #define CMDFUNC(func) static int func (int argc, char *argv[]) |
150 | #define CMDFUNCSTART(func) static int func(argc, argv) \ | | 150 | #define CMDFUNCSTART(func) static int func(argc, argv) \ |
151 | int argc; \ | | 151 | int argc; \ |
152 | char *argv[]; | | 152 | char *argv[]; |
153 | | | 153 | |
154 | CMDFUNC(helpfn); | | 154 | CMDFUNC(helpfn); |
155 | CMDFUNC(focus); /* focus on inode */ | | 155 | CMDFUNC(focus); /* focus on inode */ |
156 | CMDFUNC(active); /* print active inode */ | | 156 | CMDFUNC(active); /* print active inode */ |
157 | CMDFUNC(focusname); /* focus by name */ | | 157 | CMDFUNC(focusname); /* focus by name */ |
158 | CMDFUNC(zapi); /* clear inode */ | | 158 | CMDFUNC(zapi); /* clear inode */ |
159 | CMDFUNC(uplink); /* incr link */ | | 159 | CMDFUNC(uplink); /* incr link */ |
160 | CMDFUNC(downlink); /* decr link */ | | 160 | CMDFUNC(downlink); /* decr link */ |
161 | CMDFUNC(linkcount); /* set link count */ | | 161 | CMDFUNC(linkcount); /* set link count */ |
162 | CMDFUNC(quit); /* quit */ | | 162 | CMDFUNC(quit); /* quit */ |
163 | CMDFUNC(ls); /* list directory */ | | 163 | CMDFUNC(ls); /* list directory */ |
164 | CMDFUNC(blks); /* list blocks */ | | 164 | CMDFUNC(blks); /* list blocks */ |
165 | CMDFUNC(findblk); /* find block */ | | 165 | CMDFUNC(findblk); /* find block */ |
166 | CMDFUNC(rm); /* remove name */ | | 166 | CMDFUNC(rm); /* remove name */ |
167 | CMDFUNC(ln); /* add name */ | | 167 | CMDFUNC(ln); /* add name */ |
168 | CMDFUNC(newtype); /* change type */ | | 168 | CMDFUNC(newtype); /* change type */ |
169 | CMDFUNC(chmode); /* change mode */ | | 169 | CMDFUNC(chmode); /* change mode */ |
170 | CMDFUNC(chlen); /* change length */ | | 170 | CMDFUNC(chlen); /* change length */ |
171 | CMDFUNC(chaflags); /* change flags */ | | 171 | CMDFUNC(chaflags); /* change flags */ |
172 | CMDFUNC(chgen); /* change generation */ | | 172 | CMDFUNC(chgen); /* change generation */ |
173 | CMDFUNC(chowner); /* change owner */ | | 173 | CMDFUNC(chowner); /* change owner */ |
174 | CMDFUNC(chgroup); /* Change group */ | | 174 | CMDFUNC(chgroup); /* Change group */ |
175 | CMDFUNC(back); /* pop back to last ino */ | | 175 | CMDFUNC(back); /* pop back to last ino */ |
176 | CMDFUNC(chmtime); /* Change mtime */ | | 176 | CMDFUNC(chmtime); /* Change mtime */ |
177 | CMDFUNC(chctime); /* Change ctime */ | | 177 | CMDFUNC(chctime); /* Change ctime */ |
178 | CMDFUNC(chatime); /* Change atime */ | | 178 | CMDFUNC(chatime); /* Change atime */ |
179 | CMDFUNC(chinum); /* Change inode # of dirent */ | | 179 | CMDFUNC(chinum); /* Change inode # of dirent */ |
180 | CMDFUNC(chname); /* Change dirname of dirent */ | | 180 | CMDFUNC(chname); /* Change dirname of dirent */ |
181 | | | 181 | |
182 | static struct cmdtable cmds[] = { | | 182 | static struct cmdtable cmds[] = { |
183 | {"help", "Print out help", 1, 1, helpfn}, | | 183 | {"help", "Print out help", 1, 1, helpfn}, |
184 | {"?", "Print out help", 1, 1, helpfn}, | | 184 | {"?", "Print out help", 1, 1, helpfn}, |
185 | {"inode", "Set active inode to INUM", 2, 2, focus}, | | 185 | {"inode", "Set active inode to INUM", 2, 2, focus}, |
186 | {"clri", "Clear inode INUM", 2, 2, zapi}, | | 186 | {"clri", "Clear inode INUM", 2, 2, zapi}, |
187 | {"lookup", "Set active inode by looking up NAME", 2, 2, focusname}, | | 187 | {"lookup", "Set active inode by looking up NAME", 2, 2, focusname}, |
188 | {"cd", "Set active inode by looking up NAME", 2, 2, focusname}, | | 188 | {"cd", "Set active inode by looking up NAME", 2, 2, focusname}, |
189 | {"back", "Go to previous active inode", 1, 1, back}, | | 189 | {"back", "Go to previous active inode", 1, 1, back}, |
190 | {"active", "Print active inode", 1, 1, active}, | | 190 | {"active", "Print active inode", 1, 1, active}, |
191 | {"print", "Print active inode", 1, 1, active}, | | 191 | {"print", "Print active inode", 1, 1, active}, |
192 | {"uplink", "Increment link count", 1, 1, uplink}, | | 192 | {"uplink", "Increment link count", 1, 1, uplink}, |
193 | {"downlink", "Decrement link count", 1, 1, downlink}, | | 193 | {"downlink", "Decrement link count", 1, 1, downlink}, |
194 | {"linkcount", "Set link count to COUNT", 2, 2, linkcount}, | | 194 | {"linkcount", "Set link count to COUNT", 2, 2, linkcount}, |
195 | {"ls", "List current inode as directory", 1, 1, ls}, | | 195 | {"ls", "List current inode as directory", 1, 1, ls}, |
196 | {"blks", "List current inode's data blocks", 1, 1, blks}, | | 196 | {"blks", "List current inode's data blocks", 1, 1, blks}, |
197 | {"findblk", "Find inode owning disk block(s)", 2, 33, findblk}, | | 197 | {"findblk", "Find inode owning disk block(s)", 2, 33, findblk}, |
198 | {"rm", "Remove NAME from current inode directory", 2, 2, rm}, | | 198 | {"rm", "Remove NAME from current inode directory", 2, 2, rm}, |
199 | {"del", "Remove NAME from current inode directory", 2, 2, rm}, | | 199 | {"del", "Remove NAME from current inode directory", 2, 2, rm}, |
200 | {"ln", "Hardlink INO into current inode directory as NAME", 3, 3, ln}, | | 200 | {"ln", "Hardlink INO into current inode directory as NAME", 3, 3, ln}, |
201 | {"chinum", "Change dir entry number INDEX to INUM", 3, 3, chinum}, | | 201 | {"chinum", "Change dir entry number INDEX to INUM", 3, 3, chinum}, |
202 | {"chname", "Change dir entry number INDEX to NAME", 3, 3, chname}, | | 202 | {"chname", "Change dir entry number INDEX to NAME", 3, 3, chname}, |
203 | {"chtype", "Change type of current inode to TYPE", 2, 2, newtype}, | | 203 | {"chtype", "Change type of current inode to TYPE", 2, 2, newtype}, |
204 | {"chmod", "Change mode of current inode to MODE", 2, 2, chmode}, | | 204 | {"chmod", "Change mode of current inode to MODE", 2, 2, chmode}, |
205 | {"chown", "Change owner of current inode to OWNER", 2, 2, chowner}, | | 205 | {"chown", "Change owner of current inode to OWNER", 2, 2, chowner}, |
206 | {"chlen", "Change length of current inode to LENGTH", 2, 2, chlen}, | | 206 | {"chlen", "Change length of current inode to LENGTH", 2, 2, chlen}, |
207 | {"chgrp", "Change group of current inode to GROUP", 2, 2, chgroup}, | | 207 | {"chgrp", "Change group of current inode to GROUP", 2, 2, chgroup}, |
208 | {"chflags", "Change flags of current inode to FLAGS", 2, 2, chaflags}, | | 208 | {"chflags", "Change flags of current inode to FLAGS", 2, 2, chaflags}, |
209 | {"chgen", "Change generation number of current inode to GEN", 2, 2, | | 209 | {"chgen", "Change generation number of current inode to GEN", 2, 2, |
210 | chgen}, | | 210 | chgen}, |
211 | {"mtime", "Change mtime of current inode to MTIME", 2, 2, chmtime}, | | 211 | {"mtime", "Change mtime of current inode to MTIME", 2, 2, chmtime}, |
212 | {"ctime", "Change ctime of current inode to CTIME", 2, 2, chctime}, | | 212 | {"ctime", "Change ctime of current inode to CTIME", 2, 2, chctime}, |
213 | {"atime", "Change atime of current inode to ATIME", 2, 2, chatime}, | | 213 | {"atime", "Change atime of current inode to ATIME", 2, 2, chatime}, |
214 | {"quit", "Exit", 1, 1, quit}, | | 214 | {"quit", "Exit", 1, 1, quit}, |
215 | {"q", "Exit", 1, 1, quit}, | | 215 | {"q", "Exit", 1, 1, quit}, |
216 | {"exit", "Exit", 1, 1, quit}, | | 216 | {"exit", "Exit", 1, 1, quit}, |
217 | { .cmd = NULL}, | | 217 | { .cmd = NULL}, |
218 | }; | | 218 | }; |
219 | | | 219 | |
220 | static int | | 220 | static int |
221 | helpfn(int argc, char *argv[]) | | 221 | helpfn(int argc, char *argv[]) |
222 | { | | 222 | { |
223 | struct cmdtable *cmdtp; | | 223 | struct cmdtable *cmdtp; |
224 | | | 224 | |
225 | printf("Commands are:\n%-10s %5s %5s %s\n", | | 225 | printf("Commands are:\n%-10s %5s %5s %s\n", |
226 | "command", "min argc", "max argc", "what"); | | 226 | "command", "min argc", "max argc", "what"); |
227 | | | 227 | |
228 | for (cmdtp = cmds; cmdtp->cmd; cmdtp++) | | 228 | for (cmdtp = cmds; cmdtp->cmd; cmdtp++) |
229 | printf("%-10s %5u %5u %s\n", | | 229 | printf("%-10s %5u %5u %s\n", |
230 | cmdtp->cmd, cmdtp->minargc, cmdtp->maxargc, cmdtp->helptxt); | | 230 | cmdtp->cmd, cmdtp->minargc, cmdtp->maxargc, cmdtp->helptxt); |
231 | return 0; | | 231 | return 0; |
232 | } | | 232 | } |
233 | | | 233 | |
234 | static char * | | 234 | static char * |
235 | prompt(EditLine *el) | | 235 | prompt(EditLine *el) |
236 | { | | 236 | { |
237 | static char pstring[64]; | | 237 | static char pstring[64]; |
238 | snprintf(pstring, sizeof(pstring), "fsdb (inum: %llu)> ", | | 238 | snprintf(pstring, sizeof(pstring), "fsdb (inum: %llu)> ", |
239 | (unsigned long long)curinum); | | 239 | (unsigned long long)curinum); |
240 | return pstring; | | 240 | return pstring; |
241 | } | | 241 | } |
242 | | | 242 | |
243 | | | 243 | |
244 | static int | | 244 | static int |
245 | cmdloop(void) | | 245 | cmdloop(void) |
246 | { | | 246 | { |
247 | char *line; | | 247 | char *line; |
248 | const char *elline; | | 248 | const char *elline; |
249 | int cmd_argc, rval = 0, known; | | 249 | int cmd_argc, rval = 0, known; |
250 | #define scratch known | | 250 | #define scratch known |
251 | char **cmd_argv; | | 251 | char **cmd_argv; |
252 | struct cmdtable *cmdp; | | 252 | struct cmdtable *cmdp; |
253 | History *hist; | | 253 | History *hist; |
254 | HistEvent he; | | 254 | HistEvent he; |
255 | EditLine *elptr; | | 255 | EditLine *elptr; |
256 | | | 256 | |
257 | curinode = ginode(ROOTINO); | | 257 | curinode = ginode(ROOTINO); |
258 | curinum = ROOTINO; | | 258 | curinum = ROOTINO; |
259 | printactive(); | | 259 | printactive(); |
260 | | | 260 | |
261 | hist = history_init(); | | 261 | hist = history_init(); |
262 | history(hist, &he, H_SETSIZE, 100); /* 100 elt history buffer */ | | 262 | history(hist, &he, H_SETSIZE, 100); /* 100 elt history buffer */ |
263 | | | 263 | |
264 | elptr = el_init(getprogname(), stdin, stdout, stderr); | | 264 | elptr = el_init(getprogname(), stdin, stdout, stderr); |
265 | el_set(elptr, EL_EDITOR, "emacs"); | | 265 | el_set(elptr, EL_EDITOR, "emacs"); |
266 | el_set(elptr, EL_PROMPT, prompt); | | 266 | el_set(elptr, EL_PROMPT, prompt); |
267 | el_set(elptr, EL_HIST, history, hist); | | 267 | el_set(elptr, EL_HIST, history, hist); |
268 | el_source(elptr, NULL); | | 268 | el_source(elptr, NULL); |
269 | | | 269 | |
270 | while ((elline = el_gets(elptr, &scratch)) != NULL && scratch != 0) { | | 270 | while ((elline = el_gets(elptr, &scratch)) != NULL && scratch != 0) { |
271 | if (debug) | | 271 | if (debug) |
272 | printf("command `%s'\n", elline); | | 272 | printf("command `%s'\n", elline); |
273 | | | 273 | |
274 | history(hist, &he, H_ENTER, elline); | | 274 | history(hist, &he, H_ENTER, elline); |
275 | | | 275 | |
276 | line = strdup(elline); | | 276 | line = strdup(elline); |
277 | cmd_argv = crack(line, &cmd_argc); | | 277 | cmd_argv = crack(line, &cmd_argc); |
278 | if (cmd_argc) { | | 278 | if (cmd_argc) { |
279 | /* | | 279 | /* |
280 | * el_parse returns -1 to signal that it's not been | | 280 | * el_parse returns -1 to signal that it's not been |
281 | * handled internally. | | 281 | * handled internally. |
282 | */ | | 282 | */ |
283 | if (el_parse(elptr, cmd_argc, | | 283 | if (el_parse(elptr, cmd_argc, |
284 | (const char **)cmd_argv) != -1) | | 284 | (const char **)cmd_argv) != -1) |
285 | continue; | | 285 | continue; |
286 | known = 0; | | 286 | known = 0; |
287 | for (cmdp = cmds; cmdp->cmd; cmdp++) { | | 287 | for (cmdp = cmds; cmdp->cmd; cmdp++) { |
288 | if (!strcmp(cmdp->cmd, cmd_argv[0])) { | | 288 | if (!strcmp(cmdp->cmd, cmd_argv[0])) { |
289 | if (cmd_argc >= cmdp->minargc && | | 289 | if (cmd_argc >= cmdp->minargc && |
290 | cmd_argc <= cmdp->maxargc) | | 290 | cmd_argc <= cmdp->maxargc) |
291 | rval = | | 291 | rval = |
292 | (*cmdp->handler)(cmd_argc, | | 292 | (*cmdp->handler)(cmd_argc, |
293 | cmd_argv); | | 293 | cmd_argv); |
294 | else | | 294 | else |
295 | rval = argcount(cmdp, cmd_argc, | | 295 | rval = argcount(cmdp, cmd_argc, |
296 | cmd_argv); | | 296 | cmd_argv); |
297 | known = 1; | | 297 | known = 1; |
298 | break; | | 298 | break; |
299 | } | | 299 | } |
300 | } | | 300 | } |
301 | if (!known) | | 301 | if (!known) |
302 | warnx("unknown command `%s'", cmd_argv[0]), | | 302 | warnx("unknown command `%s'", cmd_argv[0]), |
303 | rval = 1; | | 303 | rval = 1; |
304 | } else | | 304 | } else |
305 | rval = 0; | | 305 | rval = 0; |
306 | free(line); | | 306 | free(line); |
307 | if (rval < 0) | | 307 | if (rval < 0) |
308 | return rval; | | 308 | return rval; |
309 | if (rval) | | 309 | if (rval) |
310 | warnx("rval was %d", rval); | | 310 | warnx("rval was %d", rval); |
311 | } | | 311 | } |
312 | el_end(elptr); | | 312 | el_end(elptr); |
313 | history_end(hist); | | 313 | history_end(hist); |
314 | return rval; | | 314 | return rval; |
315 | } | | 315 | } |
316 | | | 316 | |
317 | static ino_t ocurrent; | | 317 | static ino_t ocurrent; |
318 | | | 318 | |
319 | #define GETINUM(ac,inum) inum = strtoull(argv[ac], &cp, 0); \ | | 319 | #define GETINUM(ac,inum) inum = strtoull(argv[ac], &cp, 0); \ |
320 | if (inum < ROOTINO || inum >= maxino || cp == argv[ac] || *cp != '\0' ) { \ | | 320 | if (inum < ROOTINO || inum >= maxino || cp == argv[ac] || *cp != '\0' ) { \ |
321 | printf("inode %llu out of range; range is [%llu,%llu]\n", \ | | 321 | printf("inode %llu out of range; range is [%llu,%llu]\n", \ |
322 | (unsigned long long)inum, (unsigned long long)ROOTINO, \ | | 322 | (unsigned long long)inum, (unsigned long long)ROOTINO, \ |
323 | (unsigned long long)maxino); \ | | 323 | (unsigned long long)maxino); \ |
324 | return 1; \ | | 324 | return 1; \ |
325 | } | | 325 | } |
326 | | | 326 | |
327 | /* | | 327 | /* |
328 | * Focus on given inode number | | 328 | * Focus on given inode number |
329 | */ | | 329 | */ |
330 | CMDFUNCSTART(focus) | | 330 | CMDFUNCSTART(focus) |
331 | { | | 331 | { |
332 | ino_t inum; | | 332 | ino_t inum; |
333 | char *cp; | | 333 | char *cp; |
334 | | | 334 | |
335 | GETINUM(1, inum); | | 335 | GETINUM(1, inum); |
336 | curinode = ginode(inum); | | 336 | curinode = ginode(inum); |
337 | ocurrent = curinum; | | 337 | ocurrent = curinum; |
338 | curinum = inum; | | 338 | curinum = inum; |
339 | printactive(); | | 339 | printactive(); |
340 | return 0; | | 340 | return 0; |
341 | } | | 341 | } |
342 | | | 342 | |
343 | CMDFUNCSTART(back) | | 343 | CMDFUNCSTART(back) |
344 | { | | 344 | { |
345 | curinum = ocurrent; | | 345 | curinum = ocurrent; |
346 | curinode = ginode(curinum); | | 346 | curinode = ginode(curinum); |
347 | printactive(); | | 347 | printactive(); |
348 | return 0; | | 348 | return 0; |
349 | } | | 349 | } |
350 | | | 350 | |
351 | CMDFUNCSTART(zapi) | | 351 | CMDFUNCSTART(zapi) |
352 | { | | 352 | { |
353 | ino_t inum; | | 353 | ino_t inum; |
354 | union dinode *dp; | | 354 | union dinode *dp; |
355 | char *cp; | | 355 | char *cp; |
356 | | | 356 | |
357 | GETINUM(1, inum); | | 357 | GETINUM(1, inum); |
358 | dp = ginode(inum); | | 358 | dp = ginode(inum); |
359 | clearinode(dp); | | 359 | clearinode(dp); |
360 | inodirty(); | | 360 | inodirty(); |
361 | if (curinode) /* re-set after potential change */ | | 361 | if (curinode) /* re-set after potential change */ |
362 | curinode = ginode(curinum); | | 362 | curinode = ginode(curinum); |
363 | return 0; | | 363 | return 0; |
364 | } | | 364 | } |
365 | | | 365 | |
366 | CMDFUNCSTART(active) | | 366 | CMDFUNCSTART(active) |
367 | { | | 367 | { |
368 | printactive(); | | 368 | printactive(); |
369 | return 0; | | 369 | return 0; |
370 | } | | 370 | } |
371 | | | 371 | |
372 | CMDFUNCSTART(quit) | | 372 | CMDFUNCSTART(quit) |
373 | { | | 373 | { |
374 | return -1; | | 374 | return -1; |
375 | } | | 375 | } |
376 | | | 376 | |
377 | CMDFUNCSTART(uplink) | | 377 | CMDFUNCSTART(uplink) |
378 | { | | 378 | { |
379 | int16_t nlink; | | 379 | int16_t nlink; |
380 | | | 380 | |
381 | if (!checkactive()) | | 381 | if (!checkactive()) |
382 | return 1; | | 382 | return 1; |
383 | nlink = iswap16(DIP(curinode, nlink)); | | 383 | nlink = iswap16(DIP(curinode, nlink)); |
384 | nlink++; | | 384 | nlink++; |
385 | DIP_SET(curinode, nlink, iswap16(nlink)); | | 385 | DIP_SET(curinode, nlink, iswap16(nlink)); |
386 | printf("inode %llu link count now %d\n", (unsigned long long)curinum, | | 386 | printf("inode %llu link count now %d\n", (unsigned long long)curinum, |
387 | nlink); | | 387 | nlink); |
388 | inodirty(); | | 388 | inodirty(); |
389 | return 0; | | 389 | return 0; |
390 | } | | 390 | } |
391 | | | 391 | |
392 | CMDFUNCSTART(downlink) | | 392 | CMDFUNCSTART(downlink) |
393 | { | | 393 | { |
394 | int16_t nlink; | | 394 | int16_t nlink; |
395 | | | 395 | |
396 | if (!checkactive()) | | 396 | if (!checkactive()) |
397 | return 1; | | 397 | return 1; |
398 | nlink = iswap16(DIP(curinode, nlink)); | | 398 | nlink = iswap16(DIP(curinode, nlink)); |
399 | nlink--; | | 399 | nlink--; |
400 | DIP_SET(curinode, nlink, iswap16(nlink)); | | 400 | DIP_SET(curinode, nlink, iswap16(nlink)); |
401 | printf("inode %llu link count now %d\n", (unsigned long long)curinum, | | 401 | printf("inode %llu link count now %d\n", (unsigned long long)curinum, |
402 | nlink); | | 402 | nlink); |
403 | inodirty(); | | 403 | inodirty(); |
404 | return 0; | | 404 | return 0; |
405 | } | | 405 | } |
406 | | | 406 | |
407 | static const char *typename[] = { | | 407 | static const char *typename[] = { |
408 | "unknown", | | 408 | "unknown", |
409 | "fifo", | | 409 | "fifo", |
410 | "char special", | | 410 | "char special", |
411 | "unregistered #3", | | 411 | "unregistered #3", |
412 | "directory", | | 412 | "directory", |
413 | "unregistered #5", | | 413 | "unregistered #5", |
414 | "blk special", | | 414 | "blk special", |
415 | "unregistered #7", | | 415 | "unregistered #7", |
416 | "regular", | | 416 | "regular", |
417 | "unregistered #9", | | 417 | "unregistered #9", |
418 | "symlink", | | 418 | "symlink", |
419 | "unregistered #11", | | 419 | "unregistered #11", |
420 | "socket", | | 420 | "socket", |
421 | "unregistered #13", | | 421 | "unregistered #13", |
422 | "whiteout", | | 422 | "whiteout", |
423 | }; | | 423 | }; |
424 | | | 424 | |
425 | static int slot; | | 425 | static int slot; |
426 | | | 426 | |
427 | static int | | 427 | static int |
428 | scannames(struct inodesc *idesc) | | 428 | scannames(struct inodesc *idesc) |
429 | { | | 429 | { |
430 | struct direct *dirp = idesc->id_dirp; | | 430 | struct direct *dirp = idesc->id_dirp; |
431 | | | 431 | |
432 | printf("slot %d ino %d reclen %d: %s, `%.*s'\n", | | 432 | printf("slot %d ino %d reclen %d: %s, `%.*s'\n", |
433 | slot++, iswap32(dirp->d_ino), iswap16(dirp->d_reclen), | | 433 | slot++, iswap32(dirp->d_ino), iswap16(dirp->d_reclen), |
434 | typename[dirp->d_type], | | 434 | typename[dirp->d_type], |
435 | dirp->d_namlen, dirp->d_name); | | 435 | dirp->d_namlen, dirp->d_name); |
436 | return (KEEPON); | | 436 | return (KEEPON); |
437 | } | | 437 | } |
438 | | | 438 | |
439 | CMDFUNCSTART(ls) | | 439 | CMDFUNCSTART(ls) |
440 | { | | 440 | { |
441 | struct inodesc idesc; | | 441 | struct inodesc idesc; |
442 | checkactivedir(); /* let it go on anyway */ | | 442 | checkactivedir(); /* let it go on anyway */ |
443 | | | 443 | |
444 | slot = 0; | | 444 | slot = 0; |
445 | idesc.id_number = curinum; | | 445 | idesc.id_number = curinum; |
446 | idesc.id_func = scannames; | | 446 | idesc.id_func = scannames; |
447 | idesc.id_type = DATA; | | 447 | idesc.id_type = DATA; |
448 | idesc.id_fix = IGNORE; | | 448 | idesc.id_fix = IGNORE; |
449 | ckinode(curinode, &idesc); | | 449 | ckinode(curinode, &idesc); |
450 | curinode = ginode(curinum); | | 450 | curinode = ginode(curinum); |
451 | | | 451 | |
452 | return 0; | | 452 | return 0; |
453 | } | | 453 | } |
454 | | | 454 | |
455 | CMDFUNCSTART(blks) | | 455 | CMDFUNCSTART(blks) |
456 | { | | 456 | { |
457 | uint64_t blkno = 0; | | 457 | uint64_t blkno = 0; |
458 | int i, type; | | 458 | int i, type; |
459 | if (!curinode) { | | 459 | if (!curinode) { |
460 | warnx("no current inode"); | | 460 | warnx("no current inode"); |
461 | return 0; | | 461 | return 0; |
462 | } | | 462 | } |
463 | type = iswap16(DIP(curinode, mode)) & IFMT; | | 463 | type = iswap16(DIP(curinode, mode)) & IFMT; |
464 | if (type != IFDIR && type != IFREG) { | | 464 | if (type != IFDIR && type != IFREG) { |
465 | warnx("inode %llu not a file or directory", | | 465 | warnx("inode %llu not a file or directory", |
466 | (unsigned long long)curinum); | | 466 | (unsigned long long)curinum); |
467 | return 0; | | 467 | return 0; |
468 | } | | 468 | } |
469 | if (is_ufs2) { | | 469 | if (is_ufs2) { |
470 | printf("I=%llu %lld blocks\n", (unsigned long long)curinum, | | 470 | printf("I=%llu %lld blocks\n", (unsigned long long)curinum, |
471 | (long long)(iswap64(curinode->dp2.di_blocks))); | | 471 | (long long)(iswap64(curinode->dp2.di_blocks))); |
472 | } else { | | 472 | } else { |
473 | printf("I=%llu %d blocks\n", (unsigned long long)curinum, | | 473 | printf("I=%llu %d blocks\n", (unsigned long long)curinum, |
474 | iswap32(curinode->dp1.di_blocks)); | | 474 | iswap32(curinode->dp1.di_blocks)); |
475 | } | | 475 | } |
476 | printf("Direct blocks:\n"); | | 476 | printf("Direct blocks:\n"); |
477 | if (is_ufs2) | | 477 | if (is_ufs2) |
478 | print_blks64(curinode->dp2.di_db, NDADDR, &blkno); | | 478 | print_blks64(curinode->dp2.di_db, NDADDR, &blkno); |
479 | else | | 479 | else |
480 | print_blks32(curinode->dp1.di_db, NDADDR, &blkno); | | 480 | print_blks32(curinode->dp1.di_db, NDADDR, &blkno); |
481 | | | 481 | |
482 | if (is_ufs2) { | | 482 | if (is_ufs2) { |
483 | for (i = 0; i < NIADDR; i++) | | 483 | for (i = 0; i < NIADDR; i++) |
484 | print_indirblks64(iswap64(curinode->dp2.di_ib[i]), i, | | 484 | print_indirblks64(iswap64(curinode->dp2.di_ib[i]), i, |
485 | &blkno); | | 485 | &blkno); |
486 | } else { | | 486 | } else { |
487 | for (i = 0; i < NIADDR; i++) | | 487 | for (i = 0; i < NIADDR; i++) |
488 | print_indirblks32(iswap32(curinode->dp1.di_ib[i]), i, | | 488 | print_indirblks32(iswap32(curinode->dp1.di_ib[i]), i, |
489 | &blkno); | | 489 | &blkno); |
490 | } | | 490 | } |
491 | return 0; | | 491 | return 0; |
492 | } | | 492 | } |
493 | | | 493 | |
494 | static int findblk_numtofind; | | 494 | static int findblk_numtofind; |
495 | static int wantedblksize; | | 495 | static int wantedblksize; |
496 | CMDFUNCSTART(findblk) | | 496 | CMDFUNCSTART(findblk) |
497 | { | | 497 | { |
498 | ino_t inum, inosused; | | 498 | ino_t inum, inosused; |
499 | uint32_t *wantedblk32 = NULL; | | 499 | uint32_t *wantedblk32 = NULL; |
500 | uint64_t *wantedblk64 = NULL; | | 500 | uint64_t *wantedblk64 = NULL; |
501 | struct cg *cgp = cgrp; | | 501 | struct cg *cgp = cgrp; |
502 | int i, c; | | 502 | int i, c; |
503 | | | 503 | |
504 | ocurrent = curinum; | | 504 | ocurrent = curinum; |
505 | wantedblksize = (argc - 1); | | 505 | wantedblksize = (argc - 1); |
506 | if (is_ufs2) { | | 506 | if (is_ufs2) { |
507 | wantedblk64 = malloc(sizeof(uint64_t) * wantedblksize); | | 507 | wantedblk64 = malloc(sizeof(uint64_t) * wantedblksize); |
508 | if (wantedblk64 == NULL) { | | 508 | if (wantedblk64 == NULL) { |
509 | perror("malloc"); | | 509 | perror("malloc"); |
510 | return 1; | | 510 | return 1; |
511 | } | | 511 | } |
512 | memset(wantedblk64, 0, sizeof(uint64_t) * wantedblksize); | | 512 | memset(wantedblk64, 0, sizeof(uint64_t) * wantedblksize); |
513 | for (i = 1; i < argc; i++) | | 513 | for (i = 1; i < argc; i++) |
514 | wantedblk64[i - 1] = | | 514 | wantedblk64[i - 1] = |
515 | dbtofsb(sblock, strtoull(argv[i], NULL, 0)); | | 515 | dbtofsb(sblock, strtoull(argv[i], NULL, 0)); |
516 | } else { | | 516 | } else { |
517 | wantedblk32 = malloc(sizeof(uint32_t) * wantedblksize); | | 517 | wantedblk32 = malloc(sizeof(uint32_t) * wantedblksize); |
518 | if (wantedblk32 == NULL) { | | 518 | if (wantedblk32 == NULL) { |
519 | perror("malloc"); | | 519 | perror("malloc"); |
520 | return 1; | | 520 | return 1; |
521 | } | | 521 | } |
522 | memset(wantedblk32, 0, sizeof(uint32_t) * wantedblksize); | | 522 | memset(wantedblk32, 0, sizeof(uint32_t) * wantedblksize); |
523 | for (i = 1; i < argc; i++) | | 523 | for (i = 1; i < argc; i++) |
524 | wantedblk32[i - 1] = | | 524 | wantedblk32[i - 1] = |
525 | dbtofsb(sblock, strtoull(argv[i], NULL, 0)); | | 525 | dbtofsb(sblock, strtoull(argv[i], NULL, 0)); |
526 | } | | 526 | } |
527 | findblk_numtofind = wantedblksize; | | 527 | findblk_numtofind = wantedblksize; |
528 | for (c = 0; c < sblock->fs_ncg; c++) { | | 528 | for (c = 0; c < sblock->fs_ncg; c++) { |
529 | inum = c * sblock->fs_ipg; | | 529 | inum = c * sblock->fs_ipg; |
530 | getblk(&cgblk, cgtod(sblock, c), sblock->fs_cgsize); | | 530 | getblk(&cgblk, cgtod(sblock, c), sblock->fs_cgsize); |
531 | memcpy(cgp, cgblk.b_un.b_cg, sblock->fs_cgsize); | | 531 | memcpy(cgp, cgblk.b_un.b_cg, sblock->fs_cgsize); |
532 | if (needswap) | | 532 | if (needswap) |
533 | ffs_cg_swap(cgblk.b_un.b_cg, cgp, sblock); | | 533 | ffs_cg_swap(cgblk.b_un.b_cg, cgp, sblock); |
534 | if (is_ufs2) | | 534 | if (is_ufs2) |
535 | inosused = cgp->cg_initediblk; | | 535 | inosused = cgp->cg_initediblk; |
536 | else | | 536 | else |
537 | inosused = sblock->fs_ipg; | | 537 | inosused = sblock->fs_ipg; |
538 | for (; inosused > 0; inum++, inosused--) { | | 538 | for (; inosused > 0; inum++, inosused--) { |
539 | if (inum < ROOTINO) | | 539 | if (inum < ROOTINO) |
540 | continue; | | 540 | continue; |
541 | if (is_ufs2 ? compare_blk64(wantedblk64, | | 541 | if (is_ufs2 ? compare_blk64(wantedblk64, |
542 | ino_to_fsba(sblock, inum)) : | | 542 | ino_to_fsba(sblock, inum)) : |
543 | compare_blk32(wantedblk32, | | 543 | compare_blk32(wantedblk32, |
544 | ino_to_fsba(sblock, inum))) { | | 544 | ino_to_fsba(sblock, inum))) { |
545 | printf("block %llu: inode block (%llu-%llu)\n", | | 545 | printf("block %llu: inode block (%llu-%llu)\n", |
546 | (unsigned long long)fsbtodb(sblock, | | 546 | (unsigned long long)fsbtodb(sblock, |
547 | ino_to_fsba(sblock, inum)), | | 547 | ino_to_fsba(sblock, inum)), |
548 | (unsigned long long) | | 548 | (unsigned long long) |
549 | (inum / INOPB(sblock)) * INOPB(sblock), | | 549 | (inum / INOPB(sblock)) * INOPB(sblock), |
550 | (unsigned long long) | | 550 | (unsigned long long) |
551 | (inum / INOPB(sblock) + 1) * INOPB(sblock)); | | 551 | (inum / INOPB(sblock) + 1) * INOPB(sblock)); |
552 | findblk_numtofind--; | | 552 | findblk_numtofind--; |
553 | if (findblk_numtofind == 0) | | 553 | if (findblk_numtofind == 0) |
554 | goto end; | | 554 | goto end; |
555 | } | | 555 | } |
556 | curinum = inum; | | 556 | curinum = inum; |
557 | curinode = ginode(inum); | | 557 | curinode = ginode(inum); |
558 | switch (iswap16(DIP(curinode, mode)) & IFMT) { | | 558 | switch (iswap16(DIP(curinode, mode)) & IFMT) { |
559 | case IFDIR: | | 559 | case IFDIR: |
560 | case IFREG: | | 560 | case IFREG: |
561 | if (DIP(curinode, blocks) == 0) | | 561 | if (DIP(curinode, blocks) == 0) |
562 | continue; | | 562 | continue; |
563 | break; | | 563 | break; |
564 | case IFLNK: | | 564 | case IFLNK: |
565 | { | | 565 | { |
566 | uint64_t size = iswap64(DIP(curinode, size)); | | 566 | uint64_t size = iswap64(DIP(curinode, size)); |
567 | if (size > 0 && | | 567 | if (size > 0 && |
568 | size < (uint64_t)sblock->fs_maxsymlinklen && | | 568 | size < (uint64_t)sblock->fs_maxsymlinklen && |
569 | DIP(curinode, blocks) == 0) | | 569 | DIP(curinode, blocks) == 0) |
570 | continue; | | 570 | continue; |
571 | else | | 571 | else |
572 | break; | | 572 | break; |
573 | } | | 573 | } |
574 | default: | | 574 | default: |
575 | continue; | | 575 | continue; |
576 | } | | 576 | } |
577 | if (is_ufs2 ? | | 577 | if (is_ufs2 ? |
578 | find_blks64(curinode->dp2.di_db, NDADDR, | | 578 | find_blks64(curinode->dp2.di_db, NDADDR, |
579 | wantedblk64) : | | 579 | wantedblk64) : |
580 | find_blks32(curinode->dp1.di_db, NDADDR, | | 580 | find_blks32(curinode->dp1.di_db, NDADDR, |
581 | wantedblk32)) | | 581 | wantedblk32)) |
582 | goto end; | | 582 | goto end; |
583 | for (i = 0; i < NIADDR; i++) { | | 583 | for (i = 0; i < NIADDR; i++) { |
584 | if (is_ufs2 ? | | 584 | if (is_ufs2 ? |
585 | compare_blk64(wantedblk64, | | 585 | compare_blk64(wantedblk64, |
586 | iswap64(curinode->dp2.di_ib[i])) : | | 586 | iswap64(curinode->dp2.di_ib[i])) : |
587 | compare_blk32(wantedblk32, | | 587 | compare_blk32(wantedblk32, |
588 | iswap32(curinode->dp1.di_ib[i]))) | | 588 | iswap32(curinode->dp1.di_ib[i]))) |
589 | if (founddatablk(is_ufs2 ? | | 589 | if (founddatablk(is_ufs2 ? |
590 | iswap64(curinode->dp2.di_ib[i]) : | | 590 | iswap64(curinode->dp2.di_ib[i]) : |
591 | iswap32(curinode->dp1.di_ib[i]))) | | 591 | iswap32(curinode->dp1.di_ib[i]))) |
592 | goto end; | | 592 | goto end; |
593 | if (is_ufs2 ? (curinode->dp2.di_ib[i] != 0) : | | 593 | if (is_ufs2 ? (curinode->dp2.di_ib[i] != 0) : |
594 | (curinode->dp1.di_ib[i] != 0)) | | 594 | (curinode->dp1.di_ib[i] != 0)) |
595 | if (is_ufs2 ? | | 595 | if (is_ufs2 ? |
596 | find_indirblks64( | | 596 | find_indirblks64( |
597 | iswap64(curinode->dp2.di_ib[i]), | | 597 | iswap64(curinode->dp2.di_ib[i]), |
598 | i, wantedblk64) : | | 598 | i, wantedblk64) : |
599 | find_indirblks32( | | 599 | find_indirblks32( |
600 | iswap32(curinode->dp1.di_ib[i]), | | 600 | iswap32(curinode->dp1.di_ib[i]), |
601 | i, wantedblk32)) | | 601 | i, wantedblk32)) |
602 | goto end; | | 602 | goto end; |
603 | } | | 603 | } |
604 | } | | 604 | } |
605 | } | | 605 | } |
606 | end: | | 606 | end: |
607 | if (wantedblk32) | | 607 | if (wantedblk32) |
608 | free(wantedblk32); | | 608 | free(wantedblk32); |
609 | if (wantedblk64) | | 609 | if (wantedblk64) |
610 | free(wantedblk64); | | 610 | free(wantedblk64); |
611 | curinum = ocurrent; | | 611 | curinum = ocurrent; |
612 | curinode = ginode(curinum); | | 612 | curinode = ginode(curinum); |
613 | return 0; | | 613 | return 0; |
614 | } | | 614 | } |
615 | | | 615 | |
616 | static int | | 616 | static int |
617 | compare_blk32(uint32_t *wantedblk, uint32_t curblk) | | 617 | compare_blk32(uint32_t *wantedblk, uint32_t curblk) |
618 | { | | 618 | { |
619 | int i; | | 619 | int i; |
620 | for (i = 0; i < wantedblksize; i++) { | | 620 | for (i = 0; i < wantedblksize; i++) { |
621 | if (wantedblk[i] != 0 && wantedblk[i] == curblk) { | | 621 | if (wantedblk[i] != 0 && wantedblk[i] == curblk) { |
622 | wantedblk[i] = 0; | | 622 | wantedblk[i] = 0; |
623 | return 1; | | 623 | return 1; |
624 | } | | 624 | } |
625 | } | | 625 | } |
626 | return 0; | | 626 | return 0; |
627 | } | | 627 | } |
628 | | | 628 | |
629 | static int | | 629 | static int |
630 | compare_blk64(uint64_t *wantedblk, uint64_t curblk) | | 630 | compare_blk64(uint64_t *wantedblk, uint64_t curblk) |
631 | { | | 631 | { |
632 | int i; | | 632 | int i; |
633 | for (i = 0; i < wantedblksize; i++) { | | 633 | for (i = 0; i < wantedblksize; i++) { |
634 | if (wantedblk[i] != 0 && wantedblk[i] == curblk) { | | 634 | if (wantedblk[i] != 0 && wantedblk[i] == curblk) { |
635 | wantedblk[i] = 0; | | 635 | wantedblk[i] = 0; |
636 | return 1; | | 636 | return 1; |
637 | } | | 637 | } |
638 | } | | 638 | } |
639 | return 0; | | 639 | return 0; |
640 | } | | 640 | } |
641 | | | 641 | |
642 | static int | | 642 | static int |
643 | founddatablk(uint64_t blk) | | 643 | founddatablk(uint64_t blk) |
644 | { | | 644 | { |
645 | printf("%llu: data block of inode %llu\n", | | 645 | printf("%llu: data block of inode %llu\n", |
646 | (unsigned long long)fsbtodb(sblock, blk), | | 646 | (unsigned long long)fsbtodb(sblock, blk), |
647 | (unsigned long long)curinum); | | 647 | (unsigned long long)curinum); |
648 | findblk_numtofind--; | | 648 | findblk_numtofind--; |
649 | if (findblk_numtofind == 0) | | 649 | if (findblk_numtofind == 0) |
650 | return 1; | | 650 | return 1; |
651 | return 0; | | 651 | return 0; |
652 | } | | 652 | } |
653 | | | 653 | |
654 | static int | | 654 | static int |
655 | find_blks32(uint32_t *buf, int size, uint32_t *wantedblk) | | 655 | find_blks32(uint32_t *buf, int size, uint32_t *wantedblk) |
656 | { | | 656 | { |
657 | int blk; | | 657 | int blk; |
658 | for(blk = 0; blk < size; blk++) { | | 658 | for(blk = 0; blk < size; blk++) { |
659 | if (buf[blk] == 0) | | 659 | if (buf[blk] == 0) |
660 | continue; | | 660 | continue; |
661 | if (compare_blk32(wantedblk, iswap32(buf[blk]))) { | | 661 | if (compare_blk32(wantedblk, iswap32(buf[blk]))) { |
662 | if (founddatablk(iswap32(buf[blk]))) | | 662 | if (founddatablk(iswap32(buf[blk]))) |
663 | return 1; | | 663 | return 1; |
664 | } | | 664 | } |
665 | } | | 665 | } |
666 | return 0; | | 666 | return 0; |
667 | } | | 667 | } |
668 | | | 668 | |
669 | static int | | 669 | static int |
670 | find_indirblks32(uint32_t blk, int ind_level, uint32_t *wantedblk) | | 670 | find_indirblks32(uint32_t blk, int ind_level, uint32_t *wantedblk) |
671 | { | | 671 | { |
672 | #define MAXNINDIR (MAXBSIZE / sizeof(uint32_t)) | | 672 | #define MAXNINDIR (MAXBSIZE / sizeof(uint32_t)) |
673 | uint32_t idblk[MAXNINDIR]; | | 673 | uint32_t idblk[MAXNINDIR]; |
674 | size_t i; | | 674 | size_t i; |
675 | | | 675 | |
676 | bread(fsreadfd, (char *)idblk, fsbtodb(sblock, blk), | | 676 | bread(fsreadfd, (char *)idblk, fsbtodb(sblock, blk), |
677 | (int)sblock->fs_bsize); | | 677 | (int)sblock->fs_bsize); |
678 | if (ind_level <= 0) { | | 678 | if (ind_level <= 0) { |
679 | if (find_blks32(idblk, | | 679 | if (find_blks32(idblk, |
680 | sblock->fs_bsize / sizeof(uint32_t), wantedblk)) | | 680 | sblock->fs_bsize / sizeof(uint32_t), wantedblk)) |
681 | return 1; | | 681 | return 1; |
682 | } else { | | 682 | } else { |
683 | ind_level--; | | 683 | ind_level--; |
684 | for (i = 0; i < sblock->fs_bsize / sizeof(uint32_t); i++) { | | 684 | for (i = 0; i < sblock->fs_bsize / sizeof(uint32_t); i++) { |
685 | if (compare_blk32(wantedblk, iswap32(idblk[i]))) { | | 685 | if (compare_blk32(wantedblk, iswap32(idblk[i]))) { |
686 | if (founddatablk(iswap32(idblk[i]))) | | 686 | if (founddatablk(iswap32(idblk[i]))) |
687 | return 1; | | 687 | return 1; |
688 | } | | 688 | } |
689 | if(idblk[i] != 0) | | 689 | if(idblk[i] != 0) |
690 | if (find_indirblks32(iswap32(idblk[i]), | | 690 | if (find_indirblks32(iswap32(idblk[i]), |
691 | ind_level, wantedblk)) | | 691 | ind_level, wantedblk)) |
692 | return 1; | | 692 | return 1; |
693 | } | | 693 | } |
694 | } | | 694 | } |
695 | #undef MAXNINDIR | | 695 | #undef MAXNINDIR |
696 | return 0; | | 696 | return 0; |
697 | } | | 697 | } |
698 | | | 698 | |
699 | | | 699 | |
700 | static int | | 700 | static int |
701 | find_blks64(uint64_t *buf, int size, uint64_t *wantedblk) | | 701 | find_blks64(uint64_t *buf, int size, uint64_t *wantedblk) |
702 | { | | 702 | { |
703 | int blk; | | 703 | int blk; |
704 | for(blk = 0; blk < size; blk++) { | | 704 | for(blk = 0; blk < size; blk++) { |
705 | if (buf[blk] == 0) | | 705 | if (buf[blk] == 0) |
706 | continue; | | 706 | continue; |
707 | if (compare_blk64(wantedblk, iswap64(buf[blk]))) { | | 707 | if (compare_blk64(wantedblk, iswap64(buf[blk]))) { |
708 | if (founddatablk(iswap64(buf[blk]))) | | 708 | if (founddatablk(iswap64(buf[blk]))) |
709 | return 1; | | 709 | return 1; |
710 | } | | 710 | } |
711 | } | | 711 | } |
712 | return 0; | | 712 | return 0; |
713 | } | | 713 | } |
714 | | | 714 | |
715 | static int | | 715 | static int |
716 | find_indirblks64(uint64_t blk, int ind_level, uint64_t *wantedblk) | | 716 | find_indirblks64(uint64_t blk, int ind_level, uint64_t *wantedblk) |
717 | { | | 717 | { |
718 | #define MAXNINDIR (MAXBSIZE / sizeof(uint64_t)) | | 718 | #define MAXNINDIR (MAXBSIZE / sizeof(uint64_t)) |
719 | uint64_t idblk[MAXNINDIR]; | | 719 | uint64_t idblk[MAXNINDIR]; |
720 | size_t i; | | 720 | size_t i; |
721 | | | 721 | |
722 | bread(fsreadfd, (char *)idblk, fsbtodb(sblock, blk), | | 722 | bread(fsreadfd, (char *)idblk, fsbtodb(sblock, blk), |
723 | (int)sblock->fs_bsize); | | 723 | (int)sblock->fs_bsize); |
724 | if (ind_level <= 0) { | | 724 | if (ind_level <= 0) { |
725 | if (find_blks64(idblk, | | 725 | if (find_blks64(idblk, |
726 | sblock->fs_bsize / sizeof(uint64_t), wantedblk)) | | 726 | sblock->fs_bsize / sizeof(uint64_t), wantedblk)) |
727 | return 1; | | 727 | return 1; |
728 | } else { | | 728 | } else { |
729 | ind_level--; | | 729 | ind_level--; |
730 | for (i = 0; i < sblock->fs_bsize / sizeof(uint64_t); i++) { | | 730 | for (i = 0; i < sblock->fs_bsize / sizeof(uint64_t); i++) { |
731 | if (compare_blk64(wantedblk, iswap64(idblk[i]))) { | | 731 | if (compare_blk64(wantedblk, iswap64(idblk[i]))) { |
732 | if (founddatablk(iswap64(idblk[i]))) | | 732 | if (founddatablk(iswap64(idblk[i]))) |
733 | return 1; | | 733 | return 1; |
734 | } | | 734 | } |
735 | if(idblk[i] != 0) | | 735 | if(idblk[i] != 0) |
736 | if (find_indirblks64(iswap64(idblk[i]), | | 736 | if (find_indirblks64(iswap64(idblk[i]), |
737 | ind_level, wantedblk)) | | 737 | ind_level, wantedblk)) |
738 | return 1; | | 738 | return 1; |
739 | } | | 739 | } |
740 | } | | 740 | } |
741 | #undef MAXNINDIR | | 741 | #undef MAXNINDIR |
742 | return 0; | | 742 | return 0; |
743 | } | | 743 | } |
744 | | | 744 | |
745 | | | 745 | |
746 | #define CHARS_PER_LINES 70 | | 746 | #define CHARS_PER_LINES 70 |
747 | | | 747 | |
748 | static void | | 748 | static void |
749 | print_blks32(int32_t *buf, int size, uint64_t *blknum) | | 749 | print_blks32(int32_t *buf, int size, uint64_t *blknum) |
750 | { | | 750 | { |
751 | int chars; | | 751 | int chars; |
752 | char prbuf[CHARS_PER_LINES+1]; | | 752 | char prbuf[CHARS_PER_LINES+1]; |
753 | int blk; | | 753 | int blk; |
754 | | | 754 | |
755 | chars = 0; | | 755 | chars = 0; |
756 | for(blk = 0; blk < size; blk++, (*blknum)++) { | | 756 | for(blk = 0; blk < size; blk++, (*blknum)++) { |
757 | if (buf[blk] == 0) | | 757 | if (buf[blk] == 0) |
758 | continue; | | 758 | continue; |
759 | snprintf(prbuf, CHARS_PER_LINES, "%d ", iswap32(buf[blk])); | | 759 | snprintf(prbuf, CHARS_PER_LINES, "%d ", iswap32(buf[blk])); |
760 | if ((chars + strlen(prbuf)) > CHARS_PER_LINES) { | | 760 | if ((chars + strlen(prbuf)) > CHARS_PER_LINES) { |
761 | printf("\n"); | | 761 | printf("\n"); |
762 | chars = 0; | | 762 | chars = 0; |
763 | } | | 763 | } |
764 | if (chars == 0) | | 764 | if (chars == 0) |
765 | printf("%" PRIu64 ": ", *blknum); | | 765 | printf("%" PRIu64 ": ", *blknum); |
766 | printf("%s", prbuf); | | 766 | printf("%s", prbuf); |
767 | chars += strlen(prbuf); | | 767 | chars += strlen(prbuf); |
768 | } | | 768 | } |
769 | printf("\n"); | | 769 | printf("\n"); |
770 | } | | 770 | } |
771 | | | 771 | |
772 | static void | | 772 | static void |
773 | print_blks64(int64_t *buf, int size, uint64_t *blknum) | | 773 | print_blks64(int64_t *buf, int size, uint64_t *blknum) |
774 | { | | 774 | { |
775 | int chars; | | 775 | int chars; |
776 | char prbuf[CHARS_PER_LINES+1]; | | 776 | char prbuf[CHARS_PER_LINES+1]; |
777 | int blk; | | 777 | int blk; |
778 | | | 778 | |
779 | chars = 0; | | 779 | chars = 0; |
780 | for(blk = 0; blk < size; blk++, (*blknum)++) { | | 780 | for(blk = 0; blk < size; blk++, (*blknum)++) { |
781 | if (buf[blk] == 0) | | 781 | if (buf[blk] == 0) |
782 | continue; | | 782 | continue; |
783 | snprintf(prbuf, CHARS_PER_LINES, "%lld ", | | 783 | snprintf(prbuf, CHARS_PER_LINES, "%lld ", |
784 | (long long)iswap64(buf[blk])); | | 784 | (long long)iswap64(buf[blk])); |
785 | if ((chars + strlen(prbuf)) > CHARS_PER_LINES) { | | 785 | if ((chars + strlen(prbuf)) > CHARS_PER_LINES) { |
786 | printf("\n"); | | 786 | printf("\n"); |
787 | chars = 0; | | 787 | chars = 0; |
788 | } | | 788 | } |
789 | if (chars == 0) | | 789 | if (chars == 0) |
790 | printf("%" PRIu64 ": ", *blknum); | | 790 | printf("%" PRIu64 ": ", *blknum); |
791 | printf("%s", prbuf); | | 791 | printf("%s", prbuf); |
792 | chars += strlen(prbuf); | | 792 | chars += strlen(prbuf); |
793 | } | | 793 | } |
794 | printf("\n"); | | 794 | printf("\n"); |
795 | } | | 795 | } |
796 | | | 796 | |
797 | #undef CHARS_PER_LINES | | 797 | #undef CHARS_PER_LINES |
798 | | | 798 | |
799 | static void | | 799 | static void |
800 | print_indirblks32(uint32_t blk, int ind_level, uint64_t *blknum) | | 800 | print_indirblks32(uint32_t blk, int ind_level, uint64_t *blknum) |
801 | { | | 801 | { |
802 | #define MAXNINDIR (MAXBSIZE / sizeof(int32_t)) | | 802 | #define MAXNINDIR (MAXBSIZE / sizeof(int32_t)) |
803 | const int ptrperblk_shift = sblock->fs_bshift - 2; | | 803 | const int ptrperblk_shift = sblock->fs_bshift - 2; |
804 | const int ptrperblk = 1 << ptrperblk_shift; | | 804 | const int ptrperblk = 1 << ptrperblk_shift; |
805 | int32_t idblk[MAXNINDIR]; | | 805 | int32_t idblk[MAXNINDIR]; |
806 | int i; | | 806 | int i; |
807 | | | 807 | |
808 | if (blk == 0) { | | 808 | if (blk == 0) { |
809 | *blknum += (uint64_t)ptrperblk << (ptrperblk_shift * ind_level); | | 809 | *blknum += (uint64_t)ptrperblk << (ptrperblk_shift * ind_level); |
810 | return; | | 810 | return; |
811 | } | | 811 | } |
812 | | | 812 | |
813 | printf("Indirect block %lld (level %d):\n", (long long)blk, | | 813 | printf("Indirect block %lld (level %d):\n", (long long)blk, |
814 | ind_level+1); | | 814 | ind_level+1); |
815 | bread(fsreadfd, (char *)idblk, fsbtodb(sblock, blk), | | 815 | bread(fsreadfd, (char *)idblk, fsbtodb(sblock, blk), |
816 | (int)sblock->fs_bsize); | | 816 | (int)sblock->fs_bsize); |
817 | if (ind_level <= 0) { | | 817 | if (ind_level <= 0) { |
818 | print_blks32(idblk, ptrperblk, blknum); | | 818 | print_blks32(idblk, ptrperblk, blknum); |
819 | } else { | | 819 | } else { |
820 | ind_level--; | | 820 | ind_level--; |
821 | for (i = 0; i < ptrperblk; i++) | | 821 | for (i = 0; i < ptrperblk; i++) |
822 | print_indirblks32(iswap32(idblk[i]), ind_level, blknum); | | 822 | print_indirblks32(iswap32(idblk[i]), ind_level, blknum); |
823 | } | | 823 | } |
824 | #undef MAXNINDIR | | 824 | #undef MAXNINDIR |
825 | } | | 825 | } |
826 | | | 826 | |
827 | static void | | 827 | static void |
828 | print_indirblks64(uint64_t blk, int ind_level, uint64_t *blknum) | | 828 | print_indirblks64(uint64_t blk, int ind_level, uint64_t *blknum) |
829 | { | | 829 | { |
830 | #define MAXNINDIR (MAXBSIZE / sizeof(int64_t)) | | 830 | #define MAXNINDIR (MAXBSIZE / sizeof(int64_t)) |
831 | const int ptrperblk_shift = sblock->fs_bshift - 3; | | 831 | const int ptrperblk_shift = sblock->fs_bshift - 3; |
832 | const int ptrperblk = 1 << ptrperblk_shift; | | 832 | const int ptrperblk = 1 << ptrperblk_shift; |
833 | int64_t idblk[MAXNINDIR]; | | 833 | int64_t idblk[MAXNINDIR]; |
834 | int i; | | 834 | int i; |
835 | | | 835 | |
836 | if (blk == 0) { | | 836 | if (blk == 0) { |
837 | *blknum += (uint64_t)ptrperblk << (ptrperblk_shift * ind_level); | | 837 | *blknum += (uint64_t)ptrperblk << (ptrperblk_shift * ind_level); |
838 | return; | | 838 | return; |
839 | } | | 839 | } |
840 | | | 840 | |
841 | printf("Indirect block %lld (level %d):\n", (long long)blk, | | 841 | printf("Indirect block %lld (level %d):\n", (long long)blk, |
842 | ind_level+1); | | 842 | ind_level+1); |
843 | bread(fsreadfd, (char *)idblk, fsbtodb(sblock, blk), | | 843 | bread(fsreadfd, (char *)idblk, fsbtodb(sblock, blk), |
844 | (int)sblock->fs_bsize); | | 844 | (int)sblock->fs_bsize); |
845 | if (ind_level <= 0) { | | 845 | if (ind_level <= 0) { |
846 | print_blks64(idblk, ptrperblk, blknum); | | 846 | print_blks64(idblk, ptrperblk, blknum); |
847 | } else { | | 847 | } else { |
848 | ind_level--; | | 848 | ind_level--; |
849 | for (i = 0; i < ptrperblk; i++) | | 849 | for (i = 0; i < ptrperblk; i++) |
850 | print_indirblks64(iswap64(idblk[i]), ind_level, blknum); | | 850 | print_indirblks64(iswap64(idblk[i]), ind_level, blknum); |
851 | } | | 851 | } |
852 | #undef MAXNINDIR | | 852 | #undef MAXNINDIR |
853 | } | | 853 | } |
854 | | | 854 | |
855 | static int | | 855 | static int |
856 | dolookup(char *name) | | 856 | dolookup(char *name) |
857 | { | | 857 | { |
858 | struct inodesc idesc; | | 858 | struct inodesc idesc; |
859 | | | 859 | |
860 | if (!checkactivedir()) | | 860 | if (!checkactivedir()) |
861 | return 0; | | 861 | return 0; |
862 | idesc.id_number = curinum; | | 862 | idesc.id_number = curinum; |
863 | idesc.id_func = findino; | | 863 | idesc.id_func = findino; |
864 | idesc.id_name = name; | | 864 | idesc.id_name = name; |
865 | idesc.id_type = DATA; | | 865 | idesc.id_type = DATA; |
866 | idesc.id_fix = IGNORE; | | 866 | idesc.id_fix = IGNORE; |
867 | if (ckinode(curinode, &idesc) & FOUND) { | | 867 | if (ckinode(curinode, &idesc) & FOUND) { |
868 | curinum = idesc.id_parent; | | 868 | curinum = idesc.id_parent; |
869 | curinode = ginode(curinum); | | 869 | curinode = ginode(curinum); |
870 | printactive(); | | 870 | printactive(); |
871 | return 1; | | 871 | return 1; |
872 | } else { | | 872 | } else { |
873 | warnx("name `%s' not found in current inode directory", name); | | 873 | warnx("name `%s' not found in current inode directory", name); |
874 | return 0; | | 874 | return 0; |
875 | } | | 875 | } |
876 | } | | 876 | } |
877 | | | 877 | |
878 | CMDFUNCSTART(focusname) | | 878 | CMDFUNCSTART(focusname) |
879 | { | | 879 | { |
880 | char *p, *val; | | 880 | char *p, *val; |
881 | | | 881 | |
882 | if (!checkactive()) | | 882 | if (!checkactive()) |
883 | return 1; | | 883 | return 1; |
884 | | | 884 | |
885 | ocurrent = curinum; | | 885 | ocurrent = curinum; |
886 | | | 886 | |
887 | if (argv[1][0] == '/') { | | 887 | if (argv[1][0] == '/') { |
888 | curinum = ROOTINO; | | 888 | curinum = ROOTINO; |
889 | curinode = ginode(ROOTINO); | | 889 | curinode = ginode(ROOTINO); |
890 | } else { | | 890 | } else { |
891 | if (!checkactivedir()) | | 891 | if (!checkactivedir()) |
892 | return 1; | | 892 | return 1; |
893 | } | | 893 | } |
894 | for (p = argv[1]; p != NULL;) { | | 894 | for (p = argv[1]; p != NULL;) { |
895 | while ((val = strsep(&p, "/")) != NULL && *val == '\0'); | | 895 | while ((val = strsep(&p, "/")) != NULL && *val == '\0'); |
896 | if (val) { | | 896 | if (val) { |
897 | printf("component `%s': ", val); | | 897 | printf("component `%s': ", val); |
898 | fflush(stdout); | | 898 | fflush(stdout); |
899 | if (!dolookup(val)) { | | 899 | if (!dolookup(val)) { |
900 | curinode = ginode(curinum); | | 900 | curinode = ginode(curinum); |
901 | return (1); | | 901 | return (1); |
902 | } | | 902 | } |
903 | } | | 903 | } |
904 | } | | 904 | } |
905 | return 0; | | 905 | return 0; |
906 | } | | 906 | } |
907 | | | 907 | |
908 | CMDFUNCSTART(ln) | | 908 | CMDFUNCSTART(ln) |
909 | { | | 909 | { |
910 | ino_t inum; | | 910 | ino_t inum; |
911 | int rval; | | 911 | int rval; |
912 | char *cp; | | 912 | char *cp; |
913 | | | 913 | |
914 | GETINUM(1, inum); | | 914 | GETINUM(1, inum); |
915 | | | 915 | |
916 | if (!checkactivedir()) | | 916 | if (!checkactivedir()) |
917 | return 1; | | 917 | return 1; |
918 | rval = makeentry(curinum, inum, argv[2]); | | 918 | rval = makeentry(curinum, inum, argv[2]); |
919 | if (rval) | | 919 | if (rval) |
920 | printf("Ino %llu entered as `%s'\n", (unsigned long long)inum, | | 920 | printf("Ino %llu entered as `%s'\n", (unsigned long long)inum, |
921 | argv[2]); | | 921 | argv[2]); |
922 | else | | 922 | else |
923 | printf("could not enter name? weird.\n"); | | 923 | printf("could not enter name? weird.\n"); |
924 | curinode = ginode(curinum); | | 924 | curinode = ginode(curinum); |
925 | return rval; | | 925 | return rval; |
926 | } | | 926 | } |
927 | | | 927 | |
928 | CMDFUNCSTART(rm) | | 928 | CMDFUNCSTART(rm) |
929 | { | | 929 | { |
930 | int rval; | | 930 | int rval; |
931 | | | 931 | |
932 | if (!checkactivedir()) | | 932 | if (!checkactivedir()) |
933 | return 1; | | 933 | return 1; |
934 | rval = changeino(curinum, argv[1], 0); | | 934 | rval = changeino(curinum, argv[1], 0); |
935 | if (rval & ALTERED) { | | 935 | if (rval & ALTERED) { |
936 | printf("Name `%s' removed\n", argv[1]); | | 936 | printf("Name `%s' removed\n", argv[1]); |
937 | return 0; | | 937 | return 0; |
938 | } else { | | 938 | } else { |
939 | printf("could not remove name? weird.\n"); | | 939 | printf("could not remove name? weird.\n"); |
940 | return 1; | | 940 | return 1; |
941 | } | | 941 | } |
942 | } | | 942 | } |
943 | | | 943 | |
944 | static long slotcount, desired; | | 944 | static long slotcount, desired; |
945 | | | 945 | |
946 | static int | | 946 | static int |
947 | chinumfunc(struct inodesc *idesc) | | 947 | chinumfunc(struct inodesc *idesc) |
948 | { | | 948 | { |
949 | struct direct *dirp = idesc->id_dirp; | | 949 | struct direct *dirp = idesc->id_dirp; |
950 | | | 950 | |
951 | if (slotcount++ == desired) { | | 951 | if (slotcount++ == desired) { |
952 | dirp->d_ino = iswap32(idesc->id_parent); | | 952 | dirp->d_ino = iswap32(idesc->id_parent); |
953 | return STOP | ALTERED | FOUND; | | 953 | return STOP | ALTERED | FOUND; |
954 | } | | 954 | } |
955 | return KEEPON; | | 955 | return KEEPON; |
956 | } | | 956 | } |
957 | | | 957 | |
958 | CMDFUNCSTART(chinum) | | 958 | CMDFUNCSTART(chinum) |
959 | { | | 959 | { |
960 | char *cp; | | 960 | char *cp; |
961 | ino_t inum; | | 961 | ino_t inum; |
962 | struct inodesc idesc; | | 962 | struct inodesc idesc; |
963 | | | 963 | |
964 | slotcount = 0; | | 964 | slotcount = 0; |
965 | if (!checkactivedir()) | | 965 | if (!checkactivedir()) |
966 | return 1; | | 966 | return 1; |
967 | GETINUM(2, inum); | | 967 | GETINUM(2, inum); |
968 | | | 968 | |
969 | desired = strtol(argv[1], &cp, 0); | | 969 | desired = strtol(argv[1], &cp, 0); |
970 | if (cp == argv[1] || *cp != '\0' || desired < 0) { | | 970 | if (cp == argv[1] || *cp != '\0' || desired < 0) { |
971 | printf("invalid slot number `%s'\n", argv[1]); | | 971 | printf("invalid slot number `%s'\n", argv[1]); |
972 | return 1; | | 972 | return 1; |
973 | } | | 973 | } |
974 | idesc.id_number = curinum; | | 974 | idesc.id_number = curinum; |
975 | idesc.id_func = chinumfunc; | | 975 | idesc.id_func = chinumfunc; |
976 | idesc.id_fix = IGNORE; | | 976 | idesc.id_fix = IGNORE; |
977 | idesc.id_type = DATA; | | 977 | idesc.id_type = DATA; |
978 | idesc.id_parent = inum; /* XXX convenient hiding place */ | | 978 | idesc.id_parent = inum; /* XXX convenient hiding place */ |
979 | | | 979 | |
980 | if (ckinode(curinode, &idesc) & FOUND) | | 980 | if (ckinode(curinode, &idesc) & FOUND) |
981 | return 0; | | 981 | return 0; |
982 | else { | | 982 | else { |
983 | warnx("no %sth slot in current directory", argv[1]); | | 983 | warnx("no %sth slot in current directory", argv[1]); |
984 | return 1; | | 984 | return 1; |
985 | } | | 985 | } |
986 | } | | 986 | } |
987 | | | 987 | |
988 | static int | | 988 | static int |
989 | chnamefunc(struct inodesc *idesc) | | 989 | chnamefunc(struct inodesc *idesc) |
990 | { | | 990 | { |
991 | struct direct *dirp = idesc->id_dirp; | | 991 | struct direct *dirp = idesc->id_dirp; |
992 | struct direct testdir; | | 992 | struct direct testdir; |
993 | | | 993 | |
994 | if (slotcount++ == desired) { | | 994 | if (slotcount++ == desired) { |
995 | /* will name fit? */ | | 995 | /* will name fit? */ |
996 | testdir.d_namlen = strlen(idesc->id_name); | | 996 | testdir.d_namlen = strlen(idesc->id_name); |
997 | if (DIRSIZ(NEWDIRFMT, &testdir, 0) <= iswap16(dirp->d_reclen)) { | | 997 | if (DIRSIZ(NEWDIRFMT, &testdir, 0) <= iswap16(dirp->d_reclen)) { |
998 | dirp->d_namlen = testdir.d_namlen; | | 998 | dirp->d_namlen = testdir.d_namlen; |
999 | strlcpy(dirp->d_name, idesc->id_name, | | 999 | strlcpy(dirp->d_name, idesc->id_name, |
1000 | sizeof(dirp->d_name)); | | 1000 | sizeof(dirp->d_name)); |
1001 | return STOP | ALTERED | FOUND; | | 1001 | return STOP | ALTERED | FOUND; |
1002 | } else | | 1002 | } else |
1003 | return STOP | FOUND; /* won't fit, so give up */ | | 1003 | return STOP | FOUND; /* won't fit, so give up */ |
1004 | } | | 1004 | } |
1005 | return KEEPON; | | 1005 | return KEEPON; |
1006 | } | | 1006 | } |
1007 | | | 1007 | |
1008 | CMDFUNCSTART(chname) | | 1008 | CMDFUNCSTART(chname) |
1009 | { | | 1009 | { |
1010 | int rval; | | 1010 | int rval; |
1011 | char *cp; | | 1011 | char *cp; |
1012 | struct inodesc idesc; | | 1012 | struct inodesc idesc; |
1013 | | | 1013 | |
1014 | slotcount = 0; | | 1014 | slotcount = 0; |
1015 | if (!checkactivedir()) | | 1015 | if (!checkactivedir()) |
1016 | return 1; | | 1016 | return 1; |
1017 | | | 1017 | |
1018 | desired = strtoul(argv[1], &cp, 0); | | 1018 | desired = strtoul(argv[1], &cp, 0); |
1019 | if (cp == argv[1] || *cp != '\0') { | | 1019 | if (cp == argv[1] || *cp != '\0') { |
1020 | printf("invalid slot number `%s'\n", argv[1]); | | 1020 | printf("invalid slot number `%s'\n", argv[1]); |
1021 | return 1; | | 1021 | return 1; |
1022 | } | | 1022 | } |
1023 | idesc.id_number = curinum; | | 1023 | idesc.id_number = curinum; |
1024 | idesc.id_func = chnamefunc; | | 1024 | idesc.id_func = chnamefunc; |
1025 | idesc.id_fix = IGNORE; | | 1025 | idesc.id_fix = IGNORE; |
1026 | idesc.id_type = DATA; | | 1026 | idesc.id_type = DATA; |
1027 | idesc.id_name = argv[2]; | | 1027 | idesc.id_name = argv[2]; |
1028 | | | 1028 | |
1029 | rval = ckinode(curinode, &idesc); | | 1029 | rval = ckinode(curinode, &idesc); |
1030 | if ((rval & (FOUND | ALTERED)) == (FOUND | ALTERED)) | | 1030 | if ((rval & (FOUND | ALTERED)) == (FOUND | ALTERED)) |
1031 | return 0; | | 1031 | return 0; |
1032 | else | | 1032 | else |
1033 | if (rval & FOUND) { | | 1033 | if (rval & FOUND) { |
1034 | warnx("new name `%s' does not fit in slot %s", | | 1034 | warnx("new name `%s' does not fit in slot %s", |
1035 | argv[2], argv[1]); | | 1035 | argv[2], argv[1]); |
1036 | return 1; | | 1036 | return 1; |
1037 | } else { | | 1037 | } else { |
1038 | warnx("no %sth slot in current directory", argv[1]); | | 1038 | warnx("no %sth slot in current directory", argv[1]); |
1039 | return 1; | | 1039 | return 1; |
1040 | } | | 1040 | } |
1041 | } | | 1041 | } |
1042 | | | 1042 | |
1043 | static struct typemap { | | 1043 | static struct typemap { |
1044 | const char *typename; | | 1044 | const char *typename; |
1045 | int typebits; | | 1045 | int typebits; |
1046 | } typenamemap[] = { | | 1046 | } typenamemap[] = { |
1047 | { "file", IFREG }, | | 1047 | { "file", IFREG }, |
1048 | { "dir", IFDIR }, | | 1048 | { "dir", IFDIR }, |
1049 | { "socket", IFSOCK }, | | 1049 | { "socket", IFSOCK }, |
1050 | { "fifo", IFIFO }, | | 1050 | { "fifo", IFIFO }, |
1051 | }; | | 1051 | }; |
1052 | | | 1052 | |
1053 | CMDFUNCSTART(newtype) | | 1053 | CMDFUNCSTART(newtype) |
1054 | { | | 1054 | { |
1055 | int type; | | 1055 | int type; |
1056 | uint16_t mode; | | 1056 | uint16_t mode; |
1057 | struct typemap *tp; | | 1057 | struct typemap *tp; |
1058 | | | 1058 | |
1059 | if (!checkactive()) | | 1059 | if (!checkactive()) |
1060 | return 1; | | 1060 | return 1; |
1061 | mode = iswap16(DIP(curinode, mode)); | | 1061 | mode = iswap16(DIP(curinode, mode)); |
1062 | type = mode & IFMT; | | 1062 | type = mode & IFMT; |
1063 | for (tp = typenamemap; | | 1063 | for (tp = typenamemap; |
1064 | tp < &typenamemap[sizeof(typenamemap) / sizeof(*typenamemap)]; | | 1064 | tp < &typenamemap[sizeof(typenamemap) / sizeof(*typenamemap)]; |
1065 | tp++) { | | 1065 | tp++) { |
1066 | if (!strcmp(argv[1], tp->typename)) { | | 1066 | if (!strcmp(argv[1], tp->typename)) { |
1067 | printf("setting type to %s\n", tp->typename); | | 1067 | printf("setting type to %s\n", tp->typename); |
1068 | type = tp->typebits; | | 1068 | type = tp->typebits; |
1069 | break; | | 1069 | break; |
1070 | } | | 1070 | } |
1071 | } | | 1071 | } |
1072 | if (tp == &typenamemap[sizeof(typenamemap) / sizeof(*typenamemap)]) { | | 1072 | if (tp == &typenamemap[sizeof(typenamemap) / sizeof(*typenamemap)]) { |
1073 | warnx("type `%s' not known", argv[1]); | | 1073 | warnx("type `%s' not known", argv[1]); |
1074 | warnx("try one of `file', `dir', `socket', `fifo'"); | | 1074 | warnx("try one of `file', `dir', `socket', `fifo'"); |
1075 | return 1; | | 1075 | return 1; |
1076 | } | | 1076 | } |
1077 | DIP_SET(curinode, mode, iswap16((mode & ~IFMT) | type)); | | 1077 | DIP_SET(curinode, mode, iswap16((mode & ~IFMT) | type)); |
1078 | inodirty(); | | 1078 | inodirty(); |
1079 | printactive(); | | 1079 | printactive(); |
1080 | return 0; | | 1080 | return 0; |
1081 | } | | 1081 | } |
1082 | | | 1082 | |
1083 | CMDFUNCSTART(chmode) | | 1083 | CMDFUNCSTART(chmode) |
1084 | { | | 1084 | { |
1085 | long modebits; | | 1085 | long modebits; |
1086 | char *cp; | | 1086 | char *cp; |
1087 | uint16_t mode; | | 1087 | uint16_t mode; |
1088 | | | 1088 | |
1089 | if (!checkactive()) | | 1089 | if (!checkactive()) |
1090 | return 1; | | 1090 | return 1; |
1091 | | | 1091 | |
1092 | modebits = strtol(argv[1], &cp, 8); | | 1092 | modebits = strtol(argv[1], &cp, 8); |
1093 | if (cp == argv[1] || *cp != '\0') { | | 1093 | if (cp == argv[1] || *cp != '\0') { |
1094 | warnx("bad modebits `%s'", argv[1]); | | 1094 | warnx("bad modebits `%s'", argv[1]); |
1095 | return 1; | | 1095 | return 1; |
1096 | } | | 1096 | } |
1097 | mode = iswap16(DIP(curinode, mode)); | | 1097 | mode = iswap16(DIP(curinode, mode)); |
1098 | DIP_SET(curinode, mode, iswap16((mode & ~07777) | modebits)); | | 1098 | DIP_SET(curinode, mode, iswap16((mode & ~07777) | modebits)); |
1099 | inodirty(); | | 1099 | inodirty(); |
1100 | printactive(); | | 1100 | printactive(); |
1101 | return 0; | | 1101 | return 0; |
1102 | } | | 1102 | } |
1103 | | | 1103 | |
1104 | CMDFUNCSTART(chlen) | | 1104 | CMDFUNCSTART(chlen) |
1105 | { | | 1105 | { |
1106 | long len; | | 1106 | long len; |
1107 | char *cp; | | 1107 | char *cp; |
1108 | | | 1108 | |
1109 | if (!checkactive()) | | 1109 | if (!checkactive()) |
1110 | return 1; | | 1110 | return 1; |
1111 | | | 1111 | |
1112 | len = strtol(argv[1], &cp, 0); | | 1112 | len = strtol(argv[1], &cp, 0); |
1113 | if (cp == argv[1] || *cp != '\0' || len < 0) { | | 1113 | if (cp == argv[1] || *cp != '\0' || len < 0) { |
1114 | warnx("bad length '%s'", argv[1]); | | 1114 | warnx("bad length '%s'", argv[1]); |
1115 | return 1; | | 1115 | return 1; |
1116 | } | | 1116 | } |
1117 | DIP_SET(curinode, size, iswap64(len)); | | 1117 | DIP_SET(curinode, size, iswap64(len)); |
1118 | inodirty(); | | 1118 | inodirty(); |
1119 | printactive(); | | 1119 | printactive(); |
1120 | return 0; | | 1120 | return 0; |
1121 | } | | 1121 | } |
1122 | | | 1122 | |
1123 | CMDFUNCSTART(chaflags) | | 1123 | CMDFUNCSTART(chaflags) |
1124 | { | | 1124 | { |
1125 | u_long flags; | | 1125 | u_long flags; |
1126 | char *cp; | | 1126 | char *cp; |
1127 | | | 1127 | |
1128 | if (!checkactive()) | | 1128 | if (!checkactive()) |
1129 | return 1; | | 1129 | return 1; |
1130 | | | 1130 | |
1131 | flags = strtoul(argv[1], &cp, 0); | | 1131 | flags = strtoul(argv[1], &cp, 0); |
1132 | if (cp == argv[1] || *cp != '\0') { | | 1132 | if (cp == argv[1] || *cp != '\0') { |
1133 | warnx("bad flags `%s'", argv[1]); | | 1133 | warnx("bad flags `%s'", argv[1]); |
1134 | return 1; | | 1134 | return 1; |
1135 | } | | 1135 | } |
1136 | if (flags > UINT_MAX) { | | 1136 | if (flags > UINT_MAX) { |
1137 | warnx("flags set beyond 32-bit range of field (0x%lx)", | | 1137 | warnx("flags set beyond 32-bit range of field (0x%lx)", |
1138 | flags); | | 1138 | flags); |
1139 | return (1); | | 1139 | return (1); |
1140 | } | | 1140 | } |
1141 | DIP_SET(curinode, flags, iswap32(flags)); | | 1141 | DIP_SET(curinode, flags, iswap32(flags)); |