diff options
author | Eric Andersen <andersen@codepoet.org> | 2001-05-02 16:11:59 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2001-05-02 16:11:59 +0000 |
commit | bafd94f154d0a6fdf04706f7cf5687dcc8ba634b (patch) | |
tree | 070bd581bfc06c4a1eae8c230f6734720117a586 | |
parent | 1c8a59ab95d4b1a91506c69fb211fe1077e0c755 (diff) | |
download | busybox-w32-bafd94f154d0a6fdf04706f7cf5687dcc8ba634b.tar.gz busybox-w32-bafd94f154d0a6fdf04706f7cf5687dcc8ba634b.tar.bz2 busybox-w32-bafd94f154d0a6fdf04706f7cf5687dcc8ba634b.zip |
First pass at getting job control working. This gets the infrastructure
in place, but something is still missing/wrong in there. Testing with
'grep foo &' seems to put _hush_ into the background. Pondering...
-Erik
-rw-r--r-- | hush.c | 155 | ||||
-rw-r--r-- | shell/hush.c | 155 |
2 files changed, 284 insertions, 26 deletions
@@ -213,7 +213,6 @@ struct pipe { | |||
213 | int job_context; /* bitmask defining current context */ | 213 | int job_context; /* bitmask defining current context */ |
214 | pipe_style followup; /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */ | 214 | pipe_style followup; /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */ |
215 | reserved_style r_mode; /* supports if, for, while, until */ | 215 | reserved_style r_mode; /* supports if, for, while, until */ |
216 | struct jobset *job_list; | ||
217 | }; | 216 | }; |
218 | 217 | ||
219 | struct jobset { | 218 | struct jobset { |
@@ -244,7 +243,7 @@ static int fake_mode=0; | |||
244 | static int interactive=0; | 243 | static int interactive=0; |
245 | static struct close_me *close_me_head = NULL; | 244 | static struct close_me *close_me_head = NULL; |
246 | static char *cwd; | 245 | static char *cwd; |
247 | /* static struct jobset job_list = { NULL, NULL }; */ | 246 | static struct jobset *job_list; |
248 | static unsigned int last_bg_pid=0; | 247 | static unsigned int last_bg_pid=0; |
249 | static char *PS1; | 248 | static char *PS1; |
250 | static char *PS2 = "> "; | 249 | static char *PS2 = "> "; |
@@ -377,6 +376,11 @@ static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *in | |||
377 | static int parse_stream_outer(struct in_str *inp); | 376 | static int parse_stream_outer(struct in_str *inp); |
378 | static int parse_string_outer(const char *s); | 377 | static int parse_string_outer(const char *s); |
379 | static int parse_file_outer(FILE *f); | 378 | static int parse_file_outer(FILE *f); |
379 | /* job management: */ | ||
380 | static void checkjobs(); | ||
381 | static void insert_bg_job(struct pipe *pi); | ||
382 | static void remove_bg_job(struct pipe *pi); | ||
383 | static void free_pipe(struct pipe *pi); | ||
380 | 384 | ||
381 | /* Table of built-in functions. They can be forked or not, depending on | 385 | /* Table of built-in functions. They can be forked or not, depending on |
382 | * context: within pipes, they fork. As simple commands, they do not. | 386 | * context: within pipes, they fork. As simple commands, they do not. |
@@ -481,7 +485,7 @@ static int builtin_fg_bg(struct child_prog *child) | |||
481 | return EXIT_FAILURE; | 485 | return EXIT_FAILURE; |
482 | } | 486 | } |
483 | 487 | ||
484 | for (job = child->family->job_list->head; job; job = job->next) { | 488 | for (job = job_list->head; job; job = job->next) { |
485 | if (job->jobid == jobNum) { | 489 | if (job->jobid == jobNum) { |
486 | break; | 490 | break; |
487 | } | 491 | } |
@@ -498,7 +502,7 @@ static int builtin_fg_bg(struct child_prog *child) | |||
498 | /* suppress messages when run from /linuxrc mag@sysgo.de */ | 502 | /* suppress messages when run from /linuxrc mag@sysgo.de */ |
499 | if (tcsetpgrp(0, job->pgrp) && errno != ENOTTY) | 503 | if (tcsetpgrp(0, job->pgrp) && errno != ENOTTY) |
500 | perror_msg("tcsetpgrp"); | 504 | perror_msg("tcsetpgrp"); |
501 | child->family->job_list->fg = job; | 505 | job_list->fg = job; |
502 | } | 506 | } |
503 | 507 | ||
504 | /* Restart the processes in the job */ | 508 | /* Restart the processes in the job */ |
@@ -533,7 +537,7 @@ static int builtin_jobs(struct child_prog *child) | |||
533 | struct pipe *job; | 537 | struct pipe *job; |
534 | char *status_string; | 538 | char *status_string; |
535 | 539 | ||
536 | for (job = child->family->job_list->head; job; job = job->next) { | 540 | for (job = job_list->head; job; job = job->next) { |
537 | if (job->running_progs == job->stopped_progs) | 541 | if (job->running_progs == job->stopped_progs) |
538 | status_string = "Stopped"; | 542 | status_string = "Stopped"; |
539 | else | 543 | else |
@@ -1031,6 +1035,121 @@ static void pseudo_exec(struct child_prog *child) | |||
1031 | } | 1035 | } |
1032 | } | 1036 | } |
1033 | 1037 | ||
1038 | static void insert_bg_job(struct pipe *pi) | ||
1039 | { | ||
1040 | struct pipe *thejob; | ||
1041 | |||
1042 | /* Linear search for the ID of the job to use */ | ||
1043 | pi->jobid = 1; | ||
1044 | for (thejob = job_list->head; thejob; thejob = thejob->next) | ||
1045 | if (thejob->jobid >= pi->jobid) | ||
1046 | pi->jobid = thejob->jobid + 1; | ||
1047 | |||
1048 | /* add thejob to the list of running jobs */ | ||
1049 | if (!job_list->head) { | ||
1050 | thejob = job_list->head = xmalloc(sizeof(*thejob)); | ||
1051 | } else { | ||
1052 | for (thejob = job_list->head; thejob->next; thejob = thejob->next) /* nothing */; | ||
1053 | thejob->next = xmalloc(sizeof(*thejob)); | ||
1054 | thejob = thejob->next; | ||
1055 | } | ||
1056 | |||
1057 | /* physically copy the struct job */ | ||
1058 | *thejob = *pi; | ||
1059 | thejob->next = NULL; | ||
1060 | thejob->running_progs = thejob->num_progs; | ||
1061 | thejob->stopped_progs = 0; | ||
1062 | |||
1063 | /* we don't wait for background thejobs to return -- append it | ||
1064 | to the list of backgrounded thejobs and leave it alone */ | ||
1065 | printf("[%d] %d\n", pi->jobid, pi->pgrp); | ||
1066 | last_bg_pid = pi->pgrp; | ||
1067 | } | ||
1068 | |||
1069 | /* remove a backgrounded job from a jobset */ | ||
1070 | static void remove_bg_job(struct pipe *pi) | ||
1071 | { | ||
1072 | struct pipe *prev_pipe; | ||
1073 | |||
1074 | free_pipe(pi); | ||
1075 | if (pi == job_list->head) { | ||
1076 | job_list->head = pi->next; | ||
1077 | } else { | ||
1078 | prev_pipe = job_list->head; | ||
1079 | while (prev_pipe->next != pi) | ||
1080 | prev_pipe = prev_pipe->next; | ||
1081 | prev_pipe->next = pi->next; | ||
1082 | } | ||
1083 | |||
1084 | free(pi); | ||
1085 | } | ||
1086 | |||
1087 | /* free up all memory from a pipe */ | ||
1088 | static void free_pipe(struct pipe *pi) | ||
1089 | { | ||
1090 | int i; | ||
1091 | |||
1092 | for (i = 0; i < pi->num_progs; i++) { | ||
1093 | free(pi->progs[i].argv); | ||
1094 | if (pi->progs[i].redirects) | ||
1095 | free(pi->progs[i].redirects); | ||
1096 | } | ||
1097 | if (pi->progs) | ||
1098 | free(pi->progs); | ||
1099 | if (pi->text) | ||
1100 | free(pi->text); | ||
1101 | if (pi->cmdbuf) | ||
1102 | free(pi->cmdbuf); | ||
1103 | memset(pi, 0, sizeof(struct pipe)); | ||
1104 | } | ||
1105 | |||
1106 | /* Checks to see if any background processes have exited -- if they | ||
1107 | have, figure out why and see if a job has completed */ | ||
1108 | static void checkjobs() | ||
1109 | { | ||
1110 | int status; | ||
1111 | int prognum = 0; | ||
1112 | struct pipe *pi; | ||
1113 | pid_t childpid; | ||
1114 | |||
1115 | while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) { | ||
1116 | for (pi = job_list->head; pi; pi = pi->next) { | ||
1117 | prognum = 0; | ||
1118 | while (prognum < pi->num_progs && | ||
1119 | pi->progs[prognum].pid != childpid) prognum++; | ||
1120 | if (prognum < pi->num_progs) | ||
1121 | break; | ||
1122 | } | ||
1123 | |||
1124 | if (WIFEXITED(status) || WIFSIGNALED(status)) { | ||
1125 | /* child exited */ | ||
1126 | pi->running_progs--; | ||
1127 | pi->progs[prognum].pid = 0; | ||
1128 | |||
1129 | if (!pi->running_progs) { | ||
1130 | printf(JOB_STATUS_FORMAT, pi->jobid, "Done", pi->text); | ||
1131 | remove_bg_job(pi); | ||
1132 | } | ||
1133 | } else { | ||
1134 | /* child stopped */ | ||
1135 | pi->stopped_progs++; | ||
1136 | pi->progs[prognum].is_stopped = 1; | ||
1137 | |||
1138 | if (pi->stopped_progs == pi->num_progs) { | ||
1139 | printf(JOB_STATUS_FORMAT, pi->jobid, "Stopped", | ||
1140 | pi->text); | ||
1141 | } | ||
1142 | } | ||
1143 | } | ||
1144 | |||
1145 | /* move the shell to the foreground */ | ||
1146 | if (tcsetpgrp(0, getpgrp()) && errno != ENOTTY) | ||
1147 | perror_msg("tcsetpgrp"); | ||
1148 | |||
1149 | if (childpid == -1 && errno != ECHILD) | ||
1150 | perror_msg("waitpid"); | ||
1151 | } | ||
1152 | |||
1034 | /* run_pipe_real() starts all the jobs, but doesn't wait for anything | 1153 | /* run_pipe_real() starts all the jobs, but doesn't wait for anything |
1035 | * to finish. See pipe_wait(). | 1154 | * to finish. See pipe_wait(). |
1036 | * | 1155 | * |
@@ -1106,6 +1225,8 @@ static int run_pipe_real(struct pipe *pi) | |||
1106 | 1225 | ||
1107 | /* XXX test for failed fork()? */ | 1226 | /* XXX test for failed fork()? */ |
1108 | if (!(child->pid = fork())) { | 1227 | if (!(child->pid = fork())) { |
1228 | signal(SIGTTOU, SIG_DFL); | ||
1229 | |||
1109 | close_all(); | 1230 | close_all(); |
1110 | 1231 | ||
1111 | if (nextin != 0) { | 1232 | if (nextin != 0) { |
@@ -1174,22 +1295,25 @@ static int run_list_real(struct pipe *pi) | |||
1174 | /* XXX check bash's behavior with nontrivial pipes */ | 1295 | /* XXX check bash's behavior with nontrivial pipes */ |
1175 | /* XXX compute jobid */ | 1296 | /* XXX compute jobid */ |
1176 | /* XXX what does bash do with attempts to background builtins? */ | 1297 | /* XXX what does bash do with attempts to background builtins? */ |
1298 | #if 0 | ||
1177 | printf("[%d] %d\n", pi->jobid, pi->pgrp); | 1299 | printf("[%d] %d\n", pi->jobid, pi->pgrp); |
1178 | last_bg_pid = pi->pgrp; | 1300 | last_bg_pid = pi->pgrp; |
1301 | #endif | ||
1302 | insert_bg_job(pi); | ||
1179 | rcode = EXIT_SUCCESS; | 1303 | rcode = EXIT_SUCCESS; |
1180 | } else { | 1304 | } else { |
1181 | if (interactive) { | 1305 | if (interactive) { |
1182 | /* move the new process group into the foreground */ | 1306 | /* move the new process group into the foreground */ |
1183 | /* suppress messages when run from /linuxrc mag@sysgo.de */ | 1307 | /* suppress messages when run from /linuxrc mag@sysgo.de */ |
1184 | signal(SIGTTIN, SIG_IGN); | 1308 | //signal(SIGTTIN, SIG_IGN); |
1185 | signal(SIGTTOU, SIG_IGN); | 1309 | //signal(SIGTTOU, SIG_IGN); |
1186 | if (tcsetpgrp(0, pi->pgrp) && errno != ENOTTY) | 1310 | if (tcsetpgrp(0, pi->pgrp) && errno != ENOTTY) |
1187 | perror_msg("tcsetpgrp"); | 1311 | perror_msg("tcsetpgrp"); |
1188 | rcode = pipe_wait(pi); | 1312 | rcode = pipe_wait(pi); |
1189 | if (tcsetpgrp(0, getpgrp()) && errno != ENOTTY) | 1313 | if (tcsetpgrp(0, getpgrp()) && errno != ENOTTY) |
1190 | perror_msg("tcsetpgrp"); | 1314 | perror_msg("tcsetpgrp"); |
1191 | signal(SIGTTIN, SIG_DFL); | 1315 | //signal(SIGTTIN, SIG_DFL); |
1192 | signal(SIGTTOU, SIG_DFL); | 1316 | //signal(SIGTTOU, SIG_DFL); |
1193 | } else { | 1317 | } else { |
1194 | rcode = pipe_wait(pi); | 1318 | rcode = pipe_wait(pi); |
1195 | } | 1319 | } |
@@ -1202,6 +1326,7 @@ static int run_list_real(struct pipe *pi) | |||
1202 | skip_more_in_this_rmode=rmode; | 1326 | skip_more_in_this_rmode=rmode; |
1203 | /* return rcode; */ /* XXX broken if list is part of if/then/else */ | 1327 | /* return rcode; */ /* XXX broken if list is part of if/then/else */ |
1204 | } | 1328 | } |
1329 | checkjobs(); | ||
1205 | return rcode; | 1330 | return rcode; |
1206 | } | 1331 | } |
1207 | 1332 | ||
@@ -1298,7 +1423,7 @@ static int globhack(const char *src, int flags, glob_t *pglob) | |||
1298 | int cnt, pathc; | 1423 | int cnt, pathc; |
1299 | const char *s; | 1424 | const char *s; |
1300 | char *dest; | 1425 | char *dest; |
1301 | for (cnt=1, s=src; s && *s; s++) { | 1426 | for (cnt=1, s=src; *s; s++) { |
1302 | if (*s == '\\') s++; | 1427 | if (*s == '\\') s++; |
1303 | cnt++; | 1428 | cnt++; |
1304 | } | 1429 | } |
@@ -1315,7 +1440,7 @@ static int globhack(const char *src, int flags, glob_t *pglob) | |||
1315 | if (pglob->gl_pathv == NULL) return GLOB_NOSPACE; | 1440 | if (pglob->gl_pathv == NULL) return GLOB_NOSPACE; |
1316 | pglob->gl_pathv[pathc-1]=dest; | 1441 | pglob->gl_pathv[pathc-1]=dest; |
1317 | pglob->gl_pathv[pathc]=NULL; | 1442 | pglob->gl_pathv[pathc]=NULL; |
1318 | for (s=src; s && *s; s++, dest++) { | 1443 | for (s=src; *s; s++, dest++) { |
1319 | if (*s == '\\') s++; | 1444 | if (*s == '\\') s++; |
1320 | *dest = *s; | 1445 | *dest = *s; |
1321 | } | 1446 | } |
@@ -1482,8 +1607,6 @@ int reserved_word(o_string *dest, struct p_context *ctx) | |||
1482 | { "done", RES_DONE, FLAG_END } | 1607 | { "done", RES_DONE, FLAG_END } |
1483 | }; | 1608 | }; |
1484 | struct reserved_combo *r; | 1609 | struct reserved_combo *r; |
1485 | if (dest->data == NULL) | ||
1486 | return 0; | ||
1487 | for (r=reserved_list; | 1610 | for (r=reserved_list; |
1488 | #define NRES sizeof(reserved_list)/sizeof(struct reserved_combo) | 1611 | #define NRES sizeof(reserved_list)/sizeof(struct reserved_combo) |
1489 | r<reserved_list+NRES; r++) { | 1612 | r<reserved_list+NRES; r++) { |
@@ -2080,6 +2203,8 @@ int shell_main(int argc, char **argv) | |||
2080 | { | 2203 | { |
2081 | int opt; | 2204 | int opt; |
2082 | FILE *input; | 2205 | FILE *input; |
2206 | struct jobset joblist_end = { NULL, NULL }; | ||
2207 | job_list = &joblist_end; | ||
2083 | 2208 | ||
2084 | last_return_code=EXIT_SUCCESS; | 2209 | last_return_code=EXIT_SUCCESS; |
2085 | 2210 | ||
@@ -2087,6 +2212,10 @@ int shell_main(int argc, char **argv) | |||
2087 | global_argc = argc; | 2212 | global_argc = argc; |
2088 | global_argv = argv; | 2213 | global_argv = argv; |
2089 | 2214 | ||
2215 | /* don't pay any attention to this signal; it just confuses | ||
2216 | things and isn't really meant for shells anyway */ | ||
2217 | signal(SIGTTOU, SIG_IGN); | ||
2218 | |||
2090 | if (argv[0] && argv[0][0] == '-') { | 2219 | if (argv[0] && argv[0][0] == '-') { |
2091 | debug_printf("\nsourcing /etc/profile\n"); | 2220 | debug_printf("\nsourcing /etc/profile\n"); |
2092 | input = xfopen("/etc/profile", "r"); | 2221 | input = xfopen("/etc/profile", "r"); |
diff --git a/shell/hush.c b/shell/hush.c index 4641e59c8..ed4979818 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -213,7 +213,6 @@ struct pipe { | |||
213 | int job_context; /* bitmask defining current context */ | 213 | int job_context; /* bitmask defining current context */ |
214 | pipe_style followup; /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */ | 214 | pipe_style followup; /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */ |
215 | reserved_style r_mode; /* supports if, for, while, until */ | 215 | reserved_style r_mode; /* supports if, for, while, until */ |
216 | struct jobset *job_list; | ||
217 | }; | 216 | }; |
218 | 217 | ||
219 | struct jobset { | 218 | struct jobset { |
@@ -244,7 +243,7 @@ static int fake_mode=0; | |||
244 | static int interactive=0; | 243 | static int interactive=0; |
245 | static struct close_me *close_me_head = NULL; | 244 | static struct close_me *close_me_head = NULL; |
246 | static char *cwd; | 245 | static char *cwd; |
247 | /* static struct jobset job_list = { NULL, NULL }; */ | 246 | static struct jobset *job_list; |
248 | static unsigned int last_bg_pid=0; | 247 | static unsigned int last_bg_pid=0; |
249 | static char *PS1; | 248 | static char *PS1; |
250 | static char *PS2 = "> "; | 249 | static char *PS2 = "> "; |
@@ -377,6 +376,11 @@ static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *in | |||
377 | static int parse_stream_outer(struct in_str *inp); | 376 | static int parse_stream_outer(struct in_str *inp); |
378 | static int parse_string_outer(const char *s); | 377 | static int parse_string_outer(const char *s); |
379 | static int parse_file_outer(FILE *f); | 378 | static int parse_file_outer(FILE *f); |
379 | /* job management: */ | ||
380 | static void checkjobs(); | ||
381 | static void insert_bg_job(struct pipe *pi); | ||
382 | static void remove_bg_job(struct pipe *pi); | ||
383 | static void free_pipe(struct pipe *pi); | ||
380 | 384 | ||
381 | /* Table of built-in functions. They can be forked or not, depending on | 385 | /* Table of built-in functions. They can be forked or not, depending on |
382 | * context: within pipes, they fork. As simple commands, they do not. | 386 | * context: within pipes, they fork. As simple commands, they do not. |
@@ -481,7 +485,7 @@ static int builtin_fg_bg(struct child_prog *child) | |||
481 | return EXIT_FAILURE; | 485 | return EXIT_FAILURE; |
482 | } | 486 | } |
483 | 487 | ||
484 | for (job = child->family->job_list->head; job; job = job->next) { | 488 | for (job = job_list->head; job; job = job->next) { |
485 | if (job->jobid == jobNum) { | 489 | if (job->jobid == jobNum) { |
486 | break; | 490 | break; |
487 | } | 491 | } |
@@ -498,7 +502,7 @@ static int builtin_fg_bg(struct child_prog *child) | |||
498 | /* suppress messages when run from /linuxrc mag@sysgo.de */ | 502 | /* suppress messages when run from /linuxrc mag@sysgo.de */ |
499 | if (tcsetpgrp(0, job->pgrp) && errno != ENOTTY) | 503 | if (tcsetpgrp(0, job->pgrp) && errno != ENOTTY) |
500 | perror_msg("tcsetpgrp"); | 504 | perror_msg("tcsetpgrp"); |
501 | child->family->job_list->fg = job; | 505 | job_list->fg = job; |
502 | } | 506 | } |
503 | 507 | ||
504 | /* Restart the processes in the job */ | 508 | /* Restart the processes in the job */ |
@@ -533,7 +537,7 @@ static int builtin_jobs(struct child_prog *child) | |||
533 | struct pipe *job; | 537 | struct pipe *job; |
534 | char *status_string; | 538 | char *status_string; |
535 | 539 | ||
536 | for (job = child->family->job_list->head; job; job = job->next) { | 540 | for (job = job_list->head; job; job = job->next) { |
537 | if (job->running_progs == job->stopped_progs) | 541 | if (job->running_progs == job->stopped_progs) |
538 | status_string = "Stopped"; | 542 | status_string = "Stopped"; |
539 | else | 543 | else |
@@ -1031,6 +1035,121 @@ static void pseudo_exec(struct child_prog *child) | |||
1031 | } | 1035 | } |
1032 | } | 1036 | } |
1033 | 1037 | ||
1038 | static void insert_bg_job(struct pipe *pi) | ||
1039 | { | ||
1040 | struct pipe *thejob; | ||
1041 | |||
1042 | /* Linear search for the ID of the job to use */ | ||
1043 | pi->jobid = 1; | ||
1044 | for (thejob = job_list->head; thejob; thejob = thejob->next) | ||
1045 | if (thejob->jobid >= pi->jobid) | ||
1046 | pi->jobid = thejob->jobid + 1; | ||
1047 | |||
1048 | /* add thejob to the list of running jobs */ | ||
1049 | if (!job_list->head) { | ||
1050 | thejob = job_list->head = xmalloc(sizeof(*thejob)); | ||
1051 | } else { | ||
1052 | for (thejob = job_list->head; thejob->next; thejob = thejob->next) /* nothing */; | ||
1053 | thejob->next = xmalloc(sizeof(*thejob)); | ||
1054 | thejob = thejob->next; | ||
1055 | } | ||
1056 | |||
1057 | /* physically copy the struct job */ | ||
1058 | *thejob = *pi; | ||
1059 | thejob->next = NULL; | ||
1060 | thejob->running_progs = thejob->num_progs; | ||
1061 | thejob->stopped_progs = 0; | ||
1062 | |||
1063 | /* we don't wait for background thejobs to return -- append it | ||
1064 | to the list of backgrounded thejobs and leave it alone */ | ||
1065 | printf("[%d] %d\n", pi->jobid, pi->pgrp); | ||
1066 | last_bg_pid = pi->pgrp; | ||
1067 | } | ||
1068 | |||
1069 | /* remove a backgrounded job from a jobset */ | ||
1070 | static void remove_bg_job(struct pipe *pi) | ||
1071 | { | ||
1072 | struct pipe *prev_pipe; | ||
1073 | |||
1074 | free_pipe(pi); | ||
1075 | if (pi == job_list->head) { | ||
1076 | job_list->head = pi->next; | ||
1077 | } else { | ||
1078 | prev_pipe = job_list->head; | ||
1079 | while (prev_pipe->next != pi) | ||
1080 | prev_pipe = prev_pipe->next; | ||
1081 | prev_pipe->next = pi->next; | ||
1082 | } | ||
1083 | |||
1084 | free(pi); | ||
1085 | } | ||
1086 | |||
1087 | /* free up all memory from a pipe */ | ||
1088 | static void free_pipe(struct pipe *pi) | ||
1089 | { | ||
1090 | int i; | ||
1091 | |||
1092 | for (i = 0; i < pi->num_progs; i++) { | ||
1093 | free(pi->progs[i].argv); | ||
1094 | if (pi->progs[i].redirects) | ||
1095 | free(pi->progs[i].redirects); | ||
1096 | } | ||
1097 | if (pi->progs) | ||
1098 | free(pi->progs); | ||
1099 | if (pi->text) | ||
1100 | free(pi->text); | ||
1101 | if (pi->cmdbuf) | ||
1102 | free(pi->cmdbuf); | ||
1103 | memset(pi, 0, sizeof(struct pipe)); | ||
1104 | } | ||
1105 | |||
1106 | /* Checks to see if any background processes have exited -- if they | ||
1107 | have, figure out why and see if a job has completed */ | ||
1108 | static void checkjobs() | ||
1109 | { | ||
1110 | int status; | ||
1111 | int prognum = 0; | ||
1112 | struct pipe *pi; | ||
1113 | pid_t childpid; | ||
1114 | |||
1115 | while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) { | ||
1116 | for (pi = job_list->head; pi; pi = pi->next) { | ||
1117 | prognum = 0; | ||
1118 | while (prognum < pi->num_progs && | ||
1119 | pi->progs[prognum].pid != childpid) prognum++; | ||
1120 | if (prognum < pi->num_progs) | ||
1121 | break; | ||
1122 | } | ||
1123 | |||
1124 | if (WIFEXITED(status) || WIFSIGNALED(status)) { | ||
1125 | /* child exited */ | ||
1126 | pi->running_progs--; | ||
1127 | pi->progs[prognum].pid = 0; | ||
1128 | |||
1129 | if (!pi->running_progs) { | ||
1130 | printf(JOB_STATUS_FORMAT, pi->jobid, "Done", pi->text); | ||
1131 | remove_bg_job(pi); | ||
1132 | } | ||
1133 | } else { | ||
1134 | /* child stopped */ | ||
1135 | pi->stopped_progs++; | ||
1136 | pi->progs[prognum].is_stopped = 1; | ||
1137 | |||
1138 | if (pi->stopped_progs == pi->num_progs) { | ||
1139 | printf(JOB_STATUS_FORMAT, pi->jobid, "Stopped", | ||
1140 | pi->text); | ||
1141 | } | ||
1142 | } | ||
1143 | } | ||
1144 | |||
1145 | /* move the shell to the foreground */ | ||
1146 | if (tcsetpgrp(0, getpgrp()) && errno != ENOTTY) | ||
1147 | perror_msg("tcsetpgrp"); | ||
1148 | |||
1149 | if (childpid == -1 && errno != ECHILD) | ||
1150 | perror_msg("waitpid"); | ||
1151 | } | ||
1152 | |||
1034 | /* run_pipe_real() starts all the jobs, but doesn't wait for anything | 1153 | /* run_pipe_real() starts all the jobs, but doesn't wait for anything |
1035 | * to finish. See pipe_wait(). | 1154 | * to finish. See pipe_wait(). |
1036 | * | 1155 | * |
@@ -1106,6 +1225,8 @@ static int run_pipe_real(struct pipe *pi) | |||
1106 | 1225 | ||
1107 | /* XXX test for failed fork()? */ | 1226 | /* XXX test for failed fork()? */ |
1108 | if (!(child->pid = fork())) { | 1227 | if (!(child->pid = fork())) { |
1228 | signal(SIGTTOU, SIG_DFL); | ||
1229 | |||
1109 | close_all(); | 1230 | close_all(); |
1110 | 1231 | ||
1111 | if (nextin != 0) { | 1232 | if (nextin != 0) { |
@@ -1174,22 +1295,25 @@ static int run_list_real(struct pipe *pi) | |||
1174 | /* XXX check bash's behavior with nontrivial pipes */ | 1295 | /* XXX check bash's behavior with nontrivial pipes */ |
1175 | /* XXX compute jobid */ | 1296 | /* XXX compute jobid */ |
1176 | /* XXX what does bash do with attempts to background builtins? */ | 1297 | /* XXX what does bash do with attempts to background builtins? */ |
1298 | #if 0 | ||
1177 | printf("[%d] %d\n", pi->jobid, pi->pgrp); | 1299 | printf("[%d] %d\n", pi->jobid, pi->pgrp); |
1178 | last_bg_pid = pi->pgrp; | 1300 | last_bg_pid = pi->pgrp; |
1301 | #endif | ||
1302 | insert_bg_job(pi); | ||
1179 | rcode = EXIT_SUCCESS; | 1303 | rcode = EXIT_SUCCESS; |
1180 | } else { | 1304 | } else { |
1181 | if (interactive) { | 1305 | if (interactive) { |
1182 | /* move the new process group into the foreground */ | 1306 | /* move the new process group into the foreground */ |
1183 | /* suppress messages when run from /linuxrc mag@sysgo.de */ | 1307 | /* suppress messages when run from /linuxrc mag@sysgo.de */ |
1184 | signal(SIGTTIN, SIG_IGN); | 1308 | //signal(SIGTTIN, SIG_IGN); |
1185 | signal(SIGTTOU, SIG_IGN); | 1309 | //signal(SIGTTOU, SIG_IGN); |
1186 | if (tcsetpgrp(0, pi->pgrp) && errno != ENOTTY) | 1310 | if (tcsetpgrp(0, pi->pgrp) && errno != ENOTTY) |
1187 | perror_msg("tcsetpgrp"); | 1311 | perror_msg("tcsetpgrp"); |
1188 | rcode = pipe_wait(pi); | 1312 | rcode = pipe_wait(pi); |
1189 | if (tcsetpgrp(0, getpgrp()) && errno != ENOTTY) | 1313 | if (tcsetpgrp(0, getpgrp()) && errno != ENOTTY) |
1190 | perror_msg("tcsetpgrp"); | 1314 | perror_msg("tcsetpgrp"); |
1191 | signal(SIGTTIN, SIG_DFL); | 1315 | //signal(SIGTTIN, SIG_DFL); |
1192 | signal(SIGTTOU, SIG_DFL); | 1316 | //signal(SIGTTOU, SIG_DFL); |
1193 | } else { | 1317 | } else { |
1194 | rcode = pipe_wait(pi); | 1318 | rcode = pipe_wait(pi); |
1195 | } | 1319 | } |
@@ -1202,6 +1326,7 @@ static int run_list_real(struct pipe *pi) | |||
1202 | skip_more_in_this_rmode=rmode; | 1326 | skip_more_in_this_rmode=rmode; |
1203 | /* return rcode; */ /* XXX broken if list is part of if/then/else */ | 1327 | /* return rcode; */ /* XXX broken if list is part of if/then/else */ |
1204 | } | 1328 | } |
1329 | checkjobs(); | ||
1205 | return rcode; | 1330 | return rcode; |
1206 | } | 1331 | } |
1207 | 1332 | ||
@@ -1298,7 +1423,7 @@ static int globhack(const char *src, int flags, glob_t *pglob) | |||
1298 | int cnt, pathc; | 1423 | int cnt, pathc; |
1299 | const char *s; | 1424 | const char *s; |
1300 | char *dest; | 1425 | char *dest; |
1301 | for (cnt=1, s=src; s && *s; s++) { | 1426 | for (cnt=1, s=src; *s; s++) { |
1302 | if (*s == '\\') s++; | 1427 | if (*s == '\\') s++; |
1303 | cnt++; | 1428 | cnt++; |
1304 | } | 1429 | } |
@@ -1315,7 +1440,7 @@ static int globhack(const char *src, int flags, glob_t *pglob) | |||
1315 | if (pglob->gl_pathv == NULL) return GLOB_NOSPACE; | 1440 | if (pglob->gl_pathv == NULL) return GLOB_NOSPACE; |
1316 | pglob->gl_pathv[pathc-1]=dest; | 1441 | pglob->gl_pathv[pathc-1]=dest; |
1317 | pglob->gl_pathv[pathc]=NULL; | 1442 | pglob->gl_pathv[pathc]=NULL; |
1318 | for (s=src; s && *s; s++, dest++) { | 1443 | for (s=src; *s; s++, dest++) { |
1319 | if (*s == '\\') s++; | 1444 | if (*s == '\\') s++; |
1320 | *dest = *s; | 1445 | *dest = *s; |
1321 | } | 1446 | } |
@@ -1482,8 +1607,6 @@ int reserved_word(o_string *dest, struct p_context *ctx) | |||
1482 | { "done", RES_DONE, FLAG_END } | 1607 | { "done", RES_DONE, FLAG_END } |
1483 | }; | 1608 | }; |
1484 | struct reserved_combo *r; | 1609 | struct reserved_combo *r; |
1485 | if (dest->data == NULL) | ||
1486 | return 0; | ||
1487 | for (r=reserved_list; | 1610 | for (r=reserved_list; |
1488 | #define NRES sizeof(reserved_list)/sizeof(struct reserved_combo) | 1611 | #define NRES sizeof(reserved_list)/sizeof(struct reserved_combo) |
1489 | r<reserved_list+NRES; r++) { | 1612 | r<reserved_list+NRES; r++) { |
@@ -2080,6 +2203,8 @@ int shell_main(int argc, char **argv) | |||
2080 | { | 2203 | { |
2081 | int opt; | 2204 | int opt; |
2082 | FILE *input; | 2205 | FILE *input; |
2206 | struct jobset joblist_end = { NULL, NULL }; | ||
2207 | job_list = &joblist_end; | ||
2083 | 2208 | ||
2084 | last_return_code=EXIT_SUCCESS; | 2209 | last_return_code=EXIT_SUCCESS; |
2085 | 2210 | ||
@@ -2087,6 +2212,10 @@ int shell_main(int argc, char **argv) | |||
2087 | global_argc = argc; | 2212 | global_argc = argc; |
2088 | global_argv = argv; | 2213 | global_argv = argv; |
2089 | 2214 | ||
2215 | /* don't pay any attention to this signal; it just confuses | ||
2216 | things and isn't really meant for shells anyway */ | ||
2217 | signal(SIGTTOU, SIG_IGN); | ||
2218 | |||
2090 | if (argv[0] && argv[0][0] == '-') { | 2219 | if (argv[0] && argv[0][0] == '-') { |
2091 | debug_printf("\nsourcing /etc/profile\n"); | 2220 | debug_printf("\nsourcing /etc/profile\n"); |
2092 | input = xfopen("/etc/profile", "r"); | 2221 | input = xfopen("/etc/profile", "r"); |