aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-03-01 09:35:39 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-03-01 09:35:39 +0000
commitfe2188378c352255b7d0407513ca73ec3f933153 (patch)
tree01fcce006eb6d8b0fe1e448bc10ba68615049f1d
parent8a2e421f26623773b9f79f322b808a757ff055c0 (diff)
downloadbusybox-w32-fe2188378c352255b7d0407513ca73ec3f933153.tar.gz
busybox-w32-fe2188378c352255b7d0407513ca73ec3f933153.tar.bz2
busybox-w32-fe2188378c352255b7d0407513ca73ec3f933153.zip
msh: fix for bug 846 ("break" didn't work second time)
msh: don't use floating point in "times" builtin +4 bytes difference
-rw-r--r--shell/msh.c204
-rw-r--r--shell/msh_test/TODO_bug84629
2 files changed, 148 insertions, 85 deletions
diff --git a/shell/msh.c b/shell/msh.c
index 569011bbd..e98c6017a 100644
--- a/shell/msh.c
+++ b/shell/msh.c
@@ -489,36 +489,37 @@ static char **getwords(struct wdblock *wb);
489 489
490/* -------- misc stuff -------- */ 490/* -------- misc stuff -------- */
491 491
492static int dolabel(struct op *t, char **args);
493static int dohelp(struct op *t, char **args);
494static int dochdir(struct op *t, char **args);
495static int doshift(struct op *t, char **args);
496static int dologin(struct op *t, char **args);
497static int doumask(struct op *t, char **args);
498static int doexec(struct op *t, char **args);
499static int dodot(struct op *t, char **args);
500static int dowait(struct op *t, char **args);
501static int doread(struct op *t, char **args);
502static int doeval(struct op *t, char **args);
503static int dotrap(struct op *t, char **args);
504static int dobreak(struct op *t, char **args);
505static int doexit(struct op *t, char **args);
506static int doexport(struct op *t, char **args);
507static int doreadonly(struct op *t, char **args);
508static int doset(struct op *t, char **args);
509static int dotimes(struct op *t, char **args);
510static int docontinue(struct op *t, char **args);
511
492static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp); 512static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp);
493static int execute(struct op *t, int *pin, int *pout, int no_fork); 513static int execute(struct op *t, int *pin, int *pout, int no_fork);
494static int iosetup(struct ioword *iop, int pipein, int pipeout); 514static int iosetup(struct ioword *iop, int pipein, int pipeout);
495static void brkset(struct brkcon *bc); 515static void brkset(struct brkcon *bc);
496static int dolabel(struct op *t);
497static int dohelp(struct op *t);
498static int dochdir(struct op *t);
499static int doshift(struct op *t);
500static int dologin(struct op *t);
501static int doumask(struct op *t);
502static int doexec(struct op *t);
503static int dodot(struct op *t);
504static int dowait(struct op *t);
505static int doread(struct op *t);
506static int doeval(struct op *t);
507static int dotrap(struct op *t);
508static int getsig(char *s); 516static int getsig(char *s);
509static void setsig(int n, sighandler_t f); 517static void setsig(int n, sighandler_t f);
510static int getn(char *as); 518static int getn(char *as);
511static int dobreak(struct op *t);
512static int docontinue(struct op *t);
513static int brkcontin(char *cp, int val); 519static int brkcontin(char *cp, int val);
514static int doexit(struct op *t);
515static int doexport(struct op *t);
516static int doreadonly(struct op *t);
517static void rdexp(char **wp, void (*f) (struct var *), int key); 520static void rdexp(char **wp, void (*f) (struct var *), int key);
518static void badid(char *s); 521static void badid(char *s);
519static int doset(struct op *t);
520static void varput(char *s, int out); 522static void varput(char *s, int out);
521static int dotimes(struct op *t);
522static int expand(const char *cp, struct wdblock **wbp, int f); 523static int expand(const char *cp, struct wdblock **wbp, int f);
523static char *blank(int f); 524static char *blank(int f);
524static int dollar(int quoted); 525static int dollar(int quoted);
@@ -559,7 +560,7 @@ static const char *const signame[] = {
559}; 560};
560 561
561 562
562typedef int (*builtin_func_ptr)(struct op *); 563typedef int (*builtin_func_ptr)(struct op *, char **);
563 564
564struct builtincmd { 565struct builtincmd {
565 const char *name; 566 const char *name;
@@ -1821,7 +1822,7 @@ static struct op *command(int cf)
1821 t->type = (c == WHILE ? TWHILE : TUNTIL); 1822 t->type = (c == WHILE ? TWHILE : TUNTIL);
1822 t->left = c_list(); 1823 t->left = c_list();
1823 t->right = dogroup(1); 1824 t->right = dogroup(1);
1824 t->words = NULL; 1825 /* t->words = NULL; - newtp() did this */
1825 multiline--; 1826 multiline--;
1826 break; 1827 break;
1827 1828
@@ -2741,7 +2742,13 @@ static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp)
2741 } 2742 }
2742 2743
2743 forked = 0; 2744 forked = 0;
2744 t->words = wp; 2745 // We were pointing t->words to temporary (expanded) arg list:
2746 // t->words = wp;
2747 // and restored it later (in execute()), but "break"
2748 // longjmps away (at "Run builtin" below), leaving t->words clobbered!
2749 // See http://bugs.busybox.net/view.php?id=846.
2750 // Now we do not touch t->words, but separately pass wp as param list
2751 // to builtins
2745 DBGPRINTF(("FORKEXEC: bltin %p, no_fork %d, owp %p\n", bltin, 2752 DBGPRINTF(("FORKEXEC: bltin %p, no_fork %d, owp %p\n", bltin,
2746 no_fork, owp)); 2753 no_fork, owp));
2747 /* Don't fork if it is a lone builtin (not in pipe) 2754 /* Don't fork if it is a lone builtin (not in pipe)
@@ -2836,7 +2843,8 @@ static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp)
2836 _exit(-1); 2843 _exit(-1);
2837 return -1; 2844 return -1;
2838 } 2845 }
2839 i = setstatus(bltin(t)); 2846 /* Run builtin */
2847 i = setstatus(bltin(t, wp));
2840 if (forked) 2848 if (forked)
2841 _exit(i); 2849 _exit(i);
2842 DBGPRINTF(("FORKEXEC: returning i=%d\n", i)); 2850 DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
@@ -3156,7 +3164,7 @@ static int run(struct ioarg *argp, int (*f) (struct ioarg *))
3156 * built-in commands: doX 3164 * built-in commands: doX
3157 */ 3165 */
3158 3166
3159static int dohelp(struct op *t) 3167static int dohelp(struct op *t, char **args)
3160{ 3168{
3161 int col; 3169 int col;
3162 const struct builtincmd *x; 3170 const struct builtincmd *x;
@@ -3192,16 +3200,16 @@ static int dohelp(struct op *t)
3192 return EXIT_SUCCESS; 3200 return EXIT_SUCCESS;
3193} 3201}
3194 3202
3195static int dolabel(struct op *t) 3203static int dolabel(struct op *t, char **args)
3196{ 3204{
3197 return 0; 3205 return 0;
3198} 3206}
3199 3207
3200static int dochdir(struct op *t) 3208static int dochdir(struct op *t, char **args)
3201{ 3209{
3202 const char *cp, *er; 3210 const char *cp, *er;
3203 3211
3204 cp = t->words[1]; 3212 cp = args[1];
3205 if (cp == NULL) { 3213 if (cp == NULL) {
3206 cp = homedir->value; 3214 cp = homedir->value;
3207 if (cp != NULL) 3215 if (cp != NULL)
@@ -3218,11 +3226,11 @@ static int dochdir(struct op *t)
3218 return 1; 3226 return 1;
3219} 3227}
3220 3228
3221static int doshift(struct op *t) 3229static int doshift(struct op *t, char **args)
3222{ 3230{
3223 int n; 3231 int n;
3224 3232
3225 n = t->words[1] ? getn(t->words[1]) : 1; 3233 n = args[1] ? getn(args[1]) : 1;
3226 if (dolc < n) { 3234 if (dolc < n) {
3227 err("nothing to shift"); 3235 err("nothing to shift");
3228 return 1; 3236 return 1;
@@ -3237,7 +3245,7 @@ static int doshift(struct op *t)
3237/* 3245/*
3238 * execute login and newgrp directly 3246 * execute login and newgrp directly
3239 */ 3247 */
3240static int dologin(struct op *t) 3248static int dologin(struct op *t, char **args)
3241{ 3249{
3242 const char *cp; 3250 const char *cp;
3243 3251
@@ -3245,19 +3253,19 @@ static int dologin(struct op *t)
3245 signal(SIGINT, SIG_DFL); 3253 signal(SIGINT, SIG_DFL);
3246 signal(SIGQUIT, SIG_DFL); 3254 signal(SIGQUIT, SIG_DFL);
3247 } 3255 }
3248 cp = rexecve(t->words[0], t->words, makenv(0, NULL)); 3256 cp = rexecve(args[0], args, makenv(0, NULL));
3249 prs(t->words[0]); 3257 prs(args[0]);
3250 prs(": "); 3258 prs(": ");
3251 err(cp); 3259 err(cp);
3252 return 1; 3260 return 1;
3253} 3261}
3254 3262
3255static int doumask(struct op *t) 3263static int doumask(struct op *t, char **args)
3256{ 3264{
3257 int i; 3265 int i;
3258 char *cp; 3266 char *cp;
3259 3267
3260 cp = t->words[1]; 3268 cp = args[1];
3261 if (cp == NULL) { 3269 if (cp == NULL) {
3262 i = umask(0); 3270 i = umask(0);
3263 umask(i); 3271 umask(i);
@@ -3273,28 +3281,36 @@ static int doumask(struct op *t)
3273 return 0; 3281 return 0;
3274} 3282}
3275 3283
3276static int doexec(struct op *t) 3284static int doexec(struct op *t, char **args)
3277{ 3285{
3278 int i;
3279 jmp_buf ex; 3286 jmp_buf ex;
3280 xint *ofail; 3287 xint *ofail;
3288 char **sv_words;
3281 3289
3282 t->ioact = NULL; 3290 t->ioact = NULL;
3283 for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++) 3291 if (!args[1])
3284 continue;
3285 if (i == 0)
3286 return 1; 3292 return 1;
3293
3287 execflg = 1; 3294 execflg = 1;
3288 ofail = failpt; 3295 ofail = failpt;
3289 failpt = ex; 3296 failpt = ex;
3297
3298 sv_words = t->words;
3299 t->words = args + 1;
3300// TODO: test what will happen with "exec break" -
3301// will it leave t->words pointing to garbage?
3302// (see http://bugs.busybox.net/view.php?id=846)
3290 if (setjmp(failpt) == 0) 3303 if (setjmp(failpt) == 0)
3291 execute(t, NOPIPE, NOPIPE, /* no_fork: */ 1); 3304 execute(t, NOPIPE, NOPIPE, /* no_fork: */ 1);
3305 t->words = sv_words;
3306
3292 failpt = ofail; 3307 failpt = ofail;
3293 execflg = 0; 3308 execflg = 0;
3309
3294 return 1; 3310 return 1;
3295} 3311}
3296 3312
3297static int dodot(struct op *t) 3313static int dodot(struct op *t, char **args)
3298{ 3314{
3299 int i; 3315 int i;
3300 const char *sp; 3316 const char *sp;
@@ -3305,7 +3321,7 @@ static int dodot(struct op *t)
3305 DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, global_env.linep is %s\n", 3321 DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, global_env.linep is %s\n",
3306 t, t->left, t->right, ((global_env.linep == NULL) ? "NULL" : global_env.linep))); 3322 t, t->left, t->right, ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
3307 3323
3308 cp = t->words[1]; 3324 cp = args[1];
3309 if (cp == NULL) { 3325 if (cp == NULL) {
3310 DBGPRINTF(("DODOT: bad args, ret 0\n")); 3326 DBGPRINTF(("DODOT: bad args, ret 0\n"));
3311 return 0; 3327 return 0;
@@ -3349,12 +3365,12 @@ static int dodot(struct op *t)
3349 return -1; 3365 return -1;
3350} 3366}
3351 3367
3352static int dowait(struct op *t) 3368static int dowait(struct op *t, char **args)
3353{ 3369{
3354 int i; 3370 int i;
3355 char *cp; 3371 char *cp;
3356 3372
3357 cp = t->words[1]; 3373 cp = args[1];
3358 if (cp != NULL) { 3374 if (cp != NULL) {
3359 i = getn(cp); 3375 i = getn(cp);
3360 if (i == 0) 3376 if (i == 0)
@@ -3365,17 +3381,17 @@ static int dowait(struct op *t)
3365 return 0; 3381 return 0;
3366} 3382}
3367 3383
3368static int doread(struct op *t) 3384static int doread(struct op *t, char **args)
3369{ 3385{
3370 char *cp, **wp; 3386 char *cp, **wp;
3371 int nb = 0; 3387 int nb = 0;
3372 int nl = 0; 3388 int nl = 0;
3373 3389
3374 if (t->words[1] == NULL) { 3390 if (args[1] == NULL) {
3375 err("Usage: read name ..."); 3391 err("Usage: read name ...");
3376 return 1; 3392 return 1;
3377 } 3393 }
3378 for (wp = t->words + 1; *wp; wp++) { 3394 for (wp = args + 1; *wp; wp++) {
3379 for (cp = global_env.linep; !nl && cp < elinep - 1; cp++) { 3395 for (cp = global_env.linep; !nl && cp < elinep - 1; cp++) {
3380 nb = nonblock_safe_read(0, cp, sizeof(*cp)); 3396 nb = nonblock_safe_read(0, cp, sizeof(*cp));
3381 if (nb != sizeof(*cp)) 3397 if (nb != sizeof(*cp))
@@ -3392,17 +3408,17 @@ static int doread(struct op *t)
3392 return nb <= 0; 3408 return nb <= 0;
3393} 3409}
3394 3410
3395static int doeval(struct op *t) 3411static int doeval(struct op *t, char **args)
3396{ 3412{
3397 return RUN(awordlist, t->words + 1, wdchar); 3413 return RUN(awordlist, args + 1, wdchar);
3398} 3414}
3399 3415
3400static int dotrap(struct op *t) 3416static int dotrap(struct op *t, char **args)
3401{ 3417{
3402 int n, i; 3418 int n, i;
3403 int resetsig; 3419 int resetsig;
3404 3420
3405 if (t->words[1] == NULL) { 3421 if (args[1] == NULL) {
3406 for (i = 0; i <= _NSIG; i++) 3422 for (i = 0; i <= _NSIG; i++)
3407 if (trap[i]) { 3423 if (trap[i]) {
3408 prn(i); 3424 prn(i);
@@ -3412,14 +3428,14 @@ static int dotrap(struct op *t)
3412 } 3428 }
3413 return 0; 3429 return 0;
3414 } 3430 }
3415 resetsig = isdigit(*t->words[1]); 3431 resetsig = isdigit(args[1][0]);
3416 for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) { 3432 for (i = resetsig ? 1 : 2; args[i] != NULL; ++i) {
3417 n = getsig(t->words[i]); 3433 n = getsig(args[i]);
3418 freecell(trap[n]); 3434 freecell(trap[n]);
3419 trap[n] = 0; 3435 trap[n] = 0;
3420 if (!resetsig) { 3436 if (!resetsig) {
3421 if (*t->words[1] != '\0') { 3437 if (args[1][0] != '\0') {
3422 trap[n] = strsave(t->words[1], 0); 3438 trap[n] = strsave(args[1], 0);
3423 setsig(n, sig); 3439 setsig(n, sig);
3424 } else 3440 } else
3425 setsig(n, SIG_IGN); 3441 setsig(n, SIG_IGN);
@@ -3478,14 +3494,14 @@ static int getn(char *as)
3478 return n * m; 3494 return n * m;
3479} 3495}
3480 3496
3481static int dobreak(struct op *t) 3497static int dobreak(struct op *t, char **args)
3482{ 3498{
3483 return brkcontin(t->words[1], 1); 3499 return brkcontin(args[1], 1);
3484} 3500}
3485 3501
3486static int docontinue(struct op *t) 3502static int docontinue(struct op *t, char **args)
3487{ 3503{
3488 return brkcontin(t->words[1], 0); 3504 return brkcontin(args[1], 0);
3489} 3505}
3490 3506
3491static int brkcontin(char *cp, int val) 3507static int brkcontin(char *cp, int val)
@@ -3511,12 +3527,12 @@ static int brkcontin(char *cp, int val)
3511 /* NOTREACHED */ 3527 /* NOTREACHED */
3512} 3528}
3513 3529
3514static int doexit(struct op *t) 3530static int doexit(struct op *t, char **args)
3515{ 3531{
3516 char *cp; 3532 char *cp;
3517 3533
3518 execflg = 0; 3534 execflg = 0;
3519 cp = t->words[1]; 3535 cp = args[1];
3520 if (cp != NULL) 3536 if (cp != NULL)
3521 setstatus(getn(cp)); 3537 setstatus(getn(cp));
3522 3538
@@ -3527,15 +3543,15 @@ static int doexit(struct op *t)
3527 return 0; 3543 return 0;
3528} 3544}
3529 3545
3530static int doexport(struct op *t) 3546static int doexport(struct op *t, char **args)
3531{ 3547{
3532 rdexp(t->words + 1, export, EXPORT); 3548 rdexp(args + 1, export, EXPORT);
3533 return 0; 3549 return 0;
3534} 3550}
3535 3551
3536static int doreadonly(struct op *t) 3552static int doreadonly(struct op *t, char **args)
3537{ 3553{
3538 rdexp(t->words + 1, ronly, RONLY); 3554 rdexp(args + 1, ronly, RONLY);
3539 return 0; 3555 return 0;
3540} 3556}
3541 3557
@@ -3568,21 +3584,20 @@ static void badid(char *s)
3568 err(": bad identifier"); 3584 err(": bad identifier");
3569} 3585}
3570 3586
3571static int doset(struct op *t) 3587static int doset(struct op *t, char **args)
3572{ 3588{
3573 struct var *vp; 3589 struct var *vp;
3574 char *cp; 3590 char *cp;
3575 int n; 3591 int n;
3576 3592
3577 cp = t->words[1]; 3593 cp = args[1];
3578 if (cp == NULL) { 3594 if (cp == NULL) {
3579 for (vp = vlist; vp; vp = vp->next) 3595 for (vp = vlist; vp; vp = vp->next)
3580 varput(vp->name, 1); 3596 varput(vp->name, 1);
3581 return 0; 3597 return 0;
3582 } 3598 }
3583 if (*cp == '-') { 3599 if (*cp == '-') {
3584 /* bad: t->words++; */ 3600 args++;
3585 for (n = 0; (t->words[n] = t->words[n + 1]) != NULL; n++);
3586 if (*++cp == 0) 3601 if (*++cp == 0)
3587 FLAG['x'] = FLAG['v'] = 0; 3602 FLAG['x'] = FLAG['v'] = 0;
3588 else { 3603 else {
@@ -3602,12 +3617,12 @@ static int doset(struct op *t)
3602 } 3617 }
3603 setdash(); 3618 setdash();
3604 } 3619 }
3605 if (t->words[1]) { 3620 if (args[1]) {
3606 t->words[0] = dolv[0]; 3621 args[0] = dolv[0];
3607 for (n = 1; t->words[n]; n++) 3622 for (n = 1; args[n]; n++)
3608 setarea((char *) t->words[n], 0); 3623 setarea((char *) args[n], 0);
3609 dolc = n - 1; 3624 dolc = n - 1;
3610 dolv = t->words; 3625 dolv = args;
3611 setval(lookup("#"), putn(dolc)); 3626 setval(lookup("#"), putn(dolc));
3612 setarea((char *) (dolv - 1), 0); 3627 setarea((char *) (dolv - 1), 0);
3613 } 3628 }
@@ -3627,21 +3642,40 @@ static void varput(char *s, int out)
3627 * Copyright (c) 1999 Herbert Xu <herbert@debian.org> 3642 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3628 * This file contains code for the times builtin. 3643 * This file contains code for the times builtin.
3629 */ 3644 */
3630static int dotimes(struct op *t) 3645static void times_fmt(char *buf, clock_t val, unsigned clk_tck)
3646{
3647 unsigned min, sec;
3648 if (sizeof(val) > sizeof(int))
3649 sec = ((unsigned long)val) / clk_tck;
3650 else
3651 sec = ((unsigned)val) / clk_tck;
3652 min = sec / 60;
3653#if ENABLE_DESKTOP
3654 sprintf(buf, "%um%u.%03us", min, (sec - min * 60),
3655 /* msec: */ ((unsigned)(val - (clock_t)sec * clk_tck)) * 1000 / clk_tck
3656 );
3657#else
3658 sprintf(buf, "%um%us", min, (sec - min * 60));
3659#endif
3660}
3661
3662static int dotimes(struct op *t, char **args)
3631{ 3663{
3632 struct tms buf; 3664 struct tms buf;
3633 long clk_tck = sysconf(_SC_CLK_TCK); 3665 unsigned clk_tck = sysconf(_SC_CLK_TCK);
3666 /* How much do we need for "NmN.NNNs" ? */
3667 enum { TIMEBUF_SIZE = sizeof(int)*3 + sizeof(int)*3 + 6 };
3668 char u[TIMEBUF_SIZE], s[TIMEBUF_SIZE];
3669 char cu[TIMEBUF_SIZE], cs[TIMEBUF_SIZE];
3634 3670
3635 times(&buf); 3671 times(&buf);
3636 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n", 3672
3637 (int) (buf.tms_utime / clk_tck / 60), 3673 times_fmt(u, buf.tms_utime, clk_tck);
3638 ((double) buf.tms_utime) / clk_tck, 3674 times_fmt(s, buf.tms_stime, clk_tck);
3639 (int) (buf.tms_stime / clk_tck / 60), 3675 times_fmt(cu, buf.tms_cutime, clk_tck);
3640 ((double) buf.tms_stime) / clk_tck, 3676 times_fmt(cs, buf.tms_cstime, clk_tck);
3641 (int) (buf.tms_cutime / clk_tck / 60), 3677
3642 ((double) buf.tms_cutime) / clk_tck, 3678 printf("%s %s\n%s %s\n", u, s, cu, cs);
3643 (int) (buf.tms_cstime / clk_tck / 60),
3644 ((double) buf.tms_cstime) / clk_tck);
3645 return 0; 3679 return 0;
3646} 3680}
3647 3681
diff --git a/shell/msh_test/TODO_bug846 b/shell/msh_test/TODO_bug846
new file mode 100644
index 000000000..5c777fedb
--- /dev/null
+++ b/shell/msh_test/TODO_bug846
@@ -0,0 +1,29 @@
1#!/bin/sh
2# For future msh testsuite:
3# Testcase for http://bugs.busybox.net/view.php?id=846
4
5n=0
6while :
7do
8 echo A
9 while :
10 do
11 echo B
12 break
13 done
14 echo iteration
15 [ $n = 1 ] && break
16 echo C
17 n=`expr $n + 1`
18done
19echo D
20
21# output should be:
22# A
23# B
24# iteration
25# C
26# A
27# B
28# iteration
29# D