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