]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/cwfs/con.c
grep: error if sbrk fails
[plan9front.git] / sys / src / cmd / cwfs / con.c
1 #include "all.h"
2
3 static  Command command[100];
4 static  Flag    flag[35];
5 static  char    statsdef[20];   /* default stats list */
6 static  int     whoflag;
7
8 static  void    consserve1(void *);
9 static  void    installcmds(void);
10 static  void    tzinit(char*);
11
12 void
13 consserve(void)
14 {
15         int i;
16
17         snprint(cons.chan->whochan, sizeof(cons.chan->whochan), "console");
18         installcmds();
19         con_session();
20         cmd_exec("cfs");
21         cmd_exec("users");
22         cmd_exec("version");
23
24         for(i = 0; command[i].arg0; i++)
25                 if(strcmp("cwcmd", command[i].arg0) == 0){
26                         cmd_exec("cwcmd touchsb");
27                         break;
28                 }
29
30         /* switch console output to the cmd pipe */
31         dup(0, 1);
32
33         newproc(consserve1, 0, "con");
34 }
35
36 /* console commands process */
37 static void
38 consserve1(void *)
39 {
40         char *conline;
41
42         while(conline = Brdline(&bin, '\n')){
43                 conline[Blinelen(&bin)-1] = '\0';
44                 cmd_exec(conline);
45         }
46 }
47
48 static int
49 cmdcmp(void *va, void *vb)
50 {
51         Command *a, *b;
52
53         a = va;
54         b = vb;
55         return strcmp(a->arg0, b->arg0);
56 }
57
58 void
59 cmd_install(char *arg0, char *help, void (*func)(int, char*[]))
60 {
61         int i;
62
63         qlock(&cons);
64         for(i=0; command[i].arg0; i++)
65                 ;
66         if(i >= nelem(command)-2) {
67                 qunlock(&cons);
68                 print("cmd_install: too many commands\n");
69                 return;
70         }
71         command[i+1].arg0 = 0;
72         command[i].help = help;
73         command[i].func = func;
74         command[i].arg0 = arg0;
75         qsort(command, i+1, sizeof(Command), cmdcmp);
76         qunlock(&cons);
77 }
78
79 void
80 cmd_exec(char *arg)
81 {
82         char line[2*Maxword], *s;
83         char *argv[10];
84         int argc, i, c;
85
86         if(strlen(arg) >= nelem(line)-2) {
87                 print("cmd_exec: line too long\n");
88                 return;
89         }
90         strcpy(line, arg);
91
92         argc = 0;
93         s = line;
94         c = *s++;
95         for(;;) {
96                 while(isascii(c) && isspace(c))
97                         c = *s++;
98                 if(c == 0)
99                         break;
100                 if(argc >= nelem(argv)-2) {
101                         print("cmd_exec: too many args\n");
102                         return;
103                 }
104                 argv[argc++] = s-1;
105                 while((!isascii(c) || !isspace(c)) && c != '\0')
106                         c = *s++;
107                 s[-1] = 0;
108         }
109         if(argc <= 0)
110                 return;
111         for(i=0; s=command[i].arg0; i++)
112                 if(strcmp(argv[0], s) == 0) {
113                         (*command[i].func)(argc, argv);
114                         return;
115                 }
116         print("cmd_exec: unknown command: %s\n", argv[0]);
117 }
118
119 static void
120 cmd_halt(int, char *[])
121 {
122         wlock(&mainlock);       /* halt */
123         sync("halt");
124         exit();
125 }
126
127 static void
128 cmd_duallow(int argc, char *argv[])
129 {
130         int uid;
131
132         if(argc <= 1) {
133                 duallow = 0;
134                 return;
135         }
136
137         uid = strtouid(argv[1]);
138         if(uid < 0)
139                 uid = number(argv[1], -2, 10);
140         if(uid < 0) {
141                 print("bad uid %s\n", argv[1]);
142                 return;
143         }
144         duallow = uid;
145 }
146
147 static void
148 cmd_stats(int argc, char *argv[])
149 {
150         int i, c;
151         char buf[30], *s, *p, *q;
152
153         if(argc <= 1) {
154                 if(statsdef[0] == 0)
155                         strcpy(statsdef, "a");
156                 sprint(buf, "stats s%s", statsdef);
157                 cmd_exec(buf);
158                 return;
159         }
160
161         strcpy(buf, "stat");
162         p = strchr(buf, 0);
163         p[1] = 0;
164
165         q = 0;
166         for(i = 1; i < argc; i++)
167                 for(s = argv[i]; c = *s; s++) {
168                         if(c == 's')
169                                 continue;
170                         if(c == '-') {
171                                 q = statsdef;
172                                 continue;
173                         }
174                         if(q) {
175                                 *q++ = c;
176                                 *q = 0;
177                         }
178                         *p = c;
179                         cmd_exec(buf);
180                 }
181 }
182
183 static void
184 cmd_stata(int, char *[])
185 {
186         int i;
187
188         print("cons stats\n");
189 //      print("\twork =%7W%7W%7W rps\n", cons.work+0, cons.work+1, cons.work+2);
190 //      print("\trate =%7W%7W%7W tBps\n", cons.rate+0, cons.rate+1, cons.rate+2);
191 //      print("\thits =%7W%7W%7W iops\n", cons.bhit+0, cons.bhit+1, cons.bhit+2);
192 //      print("\tread =%7W%7W%7W iops\n", cons.bread+0, cons.bread+1, cons.bread+2);
193 //      print("\trah  =%7W%7W%7W iops\n", cons.brahead+0, cons.brahead+1, cons.brahead+2);
194 //      print("\tinit =%7W%7W%7W iops\n", cons.binit+0, cons.binit+1, cons.binit+2);
195         print("\tbufs =    %3ld sm %3ld lg %ld res\n",
196                 cons.nsmall, cons.nlarge, cons.nreseq);
197
198         for(i=0; i<nelem(mballocs); i++)
199                 if(mballocs[i])
200                         print("\t[%d]=%d\n", i, mballocs[i]);
201
202         print("\tioerr=    %3ld wr %3ld ww %3ld dr %3ld dw\n",
203                 cons.nwormre, cons.nwormwe, cons.nwrenre, cons.nwrenwe);
204         print("\tcache=     %9ld hit %9ld miss\n",
205                 cons.nwormhit, cons.nwormmiss);
206 }
207
208 static int
209 flagcmp(void *va, void *vb)
210 {
211         Flag *a, *b;
212
213         a = va;
214         b = vb;
215         return strcmp(a->arg0, b->arg0);
216 }
217
218 ulong
219 flag_install(char *arg, char *help)
220 {
221         int i;
222
223         qlock(&cons);
224         for(i=0; flag[i].arg0; i++)
225                 ;
226         if(i >= 32) {
227                 qunlock(&cons);
228                 print("flag_install: too many flags\n");
229                 return 0;
230         }
231         flag[i+1].arg0 = 0;
232         flag[i].arg0 = arg;
233         flag[i].help = help;
234         flag[i].flag = 1<<i;
235         qsort(flag, i+1, sizeof(Flag), flagcmp);
236         qunlock(&cons);
237         return 1<<i;
238 }
239
240 void
241 cmd_flag(int argc, char *argv[])
242 {
243         int f, n, i, j;
244         char *s;
245         Chan *cp;
246
247         if(argc <= 1) {
248                 for(i=0; flag[i].arg0; i++)
249                         print("%.4lux %s %s\n",
250                                 flag[i].flag, flag[i].arg0, flag[i].help);
251                 if(cons.flags)
252                         print("flag[*]   = %.4lux\n", cons.flags);
253                 for(cp = chans; cp; cp = cp->next)
254                         if(cp->flags)
255                                 print("flag[%3d] = %.4lux\n", cp->chan, cp->flags);
256                 return;
257         }
258
259         f = 0;
260         n = -1;
261         for(i=1; i<argc; i++) {
262                 for(j=0; s=flag[j].arg0; j++)
263                         if(strcmp(s, argv[i]) == 0)
264                                 goto found;
265                 j = number(argv[i], -1, 10);
266                 if(j < 0) {
267                         print("bad flag argument: %s\n", argv[i]);
268                         continue;
269                 }
270                 n = j;
271                 continue;
272         found:
273                 f |= flag[j].flag;
274         }
275
276         if(n < 0) {
277                 cons.flags ^= f;
278                 if(f == 0)
279                         cons.flags = 0;
280                 print("flag      = %.8lux\n", cons.flags);
281                 return;
282         }
283         for(cp = chans; cp; cp = cp->next)
284                 if(cp->chan == n) {
285                         cp->flags ^= f;
286                         if(f == 0)
287                                 cp->flags = 0;
288                         print("flag[%3d] = %.8lux\n", cp->chan, cp->flags);
289                         return;
290                 }
291         print("no such channel\n");
292 }
293
294 static void
295 cmd_who(int argc, char *argv[])
296 {
297         Chan *cp;
298         int i, c;
299
300         c = 0;
301         for(cp = chans; cp; cp = cp->next) {
302                 if(cp->whotime == 0 && !(cons.flags & whoflag)) {
303                         c++;
304                         continue;
305                 }
306                 if(argc > 1) {
307                         for(i=1; i<argc; i++)
308                                 if(strcmp(argv[i], cp->whoname) == 0)
309                                         break;
310                         if(i >= argc) {
311                                 c++;
312                                 continue;
313                         }
314                 }
315                 print("%3d: %10s %24s", cp->chan, cp->whoname, cp->whochan);
316                 if(cp->whoprint)
317                         cp->whoprint(cp);
318                 print("\n");
319         }
320         if(c > 0)
321                 print("%d chans not listed\n", c);
322 }
323
324 static void
325 cmd_hangup(int argc, char *argv[])
326 {
327         Chan *cp;
328         int n;
329
330         if(argc < 2) {
331                 print("usage: hangup chan-number\n");
332                 return;
333         }
334         n = number(argv[1], -1, 10);
335         for(cp = chans; cp; cp = cp->next) {
336                 if(cp->whotime == 0) {
337                         if(cp->chan == n)
338                                 print("that chan is hung up\n");
339                         continue;
340                 }
341                 if(cp->chan == n)
342                         chanhangup(cp, "console command");
343         }
344 }
345
346 static void
347 cmd_sync(int, char *[])
348 {
349         wlock(&mainlock);       /* sync */
350         sync("command");
351         wunlock(&mainlock);
352 }
353
354 static void
355 cmd_help(int argc, char *argv[])
356 {
357         char *arg;
358         int i, j;
359
360         for(i=0; arg=command[i].arg0; i++) {
361                 if(argc > 1) {
362                         for(j=1; j<argc; j++)
363                                 if(strcmp(argv[j], arg) == 0)
364                                         goto found;
365                         continue;
366                 }
367         found:
368                 print("\t%s %s\n", arg, command[i].help);
369         }
370 }
371
372 void
373 cmd_fstat(int argc, char *argv[])
374 {
375         int i;
376
377         for(i=1; i<argc; i++) {
378                 if(walkto(argv[i])) {
379                         print("cant stat %s\n", argv[i]);
380                         continue;
381                 }
382                 con_fstat(FID2);
383         }
384 }
385
386 void
387 cmd_create(int argc, char *argv[])
388 {
389         int uid, gid;
390         long perm;
391         char elem[NAMELEN], *p;
392
393         if(argc < 5) {
394                 print("usage: create path uid gid mode [lad]\n");
395                 return;
396         }
397
398         p = utfrrune(argv[1], '/');
399         if(p) {
400                 *p++ = 0;
401                 if(walkto(argv[1])) {
402                         print("create failed in walkto: %s\n", p);
403                         return;
404                 }
405         } else {
406                 if(walkto("/"))
407                         return;
408                 p = argv[1];
409         }
410         if(strlen(p) >= NAMELEN) {
411                 print("name too long %s\n", p);
412                 return;
413         }
414
415         memset(elem, 0, sizeof(elem));
416         strcpy(elem, p);
417
418         uid = strtouid(argv[2]);
419         if(uid < -1)
420                 uid = number(argv[2], -2, 10);
421         if(uid < -1) {
422                 print("bad uid %s\n", argv[2]);
423                 return;
424         }
425
426         gid = strtouid(argv[3]);
427         if(gid < -1)
428                 gid = number(argv[3], -2, 10);
429         if(gid < -1) {
430                 print("bad gid %s\n", argv[3]);
431                 return;
432         }
433
434         perm = number(argv[4], 0777, 8) & 0777;
435
436         if(argc > 5) {
437                 if(strchr(argv[5], 'l'))
438                         perm |= DMEXCL;
439                 if(strchr(argv[5], 'a'))
440                         perm |= DMAPPEND;
441                 if(strchr(argv[5], 'd'))
442                         perm |= DMDIR;
443                 if(strchr(argv[5], 't'))
444                         perm |= DMTMP;
445         }
446
447         if(con_create(FID2, elem, uid, gid, perm, 0))
448                 print("create failed: %s/%s\n", argv[1], p);
449 }
450
451 static void
452 cmd_clri(int argc, char *argv[])
453 {
454         int i;
455
456         for(i=1; i<argc; i++) {
457                 if(walkto(argv[i])) {
458                         print("cant remove %s\n", argv[i]);
459                         continue;
460                 }
461                 con_clri(FID2);
462         }
463 }
464
465 static void
466 cmd_allow(int argc, char *argv[])
467 {
468         char *name;
469         int uid;
470
471         uid = -1;
472         name = "any user";
473         if(argc > 1){
474                 name = argv[1];
475                 uid = strtouid(name);
476                 if(uid < 0)
477                         uid = number(name, -2, 10);
478                 if(uid < 0) {
479                         print("bad uid %s\n", name);
480                         return;
481                 }
482         }
483         print("allowed %s\n", name);
484         allowed = uid;
485 }
486
487 static void
488 cmd_disallow(int, char**)
489 {
490         allowed = 0;
491 }
492
493 void
494 ckblock(Device *d, Off a, int typ, Off qpath)
495 {
496         Iobuf *p;
497
498         if(a) {
499                 p = getbuf(d, a, Brd);
500                 if(p) {
501                         checktag(p, typ, qpath);
502                         putbuf(p);
503                 }
504         }
505 }
506
507 void
508 doclean(Iobuf *p, Dentry *d, int n, Off a)
509 {
510         int i, mod, typ;
511         Off qpath;
512
513         mod = 0;
514         qpath = d->qid.path;
515         typ = Tfile;
516         if(d->mode & DDIR){
517                 qpath ^= QPDIR;
518                 typ = Tdir;
519         }
520         for(i=0; i<NDBLOCK; i++) {
521                 print("dblock[%d] = %lld\n", i, (Wideoff)d->dblock[i]);
522                 ckblock(p->dev, d->dblock[i], typ, qpath);
523                 if(i == n) {
524                         d->dblock[i] = a;
525                         mod = 1;
526                         print("dblock[%d] modified %lld\n", i, (Wideoff)a);
527                 }
528         }
529
530         /* add NDBLOCK so user can cite block address by index */
531         for (i = 0; i < NIBLOCK; i++) {
532                 print("iblocks[%d] = %lld\n", NDBLOCK+i, (Wideoff)d->iblocks[i]);
533                 ckblock(p->dev, d->iblocks[i], Tind1+i, qpath);
534                 if(NDBLOCK+i == n) {
535                         d->iblocks[i] = a;
536                         mod = 1;
537                         print("iblocks[%d] modified %lld\n", NDBLOCK+i, (Wideoff)a);
538                 }
539         }
540
541         if(mod)
542                 p->flags |= Bmod|Bimm;
543 }
544
545 static void
546 cmd_clean(int argc, char *argv[])
547 {
548         int n;
549         Off a;
550         Iobuf *p;
551         Dentry *d;
552         File *f;
553
554         p = 0;
555         f = 0;
556         while(argc > 1) {
557                 n = -1;
558                 if(argc > 2)
559                         n = number(argv[2], -1, 10);
560                 a = 0;
561                 if(argc > 3)
562                         a = number(argv[3], 0, 10);
563                 if(walkto(argv[1])) {
564                         print("cant remove %s\n", argv[1]);
565                         break;
566                 }
567                 f = filep(cons.chan, FID2, 0);
568                 if(!f)
569                         break;
570                 if(n >= 0 && f->fs->dev->type == Devro) {
571                         print("readonly %s\n", argv[1]);
572                         break;
573                 }
574                 p = getbuf(f->fs->dev, f->addr, Brd);
575                 d = getdir(p, f->slot);
576                 if(!d || !(d->mode & DALLOC)) {
577                         print("not alloc %s\n", argv[1]);
578                         break;
579                 }
580                 doclean(p, d, n, a);
581                 break;
582         }
583         if(f)
584                 qunlock(f);
585         if(p)
586                 putbuf(p);
587 }
588
589 static void
590 cmd_remove(int argc, char *argv[])
591 {
592         int i;
593
594         for(i=1; i<argc; i++) {
595                 if(walkto(argv[i])) {
596                         print("cant remove %s\n", argv[i]);
597                         continue;
598                 }
599                 con_remove(FID2);
600         }
601 }
602
603 static void
604 cmd_version(int, char *[])
605 {
606         tzinit("/adm/timezone/local");
607         print("%d-bit %s as of %T\n", sizeof(Off)*8 - 1, service, fs_mktime);
608         print("\tlast boot %T\n", boottime);
609 }
610
611 static void
612 cmd_cfs(int argc, char *argv[])
613 {
614         Filsys *fs;
615         char *name;
616
617         name = "main";
618         if(argc > 1)
619                 name = argv[1];
620         fs = fsstr(name);
621         if(fs == 0) {
622                 print("%s: unknown file system\n", name);
623                 if(cons.curfs)
624                         return;
625                 fs = &filsys[0];
626         }
627         if(con_attach(FID1, "adm", fs->name))
628                 panic("FID1 attach to root");
629         cons.curfs = fs;
630         print("current fs is \"%s\"\n", cons.curfs->name);
631 }
632
633 static void
634 cmd_prof(int argc, char *argv[])
635 {
636         int n;
637         long m, o;
638         char *p;
639
640         if(cons.profbuf == 0) {
641                 print("no buffer\n");
642                 return;
643         }
644         n = !cons.profile;
645         if(argc > 1)
646                 n = number(argv[1], n, 10);
647         if(n && !cons.profile) {
648                 print("clr and start\n");
649                 memset(cons.profbuf, 0, cons.nprofbuf*sizeof(cons.profbuf[0]));
650                 cons.profile = 1;
651                 return;
652         }
653         if(!n && cons.profile) {
654                 cons.profile = 0;
655                 print("stop and write\n");
656                 if(walkto("/adm/kprofdata"))
657                         goto bad;
658                 if(con_open(FID2, OWRITE|OTRUNC)) {
659                 bad:
660                         print("cant open /adm/kprofdata\n");
661                         return;
662                 }
663                 p = (char*)cons.profbuf;
664                 for(m=0; m<cons.nprofbuf; m++) {
665                         n = cons.profbuf[m];
666                         p[0] = n>>24;
667                         p[1] = n>>16;
668                         p[2] = n>>8;
669                         p[3] = n>>0;
670                         p += 4;
671                 }
672
673                 m = cons.nprofbuf*sizeof(cons.profbuf[0]);
674                 o = 0;
675                 while(m > 0) {
676                         n = 8192;
677                         if(n > m)
678                                 n = m;
679                         con_write(FID2, (char*)cons.profbuf+o, o, n);
680                         m -= n;
681                         o += n;
682                 }
683                 return;
684         }
685 }
686
687 static void
688 tzinit(char *file)
689 {
690         char buf[1024];
691         Off o;
692         int f, n;
693
694         f = create("#e/timezone", OEXCL|OWRITE, 0666);
695         if(f < 0)
696                 return;
697         if(walkto(file) || con_open(FID2, 0)) {
698                 print("tzinit: cannot access %s\n", file);
699                 close(f);
700                 remove("#e/timezone");
701                 return;
702         }
703         for(o = 0; (n = con_read(FID2, buf, o, sizeof(buf))) > 0; o += n)
704                 write(f, buf, n);
705         close(f);
706 }
707
708
709 static void
710 cmd_time(int argc, char *argv[])
711 {
712         int i, len;
713         char *cmd;
714         Timet t1, t2;
715
716         t1 = time(nil);
717         len = 0;
718         for(i=1; i<argc; i++)
719                 len += 1 + strlen(argv[i]);
720         cmd = malloc(len + 1);
721         cmd[0] = 0;
722         for(i=1; i<argc; i++) {
723                 strcat(cmd, " ");
724                 strcat(cmd, argv[i]);
725         }
726         cmd_exec(cmd);
727         t2 = time(nil);
728         free(cmd);
729         print("time = %ld ms\n", TK2MS(t2-t1));
730 }
731
732 void
733 cmd_noauth(int, char *[])
734 {
735         noauth = !noauth;
736         print("auth %s\n", noauth ? "disabled" : "enabled");
737 }
738
739 void
740 cmd_nonone(int, char *[])
741 {
742         nonone = !nonone;
743         print("none %s\n", nonone ? "disabled" : "enabled");
744 }
745
746 void
747 cmd_noattach(int, char *[])
748 {
749         noattach = !noattach;
750         print("attach %s\n", noattach ? "disabled" : "enabled");
751 }
752
753 void
754 cmd_files(int, char *[])
755 {
756         long i, n;
757         Chan *cp;
758
759         for(cp = chans; cp; cp = cp->next)
760                 cp->nfile = 0;
761
762         lock(&flock);
763         n = 0;
764         for(i=0; i<conf.nfile; i++)
765                 if(files[i].cp) {
766                         n++;
767                         files[i].cp->nfile++;
768                 }
769         print("%ld out of %ld files used\n", n, conf.nfile);
770         unlock(&flock);
771
772         n = 0;
773         for(cp = chans; cp; cp = cp->next)
774                 if(cp->nfile) {
775                         print("%3d: %5d\n", cp->chan, cp->nfile);
776                         n += cp->nfile;
777                 }
778         print("%ld out of %ld files used\n", n, conf.nfile);
779 }
780
781 void
782 cmd_chatty(int argc, char *argv[])
783 {
784         if(argc < 2) {
785                 print("cmd_chatty: usage: chatty n\n");
786                 return;
787         }
788         chatty = atoi(argv[1]);
789 }
790
791 static void
792 installcmds(void)
793 {
794         cmd_install("allow", "[uid] -- disable permission checking", cmd_allow);
795         cmd_install("cfs", "[file] -- set current filesystem", cmd_cfs);
796         cmd_install("chatty", "n -- set chattiness", cmd_chatty);
797         cmd_install("clean", "file [bno [addr]] -- block print/fix", cmd_clean);
798         cmd_install("check", "[options]", cmd_check);
799         cmd_install("clri", "[file ...] -- purge files/dirs", cmd_clri);
800         cmd_install("create", "path uid gid perm [lad] -- make a file/dir", cmd_create);
801         cmd_install("disallow", "-- (re)enable permission checking", cmd_disallow);
802         cmd_install("duallow", "uid -- duallow", cmd_duallow);
803         cmd_install("flag", "-- print set flags", cmd_flag);
804         cmd_install("fstat", "path -- print info on a file/dir", cmd_fstat);
805         cmd_install("halt", "-- return to boot rom", cmd_halt);
806         cmd_install("help", "", cmd_help);
807         cmd_install("newuser", "username -- add user to /adm/users", cmd_newuser);
808         cmd_install("profile", "[01] -- fs profile", cmd_prof);
809         cmd_install("remove", "[file ...] -- remove files/dirs", cmd_remove);
810         cmd_install("stata", "-- overall stats", cmd_stata);
811         cmd_install("stats", "[[-]flags ...] -- various stats", cmd_stats);
812         cmd_install("sync", "", cmd_sync);
813         cmd_install("time", "command -- time another command", cmd_time);
814         cmd_install("users", "[file] -- read /adm/users", cmd_users);
815         cmd_install("version", "-- print time of mk and boot", cmd_version);
816         cmd_install("who", "[user ...] -- print attaches", cmd_who);
817         cmd_install("hangup", "chan -- clunk files", cmd_hangup);
818         cmd_install("printconf", "-- print configuration", cmd_printconf);
819         cmd_install("noauth", "toggle noauth flag", cmd_noauth);
820         cmd_install("nonone", "toggle nonone flag", cmd_nonone);
821         cmd_install("noattach", "toggle noattach flag", cmd_noattach);
822         cmd_install("files", "report on files structure", cmd_files);
823
824         chatflag = flag_install("chat", "-- verbose");
825         errorflag = flag_install("error", "-- on errors");
826         whoflag = flag_install("allchans", "-- on who");
827         authdebugflag = flag_install("authdebug", "-- report authentications");
828 }
829
830 int
831 walkto(char *name)
832 {
833         char elem[NAMELEN], *p;
834         int n;
835
836         if(con_clone(FID1, FID2))
837                 return 1;
838
839         for(;;) {
840                 p = utfrune(name, '/');
841                 if(p == nil)
842                         p = strchr(name, '\0');
843                 if(p == name) {
844                         if(*name == '\0')
845                                 return 0;
846                         name = p+1;
847                         continue;
848                 }
849                 n = p-name;
850                 if(n > NAMELEN)
851                         return 1;
852                 memset(elem, 0, sizeof(elem));
853                 memmove(elem, name, n);
854                 if(con_walk(FID2, elem))
855                         return 1;
856                 name = p;
857         }
858 }
859
860 /* needs to parse and return vlongs to cope with new larger block numbers */
861 vlong
862 number(char *arg, int def, int base)
863 {
864         int c, sign, any;
865         vlong n;
866
867         if(arg == nil)
868                 return def;
869
870         sign = 0;
871         any = 0;
872         n = 0;
873
874         for (c = *arg; isascii(c) && isspace(c) && c != '\n'; c = *arg)
875                 arg++;
876         if(c == '-') {
877                 sign = 1;
878                 arg++;
879                 c = *arg;
880         }
881         while (isascii(c) && (isdigit(c) || base == 16 && isxdigit(c))) {
882                 n *= base;
883                 if(c >= 'a' && c <= 'f')
884                         n += c - 'a' + 10;
885                 else if(c >= 'A' && c <= 'F')
886                         n += c - 'A' + 10;
887                 else
888                         n += c - '0';
889                 arg++;
890                 c = *arg;
891                 any = 1;
892         }
893         if(!any)
894                 return def;
895         if(sign)
896                 n = -n;
897         return n;
898 }