diff options
author | Roland McGrath <roland@gnu.org> | 1999-06-18 22:04:52 +0000 |
---|---|---|
committer | Roland McGrath <roland@gnu.org> | 1999-06-18 22:04:52 +0000 |
commit | 97b6f6af188a30e571ffdff23f5b34295aa625c3 (patch) | |
tree | 06382fd275f973f1cc5a0df43c3bc7209e03de5f /daemons/console-run.c | |
parent | 2f35e2d596ab2b2fcfdd3460488a1485a13e85ec (diff) |
1999-06-15 Roland McGrath <roland@baalperazim.frob.com>
* console-run.c: New file.
* Makefile (targets, SRCS): Add console-run, console-run.c.
(console-run): New target.
Diffstat (limited to 'daemons/console-run.c')
-rw-r--r-- | daemons/console-run.c | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/daemons/console-run.c b/daemons/console-run.c new file mode 100644 index 00000000..12a00045 --- /dev/null +++ b/daemons/console-run.c @@ -0,0 +1,222 @@ +/* Run a program on the console, trying hard to get the console open. + Copyright (C) 1999 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd 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. + + The GNU Hurd 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <error.h> +#include <paths.h> +#include <hurd.h> +#include <hurd/fshelp.h> +#include <device/device.h> + +static mach_port_t +get_console () +{ + mach_port_t device_master, console; + error_t err = get_privileged_ports (0, &device_master); + + if (err) + return MACH_PORT_NULL; + + err = device_open (device_master, D_WRITE | D_READ, "console", &console); + if (err) + return MACH_PORT_NULL; + + return console; +} + +static int open_console (char **namep); + +int +main (int argc, char **argv) +{ + mach_port_t consdev = get_console (); + char *consname; + + if (consdev == MACH_PORT_NULL) + _exit (127); + + stdin = stdout = NULL; + stderr = mach_open_devstream (consdev, "w"); + if (!stderr) + _exit (127); + + if (argc < 2) + error (1, 0, "Usage: %s PROGRAM [ARG...]", program_invocation_short_name); + + if (open_console (&consname)) + setenv ("FALLBACK_CONSOLE", consname, 1); + + execv (argv[1], &argv[1]); + error (5, errno, "cannot execute %s", argv[1]); + /* NOTREACHED */ + return 127; +} + +/* Open /dev/console. If it isn't there, or it isn't a terminal, then + create /tmp/console and put the terminal on it. If we get EROFS, + in trying to create /tmp/console then as a last resort, put the + console on /tmp itself. If all fail, we exit. + + Return nonzero if the vanilla open of /dev/console didn't work. + In any case, after the console has been opened, put it on fds 0, 1, 2. */ +static int +open_console (char **namep) +{ +#define TERMINAL_FIRST_TRY "/hurd/term\0/tmp/console\0device\0console" +#define TERMINAL_SECOND_TRY "/hurd/term\0/tmp\0device\0console" + mach_port_t term, proc; + static char *termname; + struct stat st; + error_t err = 0; + int fd; + int fallback; + + termname = _PATH_CONSOLE; + term = file_name_lookup (termname, O_RDWR, 0); + if (term != MACH_PORT_NULL) + err = io_stat (term, &st); + else + err = errno; + if (err) + error (0, err, "%s", termname); + else if (st.st_fstype != FSTYPE_TERM) + error (0, 0, "%s: Not a terminal", termname); + + fallback = (term == MACH_PORT_NULL || err || st.st_fstype != FSTYPE_TERM); + if (fallback) + /* Start the terminal server ourselves. */ + { + size_t argz_len; /* Length of args passed to translator. */ + char *terminal; /* Name of term translator. */ + mach_port_t control; /* Control port for term translator. */ + int try; + + error_t open_node (int flags, + mach_port_t *underlying, + mach_msg_type_name_t *underlying_type) + { + term = file_name_lookup (termname, flags | O_CREAT|O_NOTRANS, 0666); + if (term == MACH_PORT_NULL) + { + error (0, errno, "%s", termname); + return errno; + } + + *underlying = term; + *underlying_type = MACH_MSG_TYPE_COPY_SEND; + + return 0; + } + + for (try = 1; try < 3; ++try) + { + if (try == 1) + { + terminal = TERMINAL_FIRST_TRY; + argz_len = sizeof TERMINAL_FIRST_TRY; + } + else if (try == 2) + { + terminal = TERMINAL_SECOND_TRY; + argz_len = sizeof TERMINAL_SECOND_TRY; + } + + termname = terminal + strlen (terminal) + 1; /* first arg is name */ + + /* The callback to start_translator opens TERM as a side effect. */ + errno = + fshelp_start_translator (open_node, terminal, terminal, argz_len, + 3000, &control); + if (errno) + { + error (0, errno, "%s", terminal); + continue; + } + + errno = file_set_translator (term, 0, FS_TRANS_SET, 0, 0, 0, + control, MACH_MSG_TYPE_COPY_SEND); + mach_port_deallocate (mach_task_self (), control); + if (errno) + { + error (0, errno, "%s", termname); + continue; + } + mach_port_deallocate (mach_task_self (), term); + + /* Now repeat the open. */ + term = file_name_lookup (termname, O_RDWR, 0); + if (term == MACH_PORT_NULL) + { + error (0, errno, "%s", termname); + continue; + } + errno = io_stat (term, &st); + if (errno) + { + error (0, errno, "%s", termname); + term = MACH_PORT_NULL; + continue; + } + if (st.st_fstype != FSTYPE_TERM) + { + error (0, 0, "%s: Not a terminal", termname); + term = MACH_PORT_NULL; + continue; + } + + if (term != MACH_PORT_NULL) + { + error (0, 0, "Using temporary console %s", termname); + break; + } + } + + if (term == MACH_PORT_NULL) + error (2, 0, "Cannot start console terminal"); + } + + fd = openport (term, O_RDWR); + if (fd < 0) + error (3, errno, "Cannot open console"); + + if (fd != 0) + { + dup2 (fd, 0); + close (fd); + } + dup2 (0, 1); + dup2 (0, 2); + + if (setsid ()) + error (0, errno, "setsid"); + + /* Set the console to our pgrp. */ + tcsetpgrp (0, getpid ()); + + /* Put us in a new login collection. */ + proc = getproc (); + proc_make_login_coll (proc); + mach_port_deallocate (mach_task_self (), proc); + + *namep = termname; + return fallback; +} |