diff options
author | Ron Yorston <rmy@pobox.com> | 2015-10-13 14:45:51 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2015-10-13 14:45:51 +0100 |
commit | 8e509f11bceeec419abc718300bef7422d1fee4c (patch) | |
tree | fdfbc752ad94102e3613a5d7254f14a93eaf7f56 /shell | |
parent | 420f5edfe7676fe6e7cddbbf15c04649d096e422 (diff) | |
parent | 4d0c1ea4784c9844f8468d97ca5c26d3c70f9921 (diff) | |
download | busybox-w32-8e509f11bceeec419abc718300bef7422d1fee4c.tar.gz busybox-w32-8e509f11bceeec419abc718300bef7422d1fee4c.tar.bz2 busybox-w32-8e509f11bceeec419abc718300bef7422d1fee4c.zip |
Merge branch 'busybox' into merge
Diffstat (limited to 'shell')
-rw-r--r-- | shell/ash.c | 255 | ||||
-rw-r--r-- | shell/ash_test/ash-glob/glob1.right | 2 | ||||
-rwxr-xr-x | shell/ash_test/ash-glob/glob1.tests | 2 | ||||
-rw-r--r-- | shell/ash_test/ash-glob/glob2.right | 18 | ||||
-rwxr-xr-x | shell/ash_test/ash-glob/glob2.tests | 27 | ||||
-rw-r--r-- | shell/ash_test/ash-glob/glob3.right | 2 | ||||
-rwxr-xr-x | shell/ash_test/ash-glob/glob3.tests | 2 | ||||
-rw-r--r-- | shell/ash_test/ash-glob/glob_and_assign.right | 6 | ||||
-rwxr-xr-x | shell/ash_test/ash-glob/glob_and_assign.tests | 10 | ||||
-rw-r--r-- | shell/ash_test/ash-glob/glob_redir.right | 2 | ||||
-rwxr-xr-x | shell/ash_test/ash-glob/glob_redir.tests | 9 | ||||
-rw-r--r-- | shell/hush.c | 82 | ||||
-rw-r--r-- | shell/hush_test/hush-glob/glob3.right | 2 | ||||
-rwxr-xr-x | shell/hush_test/hush-glob/glob3.tests | 2 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/nommu3.right | 2 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/nommu3.tests | 15 | ||||
-rw-r--r-- | shell/shell_common.c | 2 |
17 files changed, 274 insertions, 166 deletions
diff --git a/shell/ash.c b/shell/ash.c index e9850f493..21fc05f01 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -607,11 +607,12 @@ flush_stdout_stderr(void) | |||
607 | INT_ON; | 607 | INT_ON; |
608 | } | 608 | } |
609 | 609 | ||
610 | /* Was called outcslow(c,FILE*), but c was always '\n' */ | ||
610 | static void | 611 | static void |
611 | outcslow(int c, FILE *dest) | 612 | newline_and_flush(FILE *dest) |
612 | { | 613 | { |
613 | INT_OFF; | 614 | INT_OFF; |
614 | putc(c, dest); | 615 | putc('\n', dest); |
615 | fflush(dest); | 616 | fflush(dest); |
616 | INT_ON; | 617 | INT_ON; |
617 | } | 618 | } |
@@ -1272,7 +1273,7 @@ ash_vmsg(const char *msg, va_list ap) | |||
1272 | fprintf(stderr, "line %d: ", startlinno); | 1273 | fprintf(stderr, "line %d: ", startlinno); |
1273 | } | 1274 | } |
1274 | vfprintf(stderr, msg, ap); | 1275 | vfprintf(stderr, msg, ap); |
1275 | outcslow('\n', stderr); | 1276 | newline_and_flush(stderr); |
1276 | } | 1277 | } |
1277 | 1278 | ||
1278 | /* | 1279 | /* |
@@ -3528,6 +3529,7 @@ unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
3528 | #define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */ | 3529 | #define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */ |
3529 | #define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */ | 3530 | #define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */ |
3530 | #define SHOW_CHANGED 0x04 /* only jobs whose state has changed */ | 3531 | #define SHOW_CHANGED 0x04 /* only jobs whose state has changed */ |
3532 | #define SHOW_STDERR 0x08 /* print to stderr (else stdout) */ | ||
3531 | 3533 | ||
3532 | /* | 3534 | /* |
3533 | * A job structure contains information about a job. A job is either a | 3535 | * A job structure contains information about a job. A job is either a |
@@ -4046,7 +4048,7 @@ showpipe(struct job *jp /*, FILE *out*/) | |||
4046 | psend = jp->ps + jp->nprocs; | 4048 | psend = jp->ps + jp->nprocs; |
4047 | for (ps = jp->ps + 1; ps < psend; ps++) | 4049 | for (ps = jp->ps + 1; ps < psend; ps++) |
4048 | printf(" | %s", ps->ps_cmd); | 4050 | printf(" | %s", ps->ps_cmd); |
4049 | outcslow('\n', stdout); | 4051 | newline_and_flush(stdout); |
4050 | flush_stdout_stderr(); | 4052 | flush_stdout_stderr(); |
4051 | } | 4053 | } |
4052 | 4054 | ||
@@ -4106,39 +4108,33 @@ fg_bgcmd(int argc UNUSED_PARAM, char **argv) | |||
4106 | #endif | 4108 | #endif |
4107 | 4109 | ||
4108 | static int | 4110 | static int |
4109 | sprint_status(char *s, int status, int sigonly) | 4111 | sprint_status48(char *s, int status, int sigonly) |
4110 | { | 4112 | { |
4111 | int col; | 4113 | int col; |
4112 | int st; | 4114 | int st; |
4113 | 4115 | ||
4114 | col = 0; | 4116 | col = 0; |
4115 | if (!WIFEXITED(status)) { | 4117 | if (!WIFEXITED(status)) { |
4116 | #if JOBS | 4118 | if (JOBS && WIFSTOPPED(status)) |
4117 | if (WIFSTOPPED(status)) | ||
4118 | st = WSTOPSIG(status); | 4119 | st = WSTOPSIG(status); |
4119 | else | 4120 | else |
4120 | #endif | ||
4121 | st = WTERMSIG(status); | 4121 | st = WTERMSIG(status); |
4122 | if (sigonly) { | 4122 | if (sigonly) { |
4123 | if (st == SIGINT || st == SIGPIPE) | 4123 | if (st == SIGINT || st == SIGPIPE) |
4124 | goto out; | 4124 | goto out; |
4125 | #if JOBS | 4125 | if (JOBS && WIFSTOPPED(status)) |
4126 | if (WIFSTOPPED(status)) | ||
4127 | goto out; | 4126 | goto out; |
4128 | #endif | ||
4129 | } | 4127 | } |
4130 | st &= 0x7f; | 4128 | st &= 0x7f; |
4131 | //TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata | 4129 | //TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata |
4132 | col = fmtstr(s, 32, strsignal(st)); | 4130 | col = fmtstr(s, 32, strsignal(st)); |
4133 | if (WCOREDUMP(status)) { | 4131 | if (WCOREDUMP(status)) { |
4134 | col += fmtstr(s + col, 16, " (core dumped)"); | 4132 | strcpy(s + col, " (core dumped)"); |
4133 | col += sizeof(" (core dumped)")-1; | ||
4135 | } | 4134 | } |
4136 | } else if (!sigonly) { | 4135 | } else if (!sigonly) { |
4137 | st = WEXITSTATUS(status); | 4136 | st = WEXITSTATUS(status); |
4138 | if (st) | 4137 | col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st); |
4139 | col = fmtstr(s, 16, "Done(%d)", st); | ||
4140 | else | ||
4141 | col = fmtstr(s, 16, "Done"); | ||
4142 | } | 4138 | } |
4143 | out: | 4139 | out: |
4144 | return col; | 4140 | return col; |
@@ -4224,7 +4220,6 @@ dowait(int wait_flags, struct job *job) | |||
4224 | int status; | 4220 | int status; |
4225 | struct job *jp; | 4221 | struct job *jp; |
4226 | struct job *thisjob; | 4222 | struct job *thisjob; |
4227 | int state; | ||
4228 | 4223 | ||
4229 | TRACE(("dowait(0x%x) called\n", wait_flags)); | 4224 | TRACE(("dowait(0x%x) called\n", wait_flags)); |
4230 | 4225 | ||
@@ -4246,11 +4241,12 @@ dowait(int wait_flags, struct job *job) | |||
4246 | INT_OFF; | 4241 | INT_OFF; |
4247 | thisjob = NULL; | 4242 | thisjob = NULL; |
4248 | for (jp = curjob; jp; jp = jp->prev_job) { | 4243 | for (jp = curjob; jp; jp = jp->prev_job) { |
4244 | int jobstate; | ||
4249 | struct procstat *ps; | 4245 | struct procstat *ps; |
4250 | struct procstat *psend; | 4246 | struct procstat *psend; |
4251 | if (jp->state == JOBDONE) | 4247 | if (jp->state == JOBDONE) |
4252 | continue; | 4248 | continue; |
4253 | state = JOBDONE; | 4249 | jobstate = JOBDONE; |
4254 | ps = jp->ps; | 4250 | ps = jp->ps; |
4255 | psend = ps + jp->nprocs; | 4251 | psend = ps + jp->nprocs; |
4256 | do { | 4252 | do { |
@@ -4264,41 +4260,41 @@ dowait(int wait_flags, struct job *job) | |||
4264 | ps->ps_pid = -1; | 4260 | ps->ps_pid = -1; |
4265 | } | 4261 | } |
4266 | if (ps->ps_status == -1) | 4262 | if (ps->ps_status == -1) |
4267 | state = JOBRUNNING; | 4263 | jobstate = JOBRUNNING; |
4268 | #if JOBS | 4264 | #if JOBS |
4269 | if (state == JOBRUNNING) | 4265 | if (jobstate == JOBRUNNING) |
4270 | continue; | 4266 | continue; |
4271 | if (WIFSTOPPED(ps->ps_status)) { | 4267 | if (WIFSTOPPED(ps->ps_status)) { |
4272 | jp->stopstatus = ps->ps_status; | 4268 | jp->stopstatus = ps->ps_status; |
4273 | state = JOBSTOPPED; | 4269 | jobstate = JOBSTOPPED; |
4274 | } | 4270 | } |
4275 | #endif | 4271 | #endif |
4276 | } while (++ps < psend); | 4272 | } while (++ps < psend); |
4277 | if (thisjob) | 4273 | if (!thisjob) |
4278 | goto gotjob; | 4274 | continue; |
4279 | } | ||
4280 | #if JOBS | ||
4281 | if (!WIFSTOPPED(status)) | ||
4282 | #endif | ||
4283 | jobless--; | ||
4284 | goto out; | ||
4285 | |||
4286 | gotjob: | ||
4287 | if (state != JOBRUNNING) { | ||
4288 | thisjob->changed = 1; | ||
4289 | 4275 | ||
4290 | if (thisjob->state != state) { | 4276 | /* Found the job where one of its processes changed its state. |
4291 | TRACE(("Job %d: changing state from %d to %d\n", | 4277 | * Is there at least one live and running process in this job? */ |
4292 | jobno(thisjob), thisjob->state, state)); | 4278 | if (jobstate != JOBRUNNING) { |
4293 | thisjob->state = state; | 4279 | /* No. All live processes in the job are stopped |
4280 | * (JOBSTOPPED) or there are no live processes (JOBDONE) | ||
4281 | */ | ||
4282 | thisjob->changed = 1; | ||
4283 | if (thisjob->state != jobstate) { | ||
4284 | TRACE(("Job %d: changing state from %d to %d\n", | ||
4285 | jobno(thisjob), thisjob->state, jobstate)); | ||
4286 | thisjob->state = jobstate; | ||
4294 | #if JOBS | 4287 | #if JOBS |
4295 | if (state == JOBSTOPPED) { | 4288 | if (jobstate == JOBSTOPPED) |
4296 | set_curjob(thisjob, CUR_STOPPED); | 4289 | set_curjob(thisjob, CUR_STOPPED); |
4297 | } | ||
4298 | #endif | 4290 | #endif |
4291 | } | ||
4299 | } | 4292 | } |
4293 | goto out; | ||
4300 | } | 4294 | } |
4301 | 4295 | /* The process wasn't found in job list */ | |
4296 | if (JOBS && !WIFSTOPPED(status)) | ||
4297 | jobless--; | ||
4302 | out: | 4298 | out: |
4303 | INT_ON; | 4299 | INT_ON; |
4304 | 4300 | ||
@@ -4306,7 +4302,7 @@ dowait(int wait_flags, struct job *job) | |||
4306 | char s[48 + 1]; | 4302 | char s[48 + 1]; |
4307 | int len; | 4303 | int len; |
4308 | 4304 | ||
4309 | len = sprint_status(s, status, 1); | 4305 | len = sprint_status48(s, status, 1); |
4310 | if (len) { | 4306 | if (len) { |
4311 | s[len] = '\n'; | 4307 | s[len] = '\n'; |
4312 | s[len + 1] = '\0'; | 4308 | s[len + 1] = '\0'; |
@@ -4327,13 +4323,14 @@ blocking_wait_with_raise_on_sig(void) | |||
4327 | 4323 | ||
4328 | #if JOBS | 4324 | #if JOBS |
4329 | static void | 4325 | static void |
4330 | showjob(FILE *out, struct job *jp, int mode) | 4326 | showjob(struct job *jp, int mode) |
4331 | { | 4327 | { |
4332 | struct procstat *ps; | 4328 | struct procstat *ps; |
4333 | struct procstat *psend; | 4329 | struct procstat *psend; |
4334 | int col; | 4330 | int col; |
4335 | int indent_col; | 4331 | int indent_col; |
4336 | char s[80]; | 4332 | char s[16 + 16 + 48]; |
4333 | FILE *out = (mode & SHOW_STDERR ? stderr : stdout); | ||
4337 | 4334 | ||
4338 | ps = jp->ps; | 4335 | ps = jp->ps; |
4339 | 4336 | ||
@@ -4363,7 +4360,7 @@ showjob(FILE *out, struct job *jp, int mode) | |||
4363 | int status = psend[-1].ps_status; | 4360 | int status = psend[-1].ps_status; |
4364 | if (jp->state == JOBSTOPPED) | 4361 | if (jp->state == JOBSTOPPED) |
4365 | status = jp->stopstatus; | 4362 | status = jp->stopstatus; |
4366 | col += sprint_status(s + col, status, 0); | 4363 | col += sprint_status48(s + col, status, 0); |
4367 | } | 4364 | } |
4368 | /* By now, "[JOBID]* [maybe PID] STATUS" is printed */ | 4365 | /* By now, "[JOBID]* [maybe PID] STATUS" is printed */ |
4369 | 4366 | ||
@@ -4390,7 +4387,7 @@ showjob(FILE *out, struct job *jp, int mode) | |||
4390 | ps->ps_cmd | 4387 | ps->ps_cmd |
4391 | ); | 4388 | ); |
4392 | } while (++ps != psend); | 4389 | } while (++ps != psend); |
4393 | outcslow('\n', out); | 4390 | newline_and_flush(out); |
4394 | 4391 | ||
4395 | jp->changed = 0; | 4392 | jp->changed = 0; |
4396 | 4393 | ||
@@ -4405,7 +4402,7 @@ showjob(FILE *out, struct job *jp, int mode) | |||
4405 | * statuses have changed since the last call to showjobs. | 4402 | * statuses have changed since the last call to showjobs. |
4406 | */ | 4403 | */ |
4407 | static void | 4404 | static void |
4408 | showjobs(FILE *out, int mode) | 4405 | showjobs(int mode) |
4409 | { | 4406 | { |
4410 | struct job *jp; | 4407 | struct job *jp; |
4411 | 4408 | ||
@@ -4417,7 +4414,7 @@ showjobs(FILE *out, int mode) | |||
4417 | 4414 | ||
4418 | for (jp = curjob; jp; jp = jp->prev_job) { | 4415 | for (jp = curjob; jp; jp = jp->prev_job) { |
4419 | if (!(mode & SHOW_CHANGED) || jp->changed) { | 4416 | if (!(mode & SHOW_CHANGED) || jp->changed) { |
4420 | showjob(out, jp, mode); | 4417 | showjob(jp, mode); |
4421 | } | 4418 | } |
4422 | } | 4419 | } |
4423 | } | 4420 | } |
@@ -4438,10 +4435,10 @@ jobscmd(int argc UNUSED_PARAM, char **argv) | |||
4438 | argv = argptr; | 4435 | argv = argptr; |
4439 | if (*argv) { | 4436 | if (*argv) { |
4440 | do | 4437 | do |
4441 | showjob(stdout, getjob(*argv, 0), mode); | 4438 | showjob(getjob(*argv, 0), mode); |
4442 | while (*++argv); | 4439 | while (*++argv); |
4443 | } else { | 4440 | } else { |
4444 | showjobs(stdout, mode); | 4441 | showjobs(mode); |
4445 | } | 4442 | } |
4446 | 4443 | ||
4447 | return 0; | 4444 | return 0; |
@@ -5894,8 +5891,8 @@ cvtnum(arith_t num) | |||
5894 | { | 5891 | { |
5895 | int len; | 5892 | int len; |
5896 | 5893 | ||
5897 | expdest = makestrspace(32, expdest); | 5894 | expdest = makestrspace(sizeof(arith_t)*3 + 2, expdest); |
5898 | len = fmtstr(expdest, 32, ARITH_FMT, num); | 5895 | len = fmtstr(expdest, sizeof(arith_t)*3 + 2, ARITH_FMT, num); |
5899 | STADJUST(len, expdest); | 5896 | STADJUST(len, expdest); |
5900 | return len; | 5897 | return len; |
5901 | } | 5898 | } |
@@ -7326,10 +7323,11 @@ expmeta(char *expdir, char *enddir, char *name) | |||
7326 | struct dirent *dp; | 7323 | struct dirent *dp; |
7327 | int atend; | 7324 | int atend; |
7328 | int matchdot; | 7325 | int matchdot; |
7326 | int esc; | ||
7329 | 7327 | ||
7330 | metaflag = 0; | 7328 | metaflag = 0; |
7331 | start = name; | 7329 | start = name; |
7332 | for (p = name; *p; p++) { | 7330 | for (p = name; esc = 0, *p; p += esc + 1) { |
7333 | if (*p == '*' || *p == '?') | 7331 | if (*p == '*' || *p == '?') |
7334 | metaflag = 1; | 7332 | metaflag = 1; |
7335 | else if (*p == '[') { | 7333 | else if (*p == '[') { |
@@ -7346,15 +7344,16 @@ expmeta(char *expdir, char *enddir, char *name) | |||
7346 | break; | 7344 | break; |
7347 | } | 7345 | } |
7348 | } | 7346 | } |
7349 | } else if (*p == '\\') | 7347 | } else { |
7350 | p++; | 7348 | if (*p == '\\') |
7351 | else if (*p == '/') { | 7349 | esc++; |
7352 | if (metaflag) | 7350 | if (p[esc] == '/') { |
7353 | goto out; | 7351 | if (metaflag) |
7354 | start = p + 1; | 7352 | break; |
7353 | start = p + esc + 1; | ||
7354 | } | ||
7355 | } | 7355 | } |
7356 | } | 7356 | } |
7357 | out: | ||
7358 | if (metaflag == 0) { /* we've reached the end of the file name */ | 7357 | if (metaflag == 0) { /* we've reached the end of the file name */ |
7359 | if (enddir != expdir) | 7358 | if (enddir != expdir) |
7360 | metaflag++; | 7359 | metaflag++; |
@@ -7394,7 +7393,8 @@ expmeta(char *expdir, char *enddir, char *name) | |||
7394 | atend = 1; | 7393 | atend = 1; |
7395 | } else { | 7394 | } else { |
7396 | atend = 0; | 7395 | atend = 0; |
7397 | *endname++ = '\0'; | 7396 | *endname = '\0'; |
7397 | endname += esc + 1; | ||
7398 | } | 7398 | } |
7399 | matchdot = 0; | 7399 | matchdot = 0; |
7400 | p = start; | 7400 | p = start; |
@@ -7419,7 +7419,7 @@ expmeta(char *expdir, char *enddir, char *name) | |||
7419 | } | 7419 | } |
7420 | closedir(dirp); | 7420 | closedir(dirp); |
7421 | if (!atend) | 7421 | if (!atend) |
7422 | endname[-1] = '/'; | 7422 | endname[-esc - 1] = esc ? '\\' : '/'; |
7423 | } | 7423 | } |
7424 | 7424 | ||
7425 | static struct strlist * | 7425 | static struct strlist * |
@@ -10118,7 +10118,7 @@ preadfd(void) | |||
10118 | } | 10118 | } |
10119 | # if ENABLE_ASH_IDLE_TIMEOUT | 10119 | # if ENABLE_ASH_IDLE_TIMEOUT |
10120 | else if (errno == EAGAIN && timeout > 0) { | 10120 | else if (errno == EAGAIN && timeout > 0) { |
10121 | printf("\007timed out waiting for input: auto-logout\n"); | 10121 | puts("\007timed out waiting for input: auto-logout"); |
10122 | exitshell(); | 10122 | exitshell(); |
10123 | } | 10123 | } |
10124 | # endif | 10124 | # endif |
@@ -10472,10 +10472,8 @@ setinputstring(char *string) | |||
10472 | 10472 | ||
10473 | #if ENABLE_ASH_MAIL | 10473 | #if ENABLE_ASH_MAIL |
10474 | 10474 | ||
10475 | #define MAXMBOXES 10 | 10475 | /* Hash of mtimes of mailboxes */ |
10476 | 10476 | static unsigned mailtime_hash; | |
10477 | /* times of mailboxes */ | ||
10478 | static time_t mailtime[MAXMBOXES]; | ||
10479 | /* Set if MAIL or MAILPATH is changed. */ | 10477 | /* Set if MAIL or MAILPATH is changed. */ |
10480 | static smallint mail_var_path_changed; | 10478 | static smallint mail_var_path_changed; |
10481 | 10479 | ||
@@ -10491,13 +10489,14 @@ chkmail(void) | |||
10491 | const char *mpath; | 10489 | const char *mpath; |
10492 | char *p; | 10490 | char *p; |
10493 | char *q; | 10491 | char *q; |
10494 | time_t *mtp; | 10492 | unsigned new_hash; |
10495 | struct stackmark smark; | 10493 | struct stackmark smark; |
10496 | struct stat statb; | 10494 | struct stat statb; |
10497 | 10495 | ||
10498 | setstackmark(&smark); | 10496 | setstackmark(&smark); |
10499 | mpath = mpathset() ? mpathval() : mailval(); | 10497 | mpath = mpathset() ? mpathval() : mailval(); |
10500 | for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) { | 10498 | new_hash = 0; |
10499 | for (;;) { | ||
10501 | p = path_advance(&mpath, nullstr); | 10500 | p = path_advance(&mpath, nullstr); |
10502 | if (p == NULL) | 10501 | if (p == NULL) |
10503 | break; | 10502 | break; |
@@ -10511,16 +10510,15 @@ chkmail(void) | |||
10511 | #endif | 10510 | #endif |
10512 | q[-1] = '\0'; /* delete trailing '/' */ | 10511 | q[-1] = '\0'; /* delete trailing '/' */ |
10513 | if (stat(p, &statb) < 0) { | 10512 | if (stat(p, &statb) < 0) { |
10514 | *mtp = 0; | ||
10515 | continue; | 10513 | continue; |
10516 | } | 10514 | } |
10517 | if (!mail_var_path_changed && statb.st_mtime != *mtp) { | 10515 | /* Very simplistic "hash": just a sum of all mtimes */ |
10518 | fprintf( | 10516 | new_hash += (unsigned)statb.st_mtime; |
10519 | stderr, "%s\n", | 10517 | } |
10520 | pathopt ? pathopt : "you have mail" | 10518 | if (!mail_var_path_changed && mailtime_hash != new_hash) { |
10521 | ); | 10519 | if (mailtime_hash != 0) |
10522 | } | 10520 | out2str("you have mail\n"); |
10523 | *mtp = statb.st_mtime; | 10521 | mailtime_hash = new_hash; |
10524 | } | 10522 | } |
10525 | mail_var_path_changed = 0; | 10523 | mail_var_path_changed = 0; |
10526 | popstackmark(&smark); | 10524 | popstackmark(&smark); |
@@ -10792,9 +10790,11 @@ getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *opt | |||
10792 | char c = '?'; | 10790 | char c = '?'; |
10793 | int done = 0; | 10791 | int done = 0; |
10794 | int err = 0; | 10792 | int err = 0; |
10795 | char s[12]; | 10793 | char sbuf[2]; |
10796 | char **optnext; | 10794 | char **optnext; |
10797 | 10795 | ||
10796 | sbuf[1] = '\0'; | ||
10797 | |||
10798 | if (*param_optind < 1) | 10798 | if (*param_optind < 1) |
10799 | return 1; | 10799 | return 1; |
10800 | optnext = optfirst + *param_optind - 1; | 10800 | optnext = optfirst + *param_optind - 1; |
@@ -10821,9 +10821,9 @@ getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *opt | |||
10821 | for (q = optstr; *q != c;) { | 10821 | for (q = optstr; *q != c;) { |
10822 | if (*q == '\0') { | 10822 | if (*q == '\0') { |
10823 | if (optstr[0] == ':') { | 10823 | if (optstr[0] == ':') { |
10824 | s[0] = c; | 10824 | sbuf[0] = c; |
10825 | s[1] = '\0'; | 10825 | /*sbuf[1] = '\0'; - already is */ |
10826 | err |= setvarsafe("OPTARG", s, 0); | 10826 | err |= setvarsafe("OPTARG", sbuf, 0); |
10827 | } else { | 10827 | } else { |
10828 | fprintf(stderr, "Illegal option -%c\n", c); | 10828 | fprintf(stderr, "Illegal option -%c\n", c); |
10829 | unsetvar("OPTARG"); | 10829 | unsetvar("OPTARG"); |
@@ -10838,9 +10838,9 @@ getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *opt | |||
10838 | if (*++q == ':') { | 10838 | if (*++q == ':') { |
10839 | if (*p == '\0' && (p = *optnext) == NULL) { | 10839 | if (*p == '\0' && (p = *optnext) == NULL) { |
10840 | if (optstr[0] == ':') { | 10840 | if (optstr[0] == ':') { |
10841 | s[0] = c; | 10841 | sbuf[0] = c; |
10842 | s[1] = '\0'; | 10842 | /*sbuf[1] = '\0'; - already is */ |
10843 | err |= setvarsafe("OPTARG", s, 0); | 10843 | err |= setvarsafe("OPTARG", sbuf, 0); |
10844 | c = ':'; | 10844 | c = ':'; |
10845 | } else { | 10845 | } else { |
10846 | fprintf(stderr, "No arg for -%c option\n", c); | 10846 | fprintf(stderr, "No arg for -%c option\n", c); |
@@ -10859,11 +10859,10 @@ getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *opt | |||
10859 | out: | 10859 | out: |
10860 | *optoff = p ? p - *(optnext - 1) : -1; | 10860 | *optoff = p ? p - *(optnext - 1) : -1; |
10861 | *param_optind = optnext - optfirst + 1; | 10861 | *param_optind = optnext - optfirst + 1; |
10862 | fmtstr(s, sizeof(s), "%d", *param_optind); | 10862 | err |= setvarsafe("OPTIND", itoa(*param_optind), VNOFUNC); |
10863 | err |= setvarsafe("OPTIND", s, VNOFUNC); | 10863 | sbuf[0] = c; |
10864 | s[0] = c; | 10864 | /*sbuf[1] = '\0'; - already is */ |
10865 | s[1] = '\0'; | 10865 | err |= setvarsafe(optvar, sbuf, 0); |
10866 | err |= setvarsafe(optvar, s, 0); | ||
10867 | if (err) { | 10866 | if (err) { |
10868 | *param_optind = 1; | 10867 | *param_optind = 1; |
10869 | *optoff = -1; | 10868 | *optoff = -1; |
@@ -12559,7 +12558,7 @@ cmdloop(int top) | |||
12559 | setstackmark(&smark); | 12558 | setstackmark(&smark); |
12560 | #if JOBS | 12559 | #if JOBS |
12561 | if (doing_jobctl) | 12560 | if (doing_jobctl) |
12562 | showjobs(stderr, SHOW_CHANGED); | 12561 | showjobs(SHOW_CHANGED|SHOW_STDERR); |
12563 | #endif | 12562 | #endif |
12564 | inter = 0; | 12563 | inter = 0; |
12565 | if (iflag && top) { | 12564 | if (iflag && top) { |
@@ -13298,21 +13297,11 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
13298 | } | 13297 | } |
13299 | 13298 | ||
13300 | static int FAST_FUNC | 13299 | static int FAST_FUNC |
13301 | umaskcmd(int argc UNUSED_PARAM, char **argv) | 13300 | umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) |
13302 | { | 13301 | { |
13303 | static const char permuser[3] ALIGN1 = "ugo"; | 13302 | static const char permuser[3] ALIGN1 = "ogu"; |
13304 | static const char permmode[3] ALIGN1 = "rwx"; | ||
13305 | static const short permmask[] ALIGN2 = { | ||
13306 | S_IRUSR, S_IWUSR, S_IXUSR, | ||
13307 | S_IRGRP, S_IWGRP, S_IXGRP, | ||
13308 | S_IROTH, S_IWOTH, S_IXOTH | ||
13309 | }; | ||
13310 | |||
13311 | /* TODO: use bb_parse_mode() instead */ | ||
13312 | 13303 | ||
13313 | char *ap; | ||
13314 | mode_t mask; | 13304 | mode_t mask; |
13315 | int i; | ||
13316 | int symbolic_mode = 0; | 13305 | int symbolic_mode = 0; |
13317 | 13306 | ||
13318 | while (nextopt("S") != '\0') { | 13307 | while (nextopt("S") != '\0') { |
@@ -13324,45 +13313,43 @@ umaskcmd(int argc UNUSED_PARAM, char **argv) | |||
13324 | umask(mask); | 13313 | umask(mask); |
13325 | INT_ON; | 13314 | INT_ON; |
13326 | 13315 | ||
13327 | ap = *argptr; | 13316 | if (*argptr == NULL) { |
13328 | if (ap == NULL) { | ||
13329 | if (symbolic_mode) { | 13317 | if (symbolic_mode) { |
13330 | char buf[18]; | 13318 | char buf[sizeof(",u=rwx,g=rwx,o=rwx")]; |
13331 | char *p = buf; | 13319 | char *p = buf; |
13320 | int i; | ||
13332 | 13321 | ||
13333 | for (i = 0; i < 3; i++) { | 13322 | i = 2; |
13334 | int j; | 13323 | for (;;) { |
13335 | 13324 | *p++ = ','; | |
13336 | *p++ = permuser[i]; | 13325 | *p++ = permuser[i]; |
13337 | *p++ = '='; | 13326 | *p++ = '='; |
13338 | for (j = 0; j < 3; j++) { | 13327 | /* mask is 0..0uuugggooo. i=2 selects uuu bits */ |
13339 | if ((mask & permmask[3 * i + j]) == 0) { | 13328 | if (!(mask & 0400)) *p++ = 'r'; |
13340 | *p++ = permmode[j]; | 13329 | if (!(mask & 0200)) *p++ = 'w'; |
13341 | } | 13330 | if (!(mask & 0100)) *p++ = 'x'; |
13342 | } | 13331 | mask <<= 3; |
13343 | *p++ = ','; | 13332 | if (--i < 0) |
13333 | break; | ||
13344 | } | 13334 | } |
13345 | *--p = 0; | 13335 | *p = '\0'; |
13346 | puts(buf); | 13336 | puts(buf + 1); |
13347 | } else { | 13337 | } else { |
13348 | out1fmt("%.4o\n", mask); | 13338 | out1fmt("%04o\n", mask); |
13349 | } | 13339 | } |
13350 | } else { | 13340 | } else { |
13351 | if (isdigit((unsigned char) *ap)) { | 13341 | char *modestr = *argptr; |
13352 | mask = 0; | 13342 | /* numeric umasks are taken as-is */ |
13353 | do { | 13343 | /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */ |
13354 | if (*ap >= '8' || *ap < '0') | 13344 | if (!isdigit(modestr[0])) |
13355 | ash_msg_and_raise_error(msg_illnum, argv[1]); | 13345 | mask ^= 0777; |
13356 | mask = (mask << 3) + (*ap - '0'); | 13346 | mask = bb_parse_mode(modestr, mask); |
13357 | } while (*++ap != '\0'); | 13347 | if ((unsigned)mask > 0777) { |
13358 | umask(mask); | 13348 | ash_msg_and_raise_error("illegal mode: %s", modestr); |
13359 | } else { | 13349 | } |
13360 | mask = ~mask & 0777; | 13350 | if (!isdigit(modestr[0])) |
13361 | if (!bb_parse_mode(ap, &mask)) { | 13351 | mask ^= 0777; |
13362 | ash_msg_and_raise_error("illegal mode: %s", ap); | 13352 | umask(mask); |
13363 | } | ||
13364 | umask(~mask & 0777); | ||
13365 | } | ||
13366 | } | 13353 | } |
13367 | return 0; | 13354 | return 0; |
13368 | } | 13355 | } |
@@ -13713,7 +13700,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
13713 | exitshell(); | 13700 | exitshell(); |
13714 | } | 13701 | } |
13715 | if (e == EXINT) { | 13702 | if (e == EXINT) { |
13716 | outcslow('\n', stderr); | 13703 | newline_and_flush(stderr); |
13717 | } | 13704 | } |
13718 | 13705 | ||
13719 | popstackmark(&smark); | 13706 | popstackmark(&smark); |
diff --git a/shell/ash_test/ash-glob/glob1.right b/shell/ash_test/ash-glob/glob1.right new file mode 100644 index 000000000..f29ab4e65 --- /dev/null +++ b/shell/ash_test/ash-glob/glob1.right | |||
@@ -0,0 +1,2 @@ | |||
1 | glob1.tests | ||
2 | glob1.tests | ||
diff --git a/shell/ash_test/ash-glob/glob1.tests b/shell/ash_test/ash-glob/glob1.tests new file mode 100755 index 000000000..f980ce064 --- /dev/null +++ b/shell/ash_test/ash-glob/glob1.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | echo *glob1?t[e]sts* | ||
2 | echo "glob1"?'t'[e]s* | ||
diff --git a/shell/ash_test/ash-glob/glob2.right b/shell/ash_test/ash-glob/glob2.right new file mode 100644 index 000000000..7a70c2263 --- /dev/null +++ b/shell/ash_test/ash-glob/glob2.right | |||
@@ -0,0 +1,18 @@ | |||
1 | Expected Actual | ||
2 | Z\* : Z\* | ||
3 | Z* : Z* | ||
4 | Z\f : Z\f | ||
5 | Z\* : Z\* | ||
6 | |||
7 | Z\z : Z\z | ||
8 | Zz : Zz | ||
9 | Z\z : Z\z | ||
10 | Z\z : Z\z | ||
11 | |||
12 | Z\ : Z\ | ||
13 | Z\ : Z\ | ||
14 | |||
15 | Z\f Zf : Z\f Zf | ||
16 | Z\f Zf : Z\f Zf | ||
17 | |||
18 | Done: 0 | ||
diff --git a/shell/ash_test/ash-glob/glob2.tests b/shell/ash_test/ash-glob/glob2.tests new file mode 100755 index 000000000..00618b9db --- /dev/null +++ b/shell/ash_test/ash-glob/glob2.tests | |||
@@ -0,0 +1,27 @@ | |||
1 | # This test demonstrates that in unquoted $v, backslashes expand by this rule: | ||
2 | # \z -> \\\z; \<eol> -> \\<eol> (for any z, special or not), | ||
3 | # and subsequently globbing converts \\ to \ and treats \z as literal z | ||
4 | # even if it is a special char. | ||
5 | |||
6 | >'Zf' | ||
7 | >'Z\f' | ||
8 | echo 'Expected' 'Actual' | ||
9 | v='\*'; echo 'Z\* :' Z$v # ash is buggy here: prints 'Z\f' | ||
10 | echo 'Z* :' Z\* | ||
11 | echo 'Z\f :' Z\\* | ||
12 | echo 'Z\* :' Z\\\* # NB! only this matches Z$v output | ||
13 | echo | ||
14 | v='\z'; echo 'Z\z :' Z$v | ||
15 | echo 'Zz :' Z\z | ||
16 | echo 'Z\z :' Z\\z | ||
17 | echo 'Z\z :' Z\\\z | ||
18 | echo | ||
19 | v='\'; echo 'Z\ :' Z$v | ||
20 | echo 'Z\ :' Z\\ | ||
21 | echo | ||
22 | v='*'; echo 'Z\f Zf :' Z$v | ||
23 | echo 'Z\f Zf :' Z* | ||
24 | echo | ||
25 | |||
26 | rm 'Z\f' 'Zf' | ||
27 | echo Done: $? | ||
diff --git a/shell/ash_test/ash-glob/glob3.right b/shell/ash_test/ash-glob/glob3.right new file mode 100644 index 000000000..161b589e0 --- /dev/null +++ b/shell/ash_test/ash-glob/glob3.right | |||
@@ -0,0 +1,2 @@ | |||
1 | glob3.tests | ||
2 | ./glob3.tests | ||
diff --git a/shell/ash_test/ash-glob/glob3.tests b/shell/ash_test/ash-glob/glob3.tests new file mode 100755 index 000000000..bdf54001e --- /dev/null +++ b/shell/ash_test/ash-glob/glob3.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | echo "glob3.test"* | ||
2 | echo "./glob3.test"* | ||
diff --git a/shell/ash_test/ash-glob/glob_and_assign.right b/shell/ash_test/ash-glob/glob_and_assign.right new file mode 100644 index 000000000..d46e44363 --- /dev/null +++ b/shell/ash_test/ash-glob/glob_and_assign.right | |||
@@ -0,0 +1,6 @@ | |||
1 | ZVAR=z.tmp ZVAR=*.tmp ZVAR=[z].tmp | ||
2 | ZVAR=z.tmp ZVAR=*.tmp ZVAR=[z].tmp | ||
3 | *.tmp | ||
4 | ZVAR=z.tmp z.tmp | ||
5 | ZVAR=z.tmp ZVAR=*.tmp ZVAR=[z].tmp | ||
6 | ZVAR=z.tmp ZVAR=*.tmp ZVAR=[z].tmp | ||
diff --git a/shell/ash_test/ash-glob/glob_and_assign.tests b/shell/ash_test/ash-glob/glob_and_assign.tests new file mode 100755 index 000000000..0b158f20f --- /dev/null +++ b/shell/ash_test/ash-glob/glob_and_assign.tests | |||
@@ -0,0 +1,10 @@ | |||
1 | >ZVAR=z.tmp | ||
2 | >z.tmp | ||
3 | ZVAR=*.tmp echo ZVAR=*.tmp "ZVAR=*.tmp" "ZVAR=[z].tmp" | ||
4 | ZVAR=*.tmp /bin/echo ZVAR=*.tmp "ZVAR=*.tmp" "ZVAR=[z].tmp" | ||
5 | ZVAR=*.tmp | ||
6 | echo "$ZVAR" | ||
7 | echo $ZVAR | ||
8 | echo ZVAR=*.tmp "ZVAR=*.tmp" "ZVAR=[z].tmp" | ||
9 | /bin/echo ZVAR=*.tmp "ZVAR=*.tmp" "ZVAR=[z].tmp" | ||
10 | rm ZVAR=z.tmp z.tmp | ||
diff --git a/shell/ash_test/ash-glob/glob_redir.right b/shell/ash_test/ash-glob/glob_redir.right new file mode 100644 index 000000000..fbd0309b0 --- /dev/null +++ b/shell/ash_test/ash-glob/glob_redir.right | |||
@@ -0,0 +1,2 @@ | |||
1 | z.tmp: | ||
2 | ?.tmp: TEST | ||
diff --git a/shell/ash_test/ash-glob/glob_redir.tests b/shell/ash_test/ash-glob/glob_redir.tests new file mode 100755 index 000000000..621d12017 --- /dev/null +++ b/shell/ash_test/ash-glob/glob_redir.tests | |||
@@ -0,0 +1,9 @@ | |||
1 | # Redirections are not globbed. | ||
2 | # bash: | ||
3 | # if run as "sh", they are not globbed, but | ||
4 | # if run as "bash", they are! | ||
5 | >z.tmp | ||
6 | echo TEST >?.tmp | ||
7 | echo 'z.tmp:' `cat 'z.tmp'` | ||
8 | echo '?.tmp:' `cat '?.tmp'` | ||
9 | rm 'z.tmp' '?.tmp' | ||
diff --git a/shell/hush.c b/shell/hush.c index 3ca04494c..eabe83ac6 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -1479,10 +1479,11 @@ static sighandler_t install_sighandler(int sig, sighandler_t handler) | |||
1479 | 1479 | ||
1480 | #if ENABLE_HUSH_JOB | 1480 | #if ENABLE_HUSH_JOB |
1481 | 1481 | ||
1482 | static void xfunc_has_died(void); | ||
1482 | /* After [v]fork, in child: do not restore tty pgrp on xfunc death */ | 1483 | /* After [v]fork, in child: do not restore tty pgrp on xfunc death */ |
1483 | # define disable_restore_tty_pgrp_on_exit() (die_sleep = 0) | 1484 | # define disable_restore_tty_pgrp_on_exit() (die_func = NULL) |
1484 | /* After [v]fork, in parent: restore tty pgrp on xfunc death */ | 1485 | /* After [v]fork, in parent: restore tty pgrp on xfunc death */ |
1485 | # define enable_restore_tty_pgrp_on_exit() (die_sleep = -1) | 1486 | # define enable_restore_tty_pgrp_on_exit() (die_func = xfunc_has_died) |
1486 | 1487 | ||
1487 | /* Restores tty foreground process group, and exits. | 1488 | /* Restores tty foreground process group, and exits. |
1488 | * May be called as signal handler for fatal signal | 1489 | * May be called as signal handler for fatal signal |
@@ -1587,6 +1588,15 @@ static void hush_exit(int exitcode) | |||
1587 | #endif | 1588 | #endif |
1588 | } | 1589 | } |
1589 | 1590 | ||
1591 | static void xfunc_has_died(void) NORETURN; | ||
1592 | static void xfunc_has_died(void) | ||
1593 | { | ||
1594 | /* xfunc has failed! die die die */ | ||
1595 | /* no EXIT traps, this is an escape hatch! */ | ||
1596 | G.exiting = 1; | ||
1597 | hush_exit(xfunc_error_retval); | ||
1598 | } | ||
1599 | |||
1590 | 1600 | ||
1591 | //TODO: return a mask of ALL handled sigs? | 1601 | //TODO: return a mask of ALL handled sigs? |
1592 | static int check_and_run_traps(void) | 1602 | static int check_and_run_traps(void) |
@@ -3161,11 +3171,29 @@ static int reserved_word(o_string *word, struct parse_context *ctx) | |||
3161 | old->command->group = ctx->list_head; | 3171 | old->command->group = ctx->list_head; |
3162 | old->command->cmd_type = CMD_NORMAL; | 3172 | old->command->cmd_type = CMD_NORMAL; |
3163 | # if !BB_MMU | 3173 | # if !BB_MMU |
3164 | o_addstr(&old->as_string, ctx->as_string.data); | 3174 | /* At this point, the compound command's string is in |
3165 | o_free_unsafe(&ctx->as_string); | 3175 | * ctx->as_string... except for the leading keyword! |
3166 | old->command->group_as_string = xstrdup(old->as_string.data); | 3176 | * Consider this example: "echo a | if true; then echo a; fi" |
3167 | debug_printf_parse("pop, remembering as:'%s'\n", | 3177 | * ctx->as_string will contain "true; then echo a; fi", |
3168 | old->command->group_as_string); | 3178 | * with "if " remaining in old->as_string! |
3179 | */ | ||
3180 | { | ||
3181 | char *str; | ||
3182 | int len = old->as_string.length; | ||
3183 | /* Concatenate halves */ | ||
3184 | o_addstr(&old->as_string, ctx->as_string.data); | ||
3185 | o_free_unsafe(&ctx->as_string); | ||
3186 | /* Find where leading keyword starts in first half */ | ||
3187 | str = old->as_string.data + len; | ||
3188 | if (str > old->as_string.data) | ||
3189 | str--; /* skip whitespace after keyword */ | ||
3190 | while (str > old->as_string.data && isalpha(str[-1])) | ||
3191 | str--; | ||
3192 | /* Ugh, we're done with this horrid hack */ | ||
3193 | old->command->group_as_string = xstrdup(str); | ||
3194 | debug_printf_parse("pop, remembering as:'%s'\n", | ||
3195 | old->command->group_as_string); | ||
3196 | } | ||
3169 | # endif | 3197 | # endif |
3170 | *ctx = *old; /* physical copy */ | 3198 | *ctx = *old; /* physical copy */ |
3171 | free(old); | 3199 | free(old); |
@@ -4248,7 +4276,7 @@ static struct pipe *parse_stream(char **pstring, | |||
4248 | pi = NULL; | 4276 | pi = NULL; |
4249 | } | 4277 | } |
4250 | #if !BB_MMU | 4278 | #if !BB_MMU |
4251 | debug_printf_parse("as_string '%s'\n", ctx.as_string.data); | 4279 | debug_printf_parse("as_string1 '%s'\n", ctx.as_string.data); |
4252 | if (pstring) | 4280 | if (pstring) |
4253 | *pstring = ctx.as_string.data; | 4281 | *pstring = ctx.as_string.data; |
4254 | else | 4282 | else |
@@ -4399,7 +4427,7 @@ static struct pipe *parse_stream(char **pstring, | |||
4399 | ) { | 4427 | ) { |
4400 | o_free(&dest); | 4428 | o_free(&dest); |
4401 | #if !BB_MMU | 4429 | #if !BB_MMU |
4402 | debug_printf_parse("as_string '%s'\n", ctx.as_string.data); | 4430 | debug_printf_parse("as_string2 '%s'\n", ctx.as_string.data); |
4403 | if (pstring) | 4431 | if (pstring) |
4404 | *pstring = ctx.as_string.data; | 4432 | *pstring = ctx.as_string.data; |
4405 | else | 4433 | else |
@@ -4639,9 +4667,6 @@ static struct pipe *parse_stream(char **pstring, | |||
4639 | * with redirect_opt_num(), but bash doesn't do it. | 4667 | * with redirect_opt_num(), but bash doesn't do it. |
4640 | * "echo foo 2| cat" yields "foo 2". */ | 4668 | * "echo foo 2| cat" yields "foo 2". */ |
4641 | done_command(&ctx); | 4669 | done_command(&ctx); |
4642 | #if !BB_MMU | ||
4643 | o_reset_to_empty_unquoted(&ctx.as_string); | ||
4644 | #endif | ||
4645 | } | 4670 | } |
4646 | goto new_cmd; | 4671 | goto new_cmd; |
4647 | case '(': | 4672 | case '(': |
@@ -6779,7 +6804,7 @@ static int checkjobs(struct pipe *fg_pipe) | |||
6779 | int sig = WTERMSIG(status); | 6804 | int sig = WTERMSIG(status); |
6780 | if (i == fg_pipe->num_cmds-1) | 6805 | if (i == fg_pipe->num_cmds-1) |
6781 | /* TODO: use strsignal() instead for bash compat? but that's bloat... */ | 6806 | /* TODO: use strsignal() instead for bash compat? but that's bloat... */ |
6782 | printf("%s\n", sig == SIGINT || sig == SIGPIPE ? "" : get_signame(sig)); | 6807 | puts(sig == SIGINT || sig == SIGPIPE ? "" : get_signame(sig)); |
6783 | /* TODO: if (WCOREDUMP(status)) + " (core dumped)"; */ | 6808 | /* TODO: if (WCOREDUMP(status)) + " (core dumped)"; */ |
6784 | /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here? | 6809 | /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here? |
6785 | * Maybe we need to use sig | 128? */ | 6810 | * Maybe we need to use sig | 128? */ |
@@ -7851,12 +7876,7 @@ int hush_main(int argc, char **argv) | |||
7851 | /* Initialize some more globals to non-zero values */ | 7876 | /* Initialize some more globals to non-zero values */ |
7852 | cmdedit_update_prompt(); | 7877 | cmdedit_update_prompt(); |
7853 | 7878 | ||
7854 | if (setjmp(die_jmp)) { | 7879 | die_func = xfunc_has_died; |
7855 | /* xfunc has failed! die die die */ | ||
7856 | /* no EXIT traps, this is an escape hatch! */ | ||
7857 | G.exiting = 1; | ||
7858 | hush_exit(xfunc_error_retval); | ||
7859 | } | ||
7860 | 7880 | ||
7861 | /* Shell is non-interactive at first. We need to call | 7881 | /* Shell is non-interactive at first. We need to call |
7862 | * install_special_sighandlers() if we are going to execute "sh <script>", | 7882 | * install_special_sighandlers() if we are going to execute "sh <script>", |
@@ -8114,9 +8134,7 @@ int hush_main(int argc, char **argv) | |||
8114 | /* Grab control of the terminal */ | 8134 | /* Grab control of the terminal */ |
8115 | tcsetpgrp(G_interactive_fd, getpid()); | 8135 | tcsetpgrp(G_interactive_fd, getpid()); |
8116 | } | 8136 | } |
8117 | /* -1 is special - makes xfuncs longjmp, not exit | 8137 | enable_restore_tty_pgrp_on_exit(); |
8118 | * (we reset die_sleep = 0 whereever we [v]fork) */ | ||
8119 | enable_restore_tty_pgrp_on_exit(); /* sets die_sleep = -1 */ | ||
8120 | 8138 | ||
8121 | # if ENABLE_HUSH_SAVEHISTORY && MAX_HISTORY > 0 | 8139 | # if ENABLE_HUSH_SAVEHISTORY && MAX_HISTORY > 0 |
8122 | { | 8140 | { |
@@ -8950,24 +8968,29 @@ static int FAST_FUNC builtin_umask(char **argv) | |||
8950 | int rc; | 8968 | int rc; |
8951 | mode_t mask; | 8969 | mode_t mask; |
8952 | 8970 | ||
8971 | rc = 1; | ||
8953 | mask = umask(0); | 8972 | mask = umask(0); |
8954 | argv = skip_dash_dash(argv); | 8973 | argv = skip_dash_dash(argv); |
8955 | if (argv[0]) { | 8974 | if (argv[0]) { |
8956 | mode_t old_mask = mask; | 8975 | mode_t old_mask = mask; |
8957 | 8976 | ||
8958 | mask ^= 0777; | 8977 | /* numeric umasks are taken as-is */ |
8959 | rc = bb_parse_mode(argv[0], &mask); | 8978 | /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */ |
8960 | mask ^= 0777; | 8979 | if (!isdigit(argv[0][0])) |
8961 | if (rc == 0) { | 8980 | mask ^= 0777; |
8981 | mask = bb_parse_mode(argv[0], mask); | ||
8982 | if (!isdigit(argv[0][0])) | ||
8983 | mask ^= 0777; | ||
8984 | if ((unsigned)mask > 0777) { | ||
8962 | mask = old_mask; | 8985 | mask = old_mask; |
8963 | /* bash messages: | 8986 | /* bash messages: |
8964 | * bash: umask: 'q': invalid symbolic mode operator | 8987 | * bash: umask: 'q': invalid symbolic mode operator |
8965 | * bash: umask: 999: octal number out of range | 8988 | * bash: umask: 999: octal number out of range |
8966 | */ | 8989 | */ |
8967 | bb_error_msg("%s: invalid mode '%s'", "umask", argv[0]); | 8990 | bb_error_msg("%s: invalid mode '%s'", "umask", argv[0]); |
8991 | rc = 0; | ||
8968 | } | 8992 | } |
8969 | } else { | 8993 | } else { |
8970 | rc = 1; | ||
8971 | /* Mimic bash */ | 8994 | /* Mimic bash */ |
8972 | printf("%04o\n", (unsigned) mask); | 8995 | printf("%04o\n", (unsigned) mask); |
8973 | /* fall through and restore mask which we set to 0 */ | 8996 | /* fall through and restore mask which we set to 0 */ |
@@ -9097,12 +9120,9 @@ static int FAST_FUNC builtin_wait(char **argv) | |||
9097 | return EXIT_FAILURE; | 9120 | return EXIT_FAILURE; |
9098 | } | 9121 | } |
9099 | if (waitpid(pid, &status, 0) == pid) { | 9122 | if (waitpid(pid, &status, 0) == pid) { |
9123 | ret = WEXITSTATUS(status); | ||
9100 | if (WIFSIGNALED(status)) | 9124 | if (WIFSIGNALED(status)) |
9101 | ret = 128 + WTERMSIG(status); | 9125 | ret = 128 + WTERMSIG(status); |
9102 | else if (WIFEXITED(status)) | ||
9103 | ret = WEXITSTATUS(status); | ||
9104 | else /* wtf? */ | ||
9105 | ret = EXIT_FAILURE; | ||
9106 | } else { | 9126 | } else { |
9107 | bb_perror_msg("wait %s", *argv); | 9127 | bb_perror_msg("wait %s", *argv); |
9108 | ret = 127; | 9128 | ret = 127; |
diff --git a/shell/hush_test/hush-glob/glob3.right b/shell/hush_test/hush-glob/glob3.right new file mode 100644 index 000000000..161b589e0 --- /dev/null +++ b/shell/hush_test/hush-glob/glob3.right | |||
@@ -0,0 +1,2 @@ | |||
1 | glob3.tests | ||
2 | ./glob3.tests | ||
diff --git a/shell/hush_test/hush-glob/glob3.tests b/shell/hush_test/hush-glob/glob3.tests new file mode 100755 index 000000000..bdf54001e --- /dev/null +++ b/shell/hush_test/hush-glob/glob3.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | echo "glob3.test"* | ||
2 | echo "./glob3.test"* | ||
diff --git a/shell/hush_test/hush-misc/nommu3.right b/shell/hush_test/hush-misc/nommu3.right new file mode 100644 index 000000000..da1534bef --- /dev/null +++ b/shell/hush_test/hush-misc/nommu3.right | |||
@@ -0,0 +1,2 @@ | |||
1 | Ok | ||
2 | 0 | ||
diff --git a/shell/hush_test/hush-misc/nommu3.tests b/shell/hush_test/hush-misc/nommu3.tests new file mode 100755 index 000000000..ac82a6a11 --- /dev/null +++ b/shell/hush_test/hush-misc/nommu3.tests | |||
@@ -0,0 +1,15 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | func() | ||
4 | { | ||
5 | while read p; do echo "$p"; done | ||
6 | } | ||
7 | |||
8 | pipe_to_func() | ||
9 | { | ||
10 | # We had a NOMMU bug which caused "echo Ok |" part to be lost | ||
11 | echo Ok | func | ||
12 | } | ||
13 | |||
14 | pipe_to_func | cat | ||
15 | echo $? | ||
diff --git a/shell/shell_common.c b/shell/shell_common.c index 1567d1de4..dbd4286bf 100644 --- a/shell/shell_common.c +++ b/shell/shell_common.c | |||
@@ -387,7 +387,7 @@ static void printlim(unsigned opts, const struct rlimit *limit, | |||
387 | val = limit->rlim_cur; | 387 | val = limit->rlim_cur; |
388 | 388 | ||
389 | if (val == RLIM_INFINITY) | 389 | if (val == RLIM_INFINITY) |
390 | printf("unlimited\n"); | 390 | puts("unlimited"); |
391 | else { | 391 | else { |
392 | val >>= l->factor_shift; | 392 | val >>= l->factor_shift; |
393 | printf("%llu\n", (long long) val); | 393 | printf("%llu\n", (long long) val); |