diff options
author | Michael I. Bushnell <mib@gnu.org> | 1994-07-21 19:03:46 +0000 |
---|---|---|
committer | Michael I. Bushnell <mib@gnu.org> | 1994-07-21 19:03:46 +0000 |
commit | 1cde8b2682dc438ef0aafa37c4a8ca9863b1e33f (patch) | |
tree | 5eeba5d1f8aa7e8e559805e67b2203f4a1a0fd98 /utils/shd.c | |
parent | 3e0f07c7d45f5e6ba6cff0215656db105a5e20af (diff) |
Initial revision
Diffstat (limited to 'utils/shd.c')
-rw-r--r-- | utils/shd.c | 366 |
1 files changed, 366 insertions, 0 deletions
diff --git a/utils/shd.c b/utils/shd.c new file mode 100644 index 00000000..c85ff07d --- /dev/null +++ b/utils/shd.c @@ -0,0 +1,366 @@ +/* + Copyright (C) 1994 Free Software Foundation + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <sys/types.h> +#include <hurd.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <device/device.h> +#include <unistd.h> +#include <errno.h> +#include <sys/wait.h> +#include <fcntl.h> +#include <stdlib.h> +#include <hurd/exec.h> + +mach_port_t proc; +int pause_startup = 0; + +void +reap (pid_t waitfor) +{ + pid_t pid; + int status; + + while (1) + { + pid = waitpid (WAIT_ANY, &status, WUNTRACED | (waitfor ? 0 : WNOHANG)); + + if (pid == -1) + { + if (errno != ESRCH && errno != EWOULDBLOCK) + perror ("waitpid"); + return; + } + else if (WIFEXITED (status)) + printf ("PID %d exit status %d\n", + pid, WEXITSTATUS (status)); + else if (WIFSIGNALED (status)) + printf ("PID %d %s\n", + pid, strsignal (WTERMSIG (status))); + else if (WIFSTOPPED (status)) + printf ("PID %d stopped: %s\n", + pid, strsignal (WSTOPSIG (status))); + else + printf ("PID %d bizarre status %#x\n", pid, status); + + if (pid == waitfor) + waitfor = 0; + } +} + +pid_t +run (char **argv, int fd0, int fd1) +{ + file_t file; + char *program; + + if (strchr (argv[0], '/') != NULL) + program = argv[0]; + else + { + size_t len = strlen (argv[0]); + const char bin[] = "/bin/"; + program = alloca (sizeof bin + len); + memcpy (program, bin, sizeof bin - 1); + memcpy (&program[sizeof bin - 1], argv[0], len + 1); + } + + file = path_lookup (program, O_EXEC, 0); + if (file == MACH_PORT_NULL) + { + perror (program); + return -1; + } + else + { + task_t task; + pid_t pid; + + if (errno = task_create (mach_task_self (), 0, &task)) + { + perror ("task_create"); + pid = -1; + } + else + { + int save0, save1; + + inline int movefd (int from, int to, int *save) + { + if (from == to) + return 0; + *save = dup (to); + if (*save < 0) + { + perror ("dup"); + return -1; + } + if (dup2 (from, to) != to) + { + perror ("dup2"); + return -1; + } + close (from); + return 0; + } + inline int restorefd (int from, int to, int *save) + { + if (from == to) + return 0; + if (dup2 (*save, to) != to) + { + perror ("dup2"); + return -1; + } + close (*save); + return 0; + } + + pid = task2pid (task); + if (pid == -1) + perror ("task2pid"), pid = 0; + if (errno = proc_child (proc, task)) + perror ("proc_child"); + if (pause_startup) + { + printf ("Pausing..."); + fflush (stdout); + getchar (); + } + + if (movefd (fd0, 0, &save0) || + movefd (fd1, 1, &save1)) + return -1; + + errno = _hurd_exec (task, file, argv, environ); + + if (restorefd (fd0, 0, &save0) || + restorefd (fd1, 1, &save1)) + return -1; + + if (errno) + { + perror ("_hurd_exec"); + if (errno = task_terminate (task)) + perror ("task_terminate"); + } + mach_port_deallocate (mach_task_self (), task); + + } + mach_port_deallocate (mach_task_self (), file); + + return pid; + } +} + +void +command (int argc, char **argv) +{ + pid_t pid; + int bg; + int i, start; + int fds[2] = { 0, 1 }; + + if (bg = !strcmp (argv[argc - 1], "&")) + argv[--argc] = NULL; + + start = 0; + for (i = 1; i < argc; ++i) + if (! strcmp (argv[i], "|")) + { + int fd0 = fds[0]; + argv[i] = NULL; + if (pipe (fds)) + { + perror ("pipe"); + return; + } + pid = run (argv + start, fd0, fds[1]); + if (pid < 0) + return; + start = i + 1; + } + + pid = run (argv + start, fds[0], 1); + + if (fds[0] != 0) + close (fds[0]); + if (fds[1] != 1) + close (fds[1]); + + reap (bg ? 0 : pid); +} + + +int +main () +{ + char *linebuf = NULL; + size_t linebufsize = 0; + + proc = getproc (); + assert (proc); + +#if 0 + { + error_t err; + mach_port_t outp; + mach_port_t hostp, masterd; + err = proc_getprivports (proc, &hostp, &masterd); + assert (!err); + + err = device_open (masterd, D_WRITE|D_READ, "console", &outp); + assert (!err); + + stdin = mach_open_devstream (outp, "r"); + stdout = stderr = mach_open_devstream (outp, "w+"); + } +#endif + + /* Kludge to give boot a port to the auth server. */ + exec_init (getdport (0), getauth (), + MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND); + + atexit ((void (*) (void)) &sync); + + while (1) + { + ssize_t n; + + sync (); + printf ("# "); + fflush (stdout); + n = getline (&linebuf, &linebufsize, stdin); + if (n == -1) + { + if (feof (stdin)) + return 0; + perror ("getline"); + continue; + } + + if (linebuf[n - 1] == '\n') + linebuf[--n] = '\0'; + + if (n > 0) + { + char *argv[(n + 1) / 2 + 1]; + int argc; + char *line, *p; + + line = linebuf; + argc = 0; + while ((p = strsep (&line, " \t\n\f\v")) != NULL) + argv[argc++] = p; + argv[argc] = NULL; + + if (!strcmp (argv[0], "exit")) + { + reap (0); + exit (0); + } + else if (!strcmp (argv[0], "pause")) + pause_startup = 1; + else if (!strcmp (argv[0], "nopause")) + pause_startup = 0; + else if (!strcmp (argv[0], "kill")) + { + if (argc == 1) + fprintf (stderr, "Usage: kill PID ...\n"); + else + { + int pid; + task_t task; + int i; + for (i = 1; i < argc; i++) + { + pid = atoi (argv[i]); + printf ("Killing pid %d\n", pid); + if (pid) + { + proc_pid2task (proc, pid, &task); + task_terminate (task); + mach_port_deallocate (mach_task_self (), task); + } + } + } + } + else if (!strcmp (argv[0], "cd")) + { + if (argc != 2) + fprintf (stderr, "Usage: cd DIRECTORY\n"); + else if (chdir (argv[1])) + perror ("chdir"); + } + else if (!strcmp (argv[0], "exec")) + { + if (argc == 1) + fprintf (stderr, "Usage: exec PROGRAM [ARGS...]\n"); + else + { + char *program; + if (strchr (argv[1], '/') != NULL) + program = argv[1]; + else + { + size_t len = strlen (argv[1]); + const char bin[] = "/bin/"; + program = alloca (sizeof bin + len); + memcpy (program, bin, sizeof bin - 1); + memcpy (&program[sizeof bin - 1], argv[1], len + 1); + } + if (execv (program, &argv[1]) == 0) + fprintf (stderr, "execv (%s) returned 0!\n", program); + else + perror ("execv"); + } + } + else if (!strcmp (argv[0], "setenv")) + { + if (argc != 3) + fprintf (stderr, "Usage: setenv VAR VALUE\n"); + else if (setenv (argv[1], argv[2], 1)) + perror ("setenv"); + } + else if (!strcmp (argv[0], "fork")) + { + pid_t pid = fork (); + switch (pid) + { + case -1: + perror ("fork"); + break; + case 0: + printf ("I am the child, PID %d.\n", (int) getpid ()); + break; + default: + printf ("I am the parent of child with PID %d.\n", pid); + reap (argc == 2 && !strcmp (argv[1], "&") ? 0 : pid); + break; + } + } + else + command (argc, argv); + } + reap (0); + fflush (stderr); + } +} + + |