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); |
