diff --git a/apps/sh.c b/apps/sh.c index 6efb0a9b..2ecfa66a 100644 --- a/apps/sh.c +++ b/apps/sh.c @@ -71,9 +71,32 @@ static int current_line = 0; static char * current_file = NULL; int pid; /* Process ID of the shell */ +int my_pgid; int is_subshell = 0; +struct semaphore { + int fds[2]; +}; + +struct semaphore create_semaphore(void) { + struct semaphore out; + pipe(out.fds); + return out; +} + +void raise_semaphore(struct semaphore s){ + close(s.fds[0]); + close(s.fds[1]); +} + +void wait_semaphore(struct semaphore s) { + close(s.fds[1]); + char buf; + read(s.fds[0], &buf, 1); + close(s.fds[0]); +} + void set_pgid(int pgid) { if (shell_interactive == 1) { setpgid(0, pgid); @@ -88,7 +111,7 @@ void set_pgrp(int pgid) { void reset_pgrp() { if (shell_interactive == 1 && !is_subshell) { - tcsetpgrp(STDIN_FILENO, pid); + tcsetpgrp(STDIN_FILENO, my_pgid); } } @@ -783,9 +806,11 @@ int wait_for_child(int pgid, char * name) { int waitee = (shell_interactive == 1 && !is_subshell) ? -pgid : pgid; int outpid; int ret_code = 0; + int e; do { outpid = waitpid(waitee, &ret_code, WSTOPPED); + e = errno; if (WIFSTOPPED(ret_code)) { suspended_pgid = pgid; if (name) { @@ -797,7 +822,7 @@ int wait_for_child(int pgid, char * name) { suspended_pgid = 0; hashmap_remove(job_hash, (void*)pgid); } - } while (outpid != -1 || (outpid == -1 && errno != ECHILD)); + } while (outpid != -1 || (outpid == -1 && e != ECHILD)); reset_pgrp(); handle_status(ret_code); return WEXITSTATUS(ret_code); @@ -1244,10 +1269,13 @@ _nope: if (cmdi > 0) { int last_output[2]; pipe(last_output); + + struct semaphore s = create_semaphore(); child_pid = fork(); if (!child_pid) { set_pgid(0); - set_pgrp(getpid()); + if (!nowait) set_pgrp(getpid()); + raise_semaphore(s); is_subshell = 1; dup2(last_output[1], STDOUT_FILENO); close(last_output[0]); @@ -1294,16 +1322,20 @@ _nope: close(last_output[0]); close(last_output[1]); + wait_semaphore(s); + /* Now execute the last piece and wait on all of them */ } else { shell_command_t func = shell_find(*arg_starts[0]); if (func) { return func(argcs[0], arg_starts[0]); } else { + struct semaphore s = create_semaphore(); child_pid = fork(); if (!child_pid) { set_pgid(0); - set_pgrp(getpid()); + if (!nowait) set_pgrp(getpid()); + raise_semaphore(s); is_subshell = 1; if (output_files[cmdi]) { int fd = open(output_files[cmdi], file_args[cmdi], 0666); @@ -1316,6 +1348,9 @@ _nope: } run_cmd(arg_starts[0]); } + + wait_semaphore(s); + pgid = child_pid; last_child = child_pid; } @@ -1519,7 +1554,7 @@ int main(int argc, char ** argv) { shell_interactive = 1; - signal(SIGTSTP, SIG_IGN); + my_pgid = getpgid(0); signal(SIGTTOU, SIG_IGN); signal(SIGTTIN, SIG_IGN); diff --git a/base/usr/include/syscall.h b/base/usr/include/syscall.h index 4db3ef1c..01b58d86 100644 --- a/base/usr/include/syscall.h +++ b/base/usr/include/syscall.h @@ -119,6 +119,7 @@ DECL_SYSCALL1(pipe, int *); DECL_SYSCALL3(readlink, char *, char *, int); DECL_SYSCALL0(setsid); DECL_SYSCALL2(setpgid,int,int); +DECL_SYSCALL1(getpgid,int); _End_C_Header diff --git a/base/usr/include/syscall_nums.h b/base/usr/include/syscall_nums.h index 11d4d182..1e790e38 100644 --- a/base/usr/include/syscall_nums.h +++ b/base/usr/include/syscall_nums.h @@ -52,3 +52,4 @@ #define SYS_CHOWN 61 #define SYS_SETSID 62 #define SYS_SETPGID 63 +#define SYS_GETPGID 64 diff --git a/base/usr/include/unistd.h b/base/usr/include/unistd.h index c1342ad9..603890cf 100644 --- a/base/usr/include/unistd.h +++ b/base/usr/include/unistd.h @@ -85,5 +85,6 @@ extern int sethostname(const char * name, size_t len); extern pid_t setsid(void); extern int setpgid(pid_t, pid_t); +extern pid_t getpgid(pid_t); _End_C_Header diff --git a/kernel/sys/syscall.c b/kernel/sys/syscall.c index d7ea1466..f034dc95 100644 --- a/kernel/sys/syscall.c +++ b/kernel/sys/syscall.c @@ -986,6 +986,21 @@ static int sys_setpgid(pid_t pid, pid_t pgid) { return 0; } +static int sys_getpgid(pid_t pid) { + process_t * proc; + if (pid == 0) { + proc = (process_t*)current_process; + } else { + proc = process_from_pid(pid); + } + + if (!proc) { + return -ESRCH; + } + + return proc->job; +} + /* * System Call Internals */ @@ -1043,6 +1058,7 @@ static int (*syscalls[])() = { [SYS_CHOWN] = sys_chown, [SYS_SETSID] = sys_setsid, [SYS_SETPGID] = sys_setpgid, + [SYS_GETPGID] = sys_getpgid, }; uint32_t num_syscalls = sizeof(syscalls) / sizeof(*syscalls); diff --git a/libc/unistd/setpgid.c b/libc/unistd/setpgid.c index 62c73b1e..3bfca064 100644 --- a/libc/unistd/setpgid.c +++ b/libc/unistd/setpgid.c @@ -4,8 +4,13 @@ #include DEFN_SYSCALL2(setpgid, SYS_SETPGID, int, int); +DEFN_SYSCALL1(getpgid, SYS_GETPGID, int); int setpgid(pid_t pid, pid_t pgid) { __sets_errno(syscall_setpgid((int)pid,(int)pgid)); } +pid_t getpgid(pid_t pid) { + __sets_errno(syscall_getpgid((int)pid)); +} +