Some more job control updates. It will now sucessfully background
stuff. Good luck getting things back into the foreground though... -Erik
This commit is contained in:
parent
20a3069ec0
commit
0fcd447d59
118
hush.c
118
hush.c
@ -470,48 +470,53 @@ static int builtin_export(struct child_prog *child)
|
|||||||
/* built-in 'fg' and 'bg' handler */
|
/* built-in 'fg' and 'bg' handler */
|
||||||
static int builtin_fg_bg(struct child_prog *child)
|
static int builtin_fg_bg(struct child_prog *child)
|
||||||
{
|
{
|
||||||
int i, jobNum;
|
int i, jobnum;
|
||||||
struct pipe *job=NULL;
|
struct pipe *pi=NULL;
|
||||||
|
|
||||||
if (!child->argv[1] || child->argv[2]) {
|
/* If they gave us no args, assume they want the last backgrounded task */
|
||||||
error_msg("%s: exactly one argument is expected\n",
|
if (!child->argv[1]) {
|
||||||
child->argv[0]);
|
for (pi = job_list->head; pi; pi = pi->next) {
|
||||||
return EXIT_FAILURE;
|
if (pi->progs && pi->progs->pid == last_bg_pid) {
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!pi) {
|
||||||
|
error_msg("%s: no current job", child->argv[0]);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) {
|
||||||
|
error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
if (sscanf(child->argv[1], "%%%d", &jobNum) != 1) {
|
for (pi = job_list->head; pi; pi = pi->next) {
|
||||||
error_msg("%s: bad argument '%s'\n",
|
if (pi->jobid == jobnum) {
|
||||||
child->argv[0], child->argv[1]);
|
break;
|
||||||
return EXIT_FAILURE;
|
}
|
||||||
}
|
}
|
||||||
|
if (!pi) {
|
||||||
for (job = job_list->head; job; job = job->next) {
|
error_msg("%s: %d: no such job", child->argv[0], jobnum);
|
||||||
if (job->jobid == jobNum) {
|
return EXIT_FAILURE;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!job) {
|
|
||||||
error_msg("%s: unknown job %d\n",
|
|
||||||
child->argv[0], jobNum);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*child->argv[0] == 'f') {
|
if (*child->argv[0] == 'f') {
|
||||||
/* Make this job the foreground job */
|
/* Make this job the foreground job */
|
||||||
|
signal(SIGTTOU, SIG_IGN);
|
||||||
/* suppress messages when run from /linuxrc mag@sysgo.de */
|
/* suppress messages when run from /linuxrc mag@sysgo.de */
|
||||||
if (tcsetpgrp(0, job->pgrp) && errno != ENOTTY)
|
if (tcsetpgrp(0, pi->pgrp) && errno != ENOTTY)
|
||||||
perror_msg("tcsetpgrp");
|
perror_msg("tcsetpgrp");
|
||||||
job_list->fg = job;
|
signal(SIGTTOU, SIG_DFL);
|
||||||
|
job_list->fg = pi;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Restart the processes in the job */
|
/* Restart the processes in the job */
|
||||||
for (i = 0; i < job->num_progs; i++)
|
for (i = 0; i < pi->num_progs; i++)
|
||||||
job->progs[i].is_stopped = 0;
|
pi->progs[i].is_stopped = 0;
|
||||||
|
|
||||||
kill(-job->pgrp, SIGCONT);
|
kill(-pi->pgrp, SIGCONT);
|
||||||
|
|
||||||
job->stopped_progs = 0;
|
pi->stopped_progs = 0;
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1055,7 +1060,7 @@ static void insert_bg_job(struct pipe *pi)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* physically copy the struct job */
|
/* physically copy the struct job */
|
||||||
*thejob = *pi;
|
memcpy(thejob, pi, sizeof(struct pipe));
|
||||||
thejob->next = NULL;
|
thejob->next = NULL;
|
||||||
thejob->running_progs = thejob->num_progs;
|
thejob->running_progs = thejob->num_progs;
|
||||||
thejob->stopped_progs = 0;
|
thejob->stopped_progs = 0;
|
||||||
@ -1103,6 +1108,7 @@ static void free_pipe(struct pipe *pi)
|
|||||||
memset(pi, 0, sizeof(struct pipe));
|
memset(pi, 0, sizeof(struct pipe));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Checks to see if any background processes have exited -- if they
|
/* Checks to see if any background processes have exited -- if they
|
||||||
have, figure out why and see if a job has completed */
|
have, figure out why and see if a job has completed */
|
||||||
static void checkjobs()
|
static void checkjobs()
|
||||||
@ -1169,14 +1175,27 @@ static void checkjobs()
|
|||||||
static int run_pipe_real(struct pipe *pi)
|
static int run_pipe_real(struct pipe *pi)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
int ctty;
|
||||||
int nextin, nextout;
|
int nextin, nextout;
|
||||||
int pipefds[2]; /* pipefds[0] is for reading */
|
int pipefds[2]; /* pipefds[0] is for reading */
|
||||||
struct child_prog *child;
|
struct child_prog *child;
|
||||||
struct built_in_command *x;
|
struct built_in_command *x;
|
||||||
|
|
||||||
|
ctty = -1;
|
||||||
nextin = 0;
|
nextin = 0;
|
||||||
pi->pgrp = 0;
|
pi->pgrp = 0;
|
||||||
|
|
||||||
|
/* Check if we are supposed to run in the foreground */
|
||||||
|
if (pi->followup!=PIPE_BG) {
|
||||||
|
if ((pi->pgrp = tcgetpgrp(ctty = 2)) < 0
|
||||||
|
&& (pi->pgrp = tcgetpgrp(ctty = 0)) < 0
|
||||||
|
&& (pi->pgrp = tcgetpgrp(ctty = 1)) < 0)
|
||||||
|
return errno = ENOTTY, -1;
|
||||||
|
|
||||||
|
if (pi->pgrp < 0 && pi->pgrp != getpgrp())
|
||||||
|
return errno = EPERM, -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if this is a simple builtin (not part of a pipe).
|
/* Check if this is a simple builtin (not part of a pipe).
|
||||||
* Builtins within pipes have to fork anyway, and are handled in
|
* Builtins within pipes have to fork anyway, and are handled in
|
||||||
* pseudo_exec. "echo foo | read bar" doesn't work on bash, either.
|
* pseudo_exec. "echo foo | read bar" doesn't work on bash, either.
|
||||||
@ -1225,6 +1244,7 @@ static int run_pipe_real(struct pipe *pi)
|
|||||||
|
|
||||||
/* XXX test for failed fork()? */
|
/* XXX test for failed fork()? */
|
||||||
if (!(child->pid = fork())) {
|
if (!(child->pid = fork())) {
|
||||||
|
|
||||||
signal(SIGTTOU, SIG_DFL);
|
signal(SIGTTOU, SIG_DFL);
|
||||||
|
|
||||||
close_all();
|
close_all();
|
||||||
@ -1245,20 +1265,31 @@ static int run_pipe_real(struct pipe *pi)
|
|||||||
* and the pipe fd is available for dup'ing. */
|
* and the pipe fd is available for dup'ing. */
|
||||||
setup_redirects(child,NULL);
|
setup_redirects(child,NULL);
|
||||||
|
|
||||||
|
if (pi->followup!=PIPE_BG) {
|
||||||
|
/* Put our child in the process group whose leader is the
|
||||||
|
* first process in this pipe. */
|
||||||
|
if (pi->pgrp < 0) {
|
||||||
|
pi->pgrp = child->pid;
|
||||||
|
}
|
||||||
|
/* Don't check for errors. The child may be dead already,
|
||||||
|
* in which case setpgid returns error code EACCES. */
|
||||||
|
if (setpgid(0, pi->pgrp) == 0) {
|
||||||
|
signal(SIGTTOU, SIG_IGN);
|
||||||
|
tcsetpgrp(ctty, pi->pgrp);
|
||||||
|
signal(SIGTTOU, SIG_DFL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pseudo_exec(child);
|
pseudo_exec(child);
|
||||||
}
|
}
|
||||||
if (interactive) {
|
/* Put our child in the process group whose leader is the
|
||||||
/* Put our child in the process group whose leader is the
|
* first process in this pipe. */
|
||||||
* first process in this pipe. */
|
if (pi->pgrp < 0) {
|
||||||
if (pi->pgrp==0) {
|
pi->pgrp = child->pid;
|
||||||
pi->pgrp = child->pid;
|
|
||||||
}
|
|
||||||
/* Don't check for errors. The child may be dead already,
|
|
||||||
* in which case setpgid returns error code EACCES. */
|
|
||||||
setpgid(child->pid, pi->pgrp);
|
|
||||||
}
|
}
|
||||||
/* In the non-interactive case, do nothing. Leave the children
|
/* Don't check for errors. The child may be dead already,
|
||||||
* with the process group that they inherited from us. */
|
* in which case setpgid returns error code EACCES. */
|
||||||
|
setpgid(child->pid, pi->pgrp);
|
||||||
|
|
||||||
if (nextin != 0)
|
if (nextin != 0)
|
||||||
close(nextin);
|
close(nextin);
|
||||||
@ -1295,13 +1326,10 @@ static int run_list_real(struct pipe *pi)
|
|||||||
/* XXX check bash's behavior with nontrivial pipes */
|
/* XXX check bash's behavior with nontrivial pipes */
|
||||||
/* XXX compute jobid */
|
/* XXX compute jobid */
|
||||||
/* XXX what does bash do with attempts to background builtins? */
|
/* XXX what does bash do with attempts to background builtins? */
|
||||||
#if 0
|
|
||||||
printf("[%d] %d\n", pi->jobid, pi->pgrp);
|
|
||||||
last_bg_pid = pi->pgrp;
|
|
||||||
#endif
|
|
||||||
insert_bg_job(pi);
|
insert_bg_job(pi);
|
||||||
rcode = EXIT_SUCCESS;
|
rcode = EXIT_SUCCESS;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (interactive) {
|
if (interactive) {
|
||||||
/* move the new process group into the foreground */
|
/* move the new process group into the foreground */
|
||||||
/* suppress messages when run from /linuxrc mag@sysgo.de */
|
/* suppress messages when run from /linuxrc mag@sysgo.de */
|
||||||
|
118
shell/hush.c
118
shell/hush.c
@ -470,48 +470,53 @@ static int builtin_export(struct child_prog *child)
|
|||||||
/* built-in 'fg' and 'bg' handler */
|
/* built-in 'fg' and 'bg' handler */
|
||||||
static int builtin_fg_bg(struct child_prog *child)
|
static int builtin_fg_bg(struct child_prog *child)
|
||||||
{
|
{
|
||||||
int i, jobNum;
|
int i, jobnum;
|
||||||
struct pipe *job=NULL;
|
struct pipe *pi=NULL;
|
||||||
|
|
||||||
if (!child->argv[1] || child->argv[2]) {
|
/* If they gave us no args, assume they want the last backgrounded task */
|
||||||
error_msg("%s: exactly one argument is expected\n",
|
if (!child->argv[1]) {
|
||||||
child->argv[0]);
|
for (pi = job_list->head; pi; pi = pi->next) {
|
||||||
return EXIT_FAILURE;
|
if (pi->progs && pi->progs->pid == last_bg_pid) {
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!pi) {
|
||||||
|
error_msg("%s: no current job", child->argv[0]);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) {
|
||||||
|
error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
if (sscanf(child->argv[1], "%%%d", &jobNum) != 1) {
|
for (pi = job_list->head; pi; pi = pi->next) {
|
||||||
error_msg("%s: bad argument '%s'\n",
|
if (pi->jobid == jobnum) {
|
||||||
child->argv[0], child->argv[1]);
|
break;
|
||||||
return EXIT_FAILURE;
|
}
|
||||||
}
|
}
|
||||||
|
if (!pi) {
|
||||||
for (job = job_list->head; job; job = job->next) {
|
error_msg("%s: %d: no such job", child->argv[0], jobnum);
|
||||||
if (job->jobid == jobNum) {
|
return EXIT_FAILURE;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!job) {
|
|
||||||
error_msg("%s: unknown job %d\n",
|
|
||||||
child->argv[0], jobNum);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*child->argv[0] == 'f') {
|
if (*child->argv[0] == 'f') {
|
||||||
/* Make this job the foreground job */
|
/* Make this job the foreground job */
|
||||||
|
signal(SIGTTOU, SIG_IGN);
|
||||||
/* suppress messages when run from /linuxrc mag@sysgo.de */
|
/* suppress messages when run from /linuxrc mag@sysgo.de */
|
||||||
if (tcsetpgrp(0, job->pgrp) && errno != ENOTTY)
|
if (tcsetpgrp(0, pi->pgrp) && errno != ENOTTY)
|
||||||
perror_msg("tcsetpgrp");
|
perror_msg("tcsetpgrp");
|
||||||
job_list->fg = job;
|
signal(SIGTTOU, SIG_DFL);
|
||||||
|
job_list->fg = pi;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Restart the processes in the job */
|
/* Restart the processes in the job */
|
||||||
for (i = 0; i < job->num_progs; i++)
|
for (i = 0; i < pi->num_progs; i++)
|
||||||
job->progs[i].is_stopped = 0;
|
pi->progs[i].is_stopped = 0;
|
||||||
|
|
||||||
kill(-job->pgrp, SIGCONT);
|
kill(-pi->pgrp, SIGCONT);
|
||||||
|
|
||||||
job->stopped_progs = 0;
|
pi->stopped_progs = 0;
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1055,7 +1060,7 @@ static void insert_bg_job(struct pipe *pi)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* physically copy the struct job */
|
/* physically copy the struct job */
|
||||||
*thejob = *pi;
|
memcpy(thejob, pi, sizeof(struct pipe));
|
||||||
thejob->next = NULL;
|
thejob->next = NULL;
|
||||||
thejob->running_progs = thejob->num_progs;
|
thejob->running_progs = thejob->num_progs;
|
||||||
thejob->stopped_progs = 0;
|
thejob->stopped_progs = 0;
|
||||||
@ -1103,6 +1108,7 @@ static void free_pipe(struct pipe *pi)
|
|||||||
memset(pi, 0, sizeof(struct pipe));
|
memset(pi, 0, sizeof(struct pipe));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Checks to see if any background processes have exited -- if they
|
/* Checks to see if any background processes have exited -- if they
|
||||||
have, figure out why and see if a job has completed */
|
have, figure out why and see if a job has completed */
|
||||||
static void checkjobs()
|
static void checkjobs()
|
||||||
@ -1169,14 +1175,27 @@ static void checkjobs()
|
|||||||
static int run_pipe_real(struct pipe *pi)
|
static int run_pipe_real(struct pipe *pi)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
int ctty;
|
||||||
int nextin, nextout;
|
int nextin, nextout;
|
||||||
int pipefds[2]; /* pipefds[0] is for reading */
|
int pipefds[2]; /* pipefds[0] is for reading */
|
||||||
struct child_prog *child;
|
struct child_prog *child;
|
||||||
struct built_in_command *x;
|
struct built_in_command *x;
|
||||||
|
|
||||||
|
ctty = -1;
|
||||||
nextin = 0;
|
nextin = 0;
|
||||||
pi->pgrp = 0;
|
pi->pgrp = 0;
|
||||||
|
|
||||||
|
/* Check if we are supposed to run in the foreground */
|
||||||
|
if (pi->followup!=PIPE_BG) {
|
||||||
|
if ((pi->pgrp = tcgetpgrp(ctty = 2)) < 0
|
||||||
|
&& (pi->pgrp = tcgetpgrp(ctty = 0)) < 0
|
||||||
|
&& (pi->pgrp = tcgetpgrp(ctty = 1)) < 0)
|
||||||
|
return errno = ENOTTY, -1;
|
||||||
|
|
||||||
|
if (pi->pgrp < 0 && pi->pgrp != getpgrp())
|
||||||
|
return errno = EPERM, -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if this is a simple builtin (not part of a pipe).
|
/* Check if this is a simple builtin (not part of a pipe).
|
||||||
* Builtins within pipes have to fork anyway, and are handled in
|
* Builtins within pipes have to fork anyway, and are handled in
|
||||||
* pseudo_exec. "echo foo | read bar" doesn't work on bash, either.
|
* pseudo_exec. "echo foo | read bar" doesn't work on bash, either.
|
||||||
@ -1225,6 +1244,7 @@ static int run_pipe_real(struct pipe *pi)
|
|||||||
|
|
||||||
/* XXX test for failed fork()? */
|
/* XXX test for failed fork()? */
|
||||||
if (!(child->pid = fork())) {
|
if (!(child->pid = fork())) {
|
||||||
|
|
||||||
signal(SIGTTOU, SIG_DFL);
|
signal(SIGTTOU, SIG_DFL);
|
||||||
|
|
||||||
close_all();
|
close_all();
|
||||||
@ -1245,20 +1265,31 @@ static int run_pipe_real(struct pipe *pi)
|
|||||||
* and the pipe fd is available for dup'ing. */
|
* and the pipe fd is available for dup'ing. */
|
||||||
setup_redirects(child,NULL);
|
setup_redirects(child,NULL);
|
||||||
|
|
||||||
|
if (pi->followup!=PIPE_BG) {
|
||||||
|
/* Put our child in the process group whose leader is the
|
||||||
|
* first process in this pipe. */
|
||||||
|
if (pi->pgrp < 0) {
|
||||||
|
pi->pgrp = child->pid;
|
||||||
|
}
|
||||||
|
/* Don't check for errors. The child may be dead already,
|
||||||
|
* in which case setpgid returns error code EACCES. */
|
||||||
|
if (setpgid(0, pi->pgrp) == 0) {
|
||||||
|
signal(SIGTTOU, SIG_IGN);
|
||||||
|
tcsetpgrp(ctty, pi->pgrp);
|
||||||
|
signal(SIGTTOU, SIG_DFL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pseudo_exec(child);
|
pseudo_exec(child);
|
||||||
}
|
}
|
||||||
if (interactive) {
|
/* Put our child in the process group whose leader is the
|
||||||
/* Put our child in the process group whose leader is the
|
* first process in this pipe. */
|
||||||
* first process in this pipe. */
|
if (pi->pgrp < 0) {
|
||||||
if (pi->pgrp==0) {
|
pi->pgrp = child->pid;
|
||||||
pi->pgrp = child->pid;
|
|
||||||
}
|
|
||||||
/* Don't check for errors. The child may be dead already,
|
|
||||||
* in which case setpgid returns error code EACCES. */
|
|
||||||
setpgid(child->pid, pi->pgrp);
|
|
||||||
}
|
}
|
||||||
/* In the non-interactive case, do nothing. Leave the children
|
/* Don't check for errors. The child may be dead already,
|
||||||
* with the process group that they inherited from us. */
|
* in which case setpgid returns error code EACCES. */
|
||||||
|
setpgid(child->pid, pi->pgrp);
|
||||||
|
|
||||||
if (nextin != 0)
|
if (nextin != 0)
|
||||||
close(nextin);
|
close(nextin);
|
||||||
@ -1295,13 +1326,10 @@ static int run_list_real(struct pipe *pi)
|
|||||||
/* XXX check bash's behavior with nontrivial pipes */
|
/* XXX check bash's behavior with nontrivial pipes */
|
||||||
/* XXX compute jobid */
|
/* XXX compute jobid */
|
||||||
/* XXX what does bash do with attempts to background builtins? */
|
/* XXX what does bash do with attempts to background builtins? */
|
||||||
#if 0
|
|
||||||
printf("[%d] %d\n", pi->jobid, pi->pgrp);
|
|
||||||
last_bg_pid = pi->pgrp;
|
|
||||||
#endif
|
|
||||||
insert_bg_job(pi);
|
insert_bg_job(pi);
|
||||||
rcode = EXIT_SUCCESS;
|
rcode = EXIT_SUCCESS;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (interactive) {
|
if (interactive) {
|
||||||
/* move the new process group into the foreground */
|
/* move the new process group into the foreground */
|
||||||
/* suppress messages when run from /linuxrc mag@sysgo.de */
|
/* suppress messages when run from /linuxrc mag@sysgo.de */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user