diff options
Diffstat (limited to 'shell/ash.c')
-rw-r--r-- | shell/ash.c | 255 |
1 files changed, 121 insertions, 134 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); |