1 d0cda8c4 2005-07-28 devnull #include <u.h>
2 d0cda8c4 2005-07-28 devnull #include <libc.h>
3 d0cda8c4 2005-07-28 devnull #include <bio.h>
4 d0cda8c4 2005-07-28 devnull #include <thread.h>
5 d0cda8c4 2005-07-28 devnull #include <venti.h>
6 d0cda8c4 2005-07-28 devnull #include <sunrpc.h>
7 d0cda8c4 2005-07-28 devnull #include <nfs3.h>
8 d0cda8c4 2005-07-28 devnull #include <diskfs.h>
10 d0cda8c4 2005-07-28 devnull uchar *buf;
11 d0cda8c4 2005-07-28 devnull uint bufsize;
12 d0cda8c4 2005-07-28 devnull Nfs3Handle cwd, root;
13 d0cda8c4 2005-07-28 devnull Biobuf bin, bout;
14 d0cda8c4 2005-07-28 devnull char pwd[1000];
15 d0cda8c4 2005-07-28 devnull Fsys *fsys;
16 d0cda8c4 2005-07-28 devnull SunAuthUnix *auth;
17 d0cda8c4 2005-07-28 devnull VtConn *z;
18 d0cda8c4 2005-07-28 devnull VtCache *c;
19 d0cda8c4 2005-07-28 devnull Disk *disk;
21 d0cda8c4 2005-07-28 devnull char *cmdhelp(int, char**);
22 d0cda8c4 2005-07-28 devnull char *cmdcd(int, char**);
23 d0cda8c4 2005-07-28 devnull char *cmdpwd(int, char**);
24 d0cda8c4 2005-07-28 devnull char *cmdls(int, char**);
25 8ecefa41 2005-08-11 devnull char *cmdget(int, char**);
26 d0cda8c4 2005-07-28 devnull char *cmdblock(int, char**);
27 d0cda8c4 2005-07-28 devnull char *cmddisk(int, char**);
29 d0cda8c4 2005-07-28 devnull typedef struct Cmd Cmd;
30 d0cda8c4 2005-07-28 devnull struct Cmd
33 d0cda8c4 2005-07-28 devnull char *(*fn)(int, char**);
34 d0cda8c4 2005-07-28 devnull char *help;
37 fa325e9b 2020-01-10 cross Cmd cmdtab[] =
39 d0cda8c4 2005-07-28 devnull "cd", cmdcd, "cd dir - change directory",
40 d0cda8c4 2005-07-28 devnull "ls", cmdls, "ls [-d] path... - list file",
41 8ecefa41 2005-08-11 devnull "get", cmdget, "get path [lpath] - copy file to local directory",
42 d0cda8c4 2005-07-28 devnull "pwd", cmdpwd, "pwd - print working directory",
43 d0cda8c4 2005-07-28 devnull "help", cmdhelp, "help - print usage summaries",
44 d0cda8c4 2005-07-28 devnull "block", cmdblock, "block path offset - print disk offset of path's byte offset",
45 cbeb0b26 2006-04-01 devnull "disk", cmddisk, "disk offset count - dump disk contents"
49 d0cda8c4 2005-07-28 devnull ebuf(void)
51 d0cda8c4 2005-07-28 devnull static char buf[ERRMAX];
53 d0cda8c4 2005-07-28 devnull rerrstr(buf, sizeof buf);
54 d0cda8c4 2005-07-28 devnull return buf;
58 ff086a82 2008-06-01 rsc estrdup(char *s)
62 ff086a82 2008-06-01 rsc t = emalloc(strlen(s)+1);
63 ff086a82 2008-06-01 rsc strcpy(t, s);
68 d0cda8c4 2005-07-28 devnull walk(char *path, Nfs3Handle *ph)
70 d0cda8c4 2005-07-28 devnull char *p, *q;
71 d0cda8c4 2005-07-28 devnull Nfs3Handle h;
72 d0cda8c4 2005-07-28 devnull Nfs3Status ok;
74 ff086a82 2008-06-01 rsc path = estrdup(path); /* writable */
75 d0cda8c4 2005-07-28 devnull if(path[0] == '/')
76 d0cda8c4 2005-07-28 devnull h = root;
79 d0cda8c4 2005-07-28 devnull for(p=path; *p; p=q){
80 d0cda8c4 2005-07-28 devnull q = strchr(p, '/');
81 d0cda8c4 2005-07-28 devnull if(q == nil)
82 d0cda8c4 2005-07-28 devnull q = p+strlen(p);
84 d0cda8c4 2005-07-28 devnull *q++ = 0;
85 d0cda8c4 2005-07-28 devnull if(*p == 0)
86 d0cda8c4 2005-07-28 devnull continue;
87 d0cda8c4 2005-07-28 devnull if((ok = fsyslookup(fsys, auth, &h, p, &h)) != Nfs3Ok){
88 d0cda8c4 2005-07-28 devnull nfs3errstr(ok);
90 d0cda8c4 2005-07-28 devnull return ebuf();
95 d0cda8c4 2005-07-28 devnull return nil;
99 d0cda8c4 2005-07-28 devnull cmdhelp(int argc, char **argv)
103 d0cda8c4 2005-07-28 devnull for(i=0; i<nelem(cmdtab); i++)
104 d0cda8c4 2005-07-28 devnull print("%s\n", cmdtab[i].help);
105 d0cda8c4 2005-07-28 devnull return nil;
109 d0cda8c4 2005-07-28 devnull cmdcd(int argc, char **argv)
111 d0cda8c4 2005-07-28 devnull char *err;
112 d0cda8c4 2005-07-28 devnull Nfs3Attr attr;
113 d0cda8c4 2005-07-28 devnull Nfs3Status ok;
114 d0cda8c4 2005-07-28 devnull Nfs3Handle h;
116 d0cda8c4 2005-07-28 devnull if(argc != 2)
117 d0cda8c4 2005-07-28 devnull return "usage: cd dir";
119 d0cda8c4 2005-07-28 devnull if((err = walk(argv[1], &h)) != nil)
120 d0cda8c4 2005-07-28 devnull return err;
121 d0cda8c4 2005-07-28 devnull if((ok = fsysgetattr(fsys, auth, &h, &attr)) != Nfs3Ok){
122 d0cda8c4 2005-07-28 devnull nfs3errstr(ok);
123 ff086a82 2008-06-01 rsc fprint(2, "%s: %r\n", argv[1]);
124 d0cda8c4 2005-07-28 devnull return nil;
126 d0cda8c4 2005-07-28 devnull if(attr.type != Nfs3FileDir)
127 d0cda8c4 2005-07-28 devnull return "not a directory";
128 d0cda8c4 2005-07-28 devnull if(argv[1][0] == '/')
129 d0cda8c4 2005-07-28 devnull pwd[0] = 0;
130 d0cda8c4 2005-07-28 devnull strcat(pwd, "/");
131 d0cda8c4 2005-07-28 devnull strcat(pwd, argv[1]);
132 d0cda8c4 2005-07-28 devnull cleanname(pwd);
133 d0cda8c4 2005-07-28 devnull cwd = h;
134 d0cda8c4 2005-07-28 devnull print("%s\n", pwd);
135 d0cda8c4 2005-07-28 devnull return nil;
139 d0cda8c4 2005-07-28 devnull cmdpwd(int argc, char **argv)
141 d0cda8c4 2005-07-28 devnull if(argc != 1)
142 d0cda8c4 2005-07-28 devnull return "usage: pwd";
144 d0cda8c4 2005-07-28 devnull print("%s\n", pwd);
145 d0cda8c4 2005-07-28 devnull return nil;
149 d0cda8c4 2005-07-28 devnull * XXX maybe make a list of these in memory and then print them nicer
152 d0cda8c4 2005-07-28 devnull ls(char *dir, char *elem, Nfs3Attr *attr)
156 d0cda8c4 2005-07-28 devnull c = ' '; /* use attr->type */
157 d0cda8c4 2005-07-28 devnull Bprint(&bout, "%s%s%s", dir ? dir : "", dir && elem ? "/" : "", elem ? elem : "");
158 d0cda8c4 2005-07-28 devnull Bprint(&bout, " %c%luo %1d %4d %4d", c, attr->mode, attr->nlink, attr->uid, attr->gid);
159 d0cda8c4 2005-07-28 devnull Bprint(&bout, " %11,lld %11,lld %4d.%4d %#11,llux %#11,llux",
160 d0cda8c4 2005-07-28 devnull attr->size, attr->used, attr->major, attr->minor, attr->fsid, attr->fileid);
161 d0cda8c4 2005-07-28 devnull Bprint(&bout, "\n");
165 d0cda8c4 2005-07-28 devnull lsdir(char *dir, Nfs3Handle *h)
167 d0cda8c4 2005-07-28 devnull uchar *data, *p, *ep;
168 d0cda8c4 2005-07-28 devnull Nfs3Attr attr;
169 d0cda8c4 2005-07-28 devnull Nfs3Entry e;
170 d0cda8c4 2005-07-28 devnull Nfs3Handle eh;
171 d0cda8c4 2005-07-28 devnull u32int count;
172 d0cda8c4 2005-07-28 devnull u1int eof;
173 d0cda8c4 2005-07-28 devnull Nfs3Status ok;
174 d0cda8c4 2005-07-28 devnull u64int cookie;
176 d0cda8c4 2005-07-28 devnull cookie = 0;
177 d0cda8c4 2005-07-28 devnull for(;;){
178 d0cda8c4 2005-07-28 devnull ok = fsysreaddir(fsys, auth, h, 8192, cookie, &data, &count, &eof);
179 d0cda8c4 2005-07-28 devnull if(ok != Nfs3Ok){
180 d0cda8c4 2005-07-28 devnull nfs3errstr(ok);
181 d0cda8c4 2005-07-28 devnull fprint(2, "ls %s: %r\n", dir);
184 8ecefa41 2005-08-11 devnull fprint(2, "got %d\n", count);
185 d0cda8c4 2005-07-28 devnull p = data;
186 d0cda8c4 2005-07-28 devnull ep = data+count;
187 d0cda8c4 2005-07-28 devnull while(p<ep){
188 d0cda8c4 2005-07-28 devnull if(nfs3entryunpack(p, ep, &p, &e) < 0){
189 d0cda8c4 2005-07-28 devnull fprint(2, "%s: unpacking directory: %r\n", dir);
192 d0cda8c4 2005-07-28 devnull cookie = e.cookie;
193 d0cda8c4 2005-07-28 devnull if((ok = fsyslookup(fsys, auth, h, e.name, &eh)) != Nfs3Ok){
194 d0cda8c4 2005-07-28 devnull nfs3errstr(ok);
195 d0cda8c4 2005-07-28 devnull fprint(2, "%s/%s: %r\n", dir, e.name);
196 d0cda8c4 2005-07-28 devnull continue;
198 d0cda8c4 2005-07-28 devnull if((ok = fsysgetattr(fsys, auth, &eh, &attr)) != Nfs3Ok){
199 d0cda8c4 2005-07-28 devnull nfs3errstr(ok);
200 d0cda8c4 2005-07-28 devnull fprint(2, "%s/%s: %r\n", dir, e.name);
201 d0cda8c4 2005-07-28 devnull continue;
203 d0cda8c4 2005-07-28 devnull ls(dir, e.name, &attr);
205 d0cda8c4 2005-07-28 devnull free(data);
212 d0cda8c4 2005-07-28 devnull cmdls(int argc, char **argv)
215 d0cda8c4 2005-07-28 devnull int dflag;
216 d0cda8c4 2005-07-28 devnull char *e;
217 d0cda8c4 2005-07-28 devnull Nfs3Handle h;
218 d0cda8c4 2005-07-28 devnull Nfs3Attr attr;
219 d0cda8c4 2005-07-28 devnull Nfs3Status ok;
221 d0cda8c4 2005-07-28 devnull dflag = 0;
222 d0cda8c4 2005-07-28 devnull ARGBEGIN{
223 d0cda8c4 2005-07-28 devnull case 'd':
224 d0cda8c4 2005-07-28 devnull dflag = 1;
226 d0cda8c4 2005-07-28 devnull default:
227 d0cda8c4 2005-07-28 devnull return "usage: ls [-d] [path...]";
230 d0cda8c4 2005-07-28 devnull if(argc == 0){
231 d0cda8c4 2005-07-28 devnull lsdir(nil, &cwd);
232 d0cda8c4 2005-07-28 devnull Bflush(&bout);
233 d0cda8c4 2005-07-28 devnull return nil;
236 d0cda8c4 2005-07-28 devnull for(i=0; i<argc; i++){
237 d0cda8c4 2005-07-28 devnull if((e = walk(argv[i], &h)) != nil){
238 d0cda8c4 2005-07-28 devnull fprint(2, "%s: %s\n", argv[i], e);
239 d0cda8c4 2005-07-28 devnull continue;
241 d0cda8c4 2005-07-28 devnull if((ok = fsysgetattr(fsys, auth, &h, &attr)) != Nfs3Ok){
242 d0cda8c4 2005-07-28 devnull nfs3errstr(ok);
243 d0cda8c4 2005-07-28 devnull fprint(2, "%s: %r\n", argv[i]);
244 d0cda8c4 2005-07-28 devnull continue;
246 d0cda8c4 2005-07-28 devnull if(attr.type != Nfs3FileDir || dflag)
247 d0cda8c4 2005-07-28 devnull ls(argv[i], nil, &attr);
249 d0cda8c4 2005-07-28 devnull lsdir(argv[i], &h);
250 d0cda8c4 2005-07-28 devnull Bflush(&bout);
252 d0cda8c4 2005-07-28 devnull return nil;
256 8ecefa41 2005-08-11 devnull cmdget(int argc, char **argv)
258 8ecefa41 2005-08-11 devnull uchar eof;
259 8ecefa41 2005-08-11 devnull u32int n;
260 8ecefa41 2005-08-11 devnull int dflag, fd;
261 8ecefa41 2005-08-11 devnull char *e, *local;
262 8ecefa41 2005-08-11 devnull uchar *buf;
263 8ecefa41 2005-08-11 devnull Nfs3Handle h;
264 8ecefa41 2005-08-11 devnull Nfs3Attr attr;
265 8ecefa41 2005-08-11 devnull Nfs3Status ok;
266 8ecefa41 2005-08-11 devnull vlong o;
268 8ecefa41 2005-08-11 devnull dflag = 0;
269 8ecefa41 2005-08-11 devnull ARGBEGIN{
270 8ecefa41 2005-08-11 devnull default:
272 8ecefa41 2005-08-11 devnull return "usage: get path [lpath]]";
275 8ecefa41 2005-08-11 devnull if(argc != 1 && argc != 2)
276 8ecefa41 2005-08-11 devnull goto usage;
278 8ecefa41 2005-08-11 devnull if((e = walk(argv[0], &h)) != nil){
279 8ecefa41 2005-08-11 devnull fprint(2, "%s: %s\n", argv[0], e);
280 8ecefa41 2005-08-11 devnull return nil;
282 8ecefa41 2005-08-11 devnull if((ok = fsysgetattr(fsys, auth, &h, &attr)) != Nfs3Ok){
283 8ecefa41 2005-08-11 devnull nfs3errstr(ok);
284 8ecefa41 2005-08-11 devnull fprint(2, "%s: %r\n", argv[0]);
285 8ecefa41 2005-08-11 devnull return nil;
287 8ecefa41 2005-08-11 devnull local = argv[0];
288 8ecefa41 2005-08-11 devnull if(argc == 2)
289 8ecefa41 2005-08-11 devnull local = argv[1];
290 8ecefa41 2005-08-11 devnull if((fd = create(local, OWRITE, 0666)) < 0){
291 8ecefa41 2005-08-11 devnull fprint(2, "create %s: %r\n", local);
292 8ecefa41 2005-08-11 devnull return nil;
294 8ecefa41 2005-08-11 devnull eof = 0;
295 8ecefa41 2005-08-11 devnull for(o=0; o<attr.size && !eof; o+=n){
296 8ecefa41 2005-08-11 devnull if((ok = fsysreadfile(fsys, nil, &h, fsys->blocksize, o, &buf, &n, &eof)) != Nfs3Ok){
297 8ecefa41 2005-08-11 devnull nfs3errstr(ok);
298 8ecefa41 2005-08-11 devnull fprint(2, "reading %s: %r\n", argv[0]);
299 8ecefa41 2005-08-11 devnull close(fd);
300 8ecefa41 2005-08-11 devnull return nil;
302 8ecefa41 2005-08-11 devnull if(write(fd, buf, n) != n){
303 8ecefa41 2005-08-11 devnull fprint(2, "writing %s: %r\n", local);
304 8ecefa41 2005-08-11 devnull close(fd);
305 8ecefa41 2005-08-11 devnull free(buf);
306 8ecefa41 2005-08-11 devnull return nil;
308 8ecefa41 2005-08-11 devnull free(buf);
310 8ecefa41 2005-08-11 devnull close(fd);
311 8ecefa41 2005-08-11 devnull fprint(2, "copied %,lld bytes\n", o);
312 8ecefa41 2005-08-11 devnull return nil;
317 d0cda8c4 2005-07-28 devnull cmdblock(int argc, char **argv)
319 d0cda8c4 2005-07-28 devnull char *e;
320 d0cda8c4 2005-07-28 devnull Nfs3Handle h;
321 d0cda8c4 2005-07-28 devnull u64int bno;
323 d0cda8c4 2005-07-28 devnull ARGBEGIN{
324 d0cda8c4 2005-07-28 devnull default:
325 d0cda8c4 2005-07-28 devnull return "usage: block path offset";
328 d0cda8c4 2005-07-28 devnull if(argc != 2)
329 d0cda8c4 2005-07-28 devnull return "usage: block path offset";
331 d0cda8c4 2005-07-28 devnull if((e = walk(argv[0], &h)) != nil){
332 d0cda8c4 2005-07-28 devnull fprint(2, "%s: %s\n", argv[0], e);
333 d0cda8c4 2005-07-28 devnull return nil;
335 d0cda8c4 2005-07-28 devnull if((bno = fsys->fileblock(fsys, &h, strtoll(argv[1], 0, 0))) == 0){
336 d0cda8c4 2005-07-28 devnull fprint(2, "%s: %r\n", argv[0]);
337 d0cda8c4 2005-07-28 devnull return nil;
339 d0cda8c4 2005-07-28 devnull print("%#llux\n", bno);
340 d0cda8c4 2005-07-28 devnull return nil;
344 d0cda8c4 2005-07-28 devnull cmddisk(int argc, char **argv)
346 d0cda8c4 2005-07-28 devnull Block *b;
347 d0cda8c4 2005-07-28 devnull int delta, count, i;
348 d0cda8c4 2005-07-28 devnull u64int offset;
349 d0cda8c4 2005-07-28 devnull uchar *p;
351 d0cda8c4 2005-07-28 devnull ARGBEGIN{
352 d0cda8c4 2005-07-28 devnull default:
353 d0cda8c4 2005-07-28 devnull return "usage: disk offset count";
356 d0cda8c4 2005-07-28 devnull if(argc != 2)
357 d0cda8c4 2005-07-28 devnull return "usage: disk offset count";
359 d0cda8c4 2005-07-28 devnull offset = strtoull(argv[0], 0, 0);
360 d0cda8c4 2005-07-28 devnull count = atoi(argv[1]);
361 d0cda8c4 2005-07-28 devnull delta = offset%fsys->blocksize;
363 d0cda8c4 2005-07-28 devnull b = diskread(disk, fsys->blocksize, offset-delta);
364 d0cda8c4 2005-07-28 devnull if(b == nil){
365 d0cda8c4 2005-07-28 devnull fprint(2, "diskread: %r\n");
366 d0cda8c4 2005-07-28 devnull return nil;
368 d0cda8c4 2005-07-28 devnull p = b->data + delta;
369 d0cda8c4 2005-07-28 devnull for(i=0; i<count; i++){
370 d0cda8c4 2005-07-28 devnull Bprint(&bout, "%2.2ux ", p[i]);
371 d0cda8c4 2005-07-28 devnull if(i%16 == 15)
372 d0cda8c4 2005-07-28 devnull Bprint(&bout, "\n");
373 d0cda8c4 2005-07-28 devnull else if(i%8 == 7)
374 d0cda8c4 2005-07-28 devnull Bprint(&bout, " - ");
376 d0cda8c4 2005-07-28 devnull if(i%16 != 0)
377 d0cda8c4 2005-07-28 devnull Bprint(&bout, "\n");
378 d0cda8c4 2005-07-28 devnull Bflush(&bout);
379 d0cda8c4 2005-07-28 devnull blockput(b);
380 d0cda8c4 2005-07-28 devnull return nil;
384 d0cda8c4 2005-07-28 devnull usage(void)
386 d0cda8c4 2005-07-28 devnull fprint(2, "usage: vftp score\n");
387 d0cda8c4 2005-07-28 devnull threadexitsall("usage");
390 dbf91a04 2006-06-15 devnull extern int allowall;
393 d0cda8c4 2005-07-28 devnull threadmain(int argc, char **argv)
395 d0cda8c4 2005-07-28 devnull char *err, *f[10], *p;
396 d0cda8c4 2005-07-28 devnull int i, nf;
397 d0cda8c4 2005-07-28 devnull uchar score[VtScoreSize];
398 d0cda8c4 2005-07-28 devnull Nfs3Status ok;
400 dbf91a04 2006-06-15 devnull allowall = 1;
401 d0cda8c4 2005-07-28 devnull ARGBEGIN{
402 d0cda8c4 2005-07-28 devnull case 'V':
403 d0cda8c4 2005-07-28 devnull chattyventi++;
405 d0cda8c4 2005-07-28 devnull default:
406 d0cda8c4 2005-07-28 devnull usage();
409 d0cda8c4 2005-07-28 devnull if(argc != 1)
410 d0cda8c4 2005-07-28 devnull usage();
412 d0cda8c4 2005-07-28 devnull fmtinstall('F', vtfcallfmt);
413 d0cda8c4 2005-07-28 devnull fmtinstall('H', encodefmt);
414 d0cda8c4 2005-07-28 devnull fmtinstall('V', vtscorefmt);
416 8ecefa41 2005-08-11 devnull if(access(argv[0], AEXIST) >= 0 || strchr(argv[0], '/')){
417 8ecefa41 2005-08-11 devnull if((disk = diskopenfile(argv[0])) == nil)
418 8ecefa41 2005-08-11 devnull sysfatal("diskopen: %r");
419 651ababc 2006-06-26 devnull if((disk = diskcache(disk, 32768, 16)) == nil)
420 8ecefa41 2005-08-11 devnull sysfatal("diskcache: %r");
422 8ecefa41 2005-08-11 devnull if(vtparsescore(argv[0], nil, score) < 0)
423 8ecefa41 2005-08-11 devnull sysfatal("bad score '%s'", argv[0]);
424 8ecefa41 2005-08-11 devnull if((z = vtdial(nil)) == nil)
425 8ecefa41 2005-08-11 devnull sysfatal("vtdial: %r");
426 8ecefa41 2005-08-11 devnull if(vtconnect(z) < 0)
427 8ecefa41 2005-08-11 devnull sysfatal("vtconnect: %r");
428 651ababc 2006-06-26 devnull if((c = vtcachealloc(z, 32768, 32)) == nil)
429 8ecefa41 2005-08-11 devnull sysfatal("vtcache: %r");
430 8ecefa41 2005-08-11 devnull if((disk = diskopenventi(c, score)) == nil)
431 8ecefa41 2005-08-11 devnull sysfatal("diskopenventi: %r");
433 d0cda8c4 2005-07-28 devnull if((fsys = fsysopen(disk)) == nil)
434 83ab7d88 2007-11-27 rsc sysfatal("fsysopen: %r");
436 d0cda8c4 2005-07-28 devnull fprint(2, "block size %d\n", fsys->blocksize);
437 d0cda8c4 2005-07-28 devnull buf = emalloc(fsys->blocksize);
438 d0cda8c4 2005-07-28 devnull if((ok = fsysroot(fsys, &root)) != Nfs3Ok){
439 d0cda8c4 2005-07-28 devnull nfs3errstr(ok);
440 d0cda8c4 2005-07-28 devnull sysfatal("accessing root: %r");
442 d0cda8c4 2005-07-28 devnull cwd = root;
443 d0cda8c4 2005-07-28 devnull Binit(&bin, 0, OREAD);
444 d0cda8c4 2005-07-28 devnull Binit(&bout, 1, OWRITE);
446 d0cda8c4 2005-07-28 devnull while(fprint(2, "vftp> "), (p = Brdstr(&bin, '\n', 1)) != nil){
447 d0cda8c4 2005-07-28 devnull if(p[0] == '#')
448 d0cda8c4 2005-07-28 devnull continue;
449 d0cda8c4 2005-07-28 devnull nf = tokenize(p, f, nelem(f));
450 d0cda8c4 2005-07-28 devnull if(nf == 0)
451 d0cda8c4 2005-07-28 devnull continue;
452 d0cda8c4 2005-07-28 devnull for(i=0; i<nelem(cmdtab); i++){
453 d0cda8c4 2005-07-28 devnull if(strcmp(f[0], cmdtab[i].s) == 0){
454 d0cda8c4 2005-07-28 devnull if((err = cmdtab[i].fn(nf, f)) != nil)
455 d0cda8c4 2005-07-28 devnull fprint(2, "%s\n", err);
459 d0cda8c4 2005-07-28 devnull if(i == nelem(cmdtab))
460 d0cda8c4 2005-07-28 devnull fprint(2, "unknown command '%s'\n", f[0]);
462 d0cda8c4 2005-07-28 devnull threadexitsall(nil);