Make init(8) slightly more robust when /dev/console is missing.

If the environment doesn't offer a working /dev/console, the existing
version of init(8) will simply refuse running rc(8) scripts. This means
you'll only have a system running init(8) and nothing else.

Change the code to do the following:

- Open /dev/console like we used to do, but make it more robust to use
  O_NONBLOCK to prevent blocking on a carrier.
- If this fails, use /dev/null as stdin and /var/log/init.log as stdout
  and stderr.
- If even this fails, use /dev/null as stdin, stdout and stderr.

So why us this useful? Well, if you remove the `getpid() == 1' check in
main(), you can now use init(8) inside jails to properly execute rc(8).
It still requires some polishing, as existing tools assume init(8) has
PID 1.

Also it is now possible to use use init(8) on `headless' devices that
don't even have a serial boot console.
This commit is contained in:
ed 2012-03-14 16:22:09 +00:00
parent a6abf8bf85
commit 1204585265
4 changed files with 35 additions and 17 deletions

View File

@ -24,6 +24,7 @@
/var/log/cron 600 3 100 * JC
/var/log/daily.log 640 7 * @T00 JN
/var/log/debug.log 600 7 100 * JC
/var/log/init.log 644 3 100 * J
/var/log/kerberos.log 600 7 100 * J
/var/log/lpd-errs 644 7 100 * JC
/var/log/maillog 640 7 * @T00 JC

View File

@ -31,7 +31,7 @@
.\" @(#)init.8 8.3 (Berkeley) 4/18/94
.\" $FreeBSD$
.\"
.Dd February 11, 2012
.Dd March 14, 2012
.Dt INIT 8
.Os
.Sh NAME
@ -293,22 +293,22 @@ as follows:
file
.El
.Sh FILES
.Bl -tag -width /etc/rc.shutdown -compact
.Bl -tag -width /var/log/init.log -compact
.It Pa /dev/console
system console device
.It Pa /dev/tty*
terminal ports found in
.Xr ttys 5
.It Pa /var/run/utx.active
record of current users on the system
.It Pa /var/log/utx.log
record of all logins and logouts
.It Pa /etc/ttys
the terminal initialization information file
.It Pa /etc/rc
system startup commands
.It Pa /etc/rc.shutdown
system shutdown commands
.It Pa /var/log/init.log
log of
.Xr rc 8
output if the system console device is not available
.El
.Sh DIAGNOSTICS
.Bl -diag

View File

@ -138,7 +138,7 @@ static void transition(state_t);
static state_t requested_transition;
static state_t current_state = death_single;
static void setctty(const char *);
static void open_console(void);
static const char *get_shell(void);
static void write_stderr(const char *message);
@ -568,19 +568,35 @@ transition(state_t s)
* Only called by children of init after forking.
*/
static void
setctty(const char *name)
open_console(void)
{
int fd;
revoke(name);
if ((fd = open(name, O_RDWR)) == -1) {
stall("can't open %s: %m", name);
/* Try to open /dev/console. */
revoke(_PATH_CONSOLE);
if ((fd = open(_PATH_CONSOLE, O_RDWR | O_NONBLOCK)) != -1) {
if (login_tty(fd) == 0)
return;
close(fd);
}
/* No luck. Log output to file if possible. */
if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
stall("cannot open null device.");
_exit(1);
}
if (login_tty(fd) == -1) {
stall("can't get %s for controlling terminal: %m", name);
_exit(1);
if (fd != STDIN_FILENO) {
dup2(fd, STDIN_FILENO);
close(fd);
}
fd = open(_PATH_INITLOG, O_WRONLY | O_APPEND | O_CREAT, 0644);
if (fd == -1)
dup2(STDIN_FILENO, STDOUT_FILENO);
else if (fd != STDOUT_FILENO) {
dup2(fd, STDOUT_FILENO);
close(fd);
}
dup2(STDOUT_FILENO, STDERR_FILENO);
}
static const char *
@ -638,7 +654,7 @@ single_user(void)
/*
* Start the single user session.
*/
setctty(_PATH_CONSOLE);
open_console();
#ifdef SECURE
/*
@ -798,7 +814,7 @@ run_script(const char *script)
sigaction(SIGTSTP, &sa, (struct sigaction *)0);
sigaction(SIGHUP, &sa, (struct sigaction *)0);
setctty(_PATH_CONSOLE);
open_console();
char _sh[] = "sh";
char _autoboot[] = "autoboot";
@ -1572,7 +1588,7 @@ runshutdown(void)
sigaction(SIGTSTP, &sa, (struct sigaction *)0);
sigaction(SIGHUP, &sa, (struct sigaction *)0);
setctty(_PATH_CONSOLE);
open_console();
char _sh[] = "sh";
char _reboot[] = "reboot";

View File

@ -35,6 +35,7 @@
#include <paths.h>
#define _PATH_INITLOG "/var/log/init.log"
#define _PATH_SLOGGER "/sbin/session_logger"
#define _PATH_RUNCOM "/etc/rc"
#define _PATH_RUNDOWN "/etc/rc.shutdown"