From owner-svn-src-all@FreeBSD.ORG Sun Jan 23 14:22:27 2011 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 25E0F106564A; Sun, 23 Jan 2011 14:22:27 +0000 (UTC) (envelope-from jilles@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 14EC08FC19; Sun, 23 Jan 2011 14:22:27 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id p0NEMQFk057829; Sun, 23 Jan 2011 14:22:26 GMT (envelope-from jilles@svn.freebsd.org) Received: (from jilles@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id p0NEMQjZ057827; Sun, 23 Jan 2011 14:22:26 GMT (envelope-from jilles@svn.freebsd.org) Message-Id: <201101231422.p0NEMQjZ057827@svn.freebsd.org> From: Jilles Tjoelker Date: Sun, 23 Jan 2011 14:22:26 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r217750 - head/sbin/init X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 23 Jan 2011 14:22:27 -0000 Author: jilles Date: Sun Jan 23 14:22:26 2011 New Revision: 217750 URL: http://svn.freebsd.org/changeset/base/217750 Log: init: Only run /etc/rc.shutdown if /etc/rc was run. It does not make sense to shut down daemons that were not started. In particular, this fixes loss of mixer settings when shutting down using shutdown(8), init(8) or ctrl+alt+del from single-user mode. If /etc/rc reboots, /etc/rc.shutdown is not run. Also fix segfaults and other erratic behaviour if init receives SIGHUP or SIGTSTP while in single-user mode. This commit does not attempt to fix any badness with signal handlers (assumption that pointers can be read and written atomically, EINTR race condition). I believe it does not make this badness any worse. Silence on: -arch@ Modified: head/sbin/init/init.c Modified: head/sbin/init/init.c ============================================================================== --- head/sbin/init/init.c Sun Jan 23 14:08:59 2011 (r217749) +++ head/sbin/init/init.c Sun Jan 23 14:22:26 2011 (r217750) @@ -122,6 +122,7 @@ static state_func_t multi_user(void); static state_func_t clean_ttys(void); static state_func_t catatonia(void); static state_func_t death(void); +static state_func_t death_single(void); static state_func_t run_script(const char *); @@ -136,6 +137,7 @@ int devfs; static void transition(state_t); static state_t requested_transition; +static state_t current_state = death_single; static void setctty(const char *); static const char *get_shell(void); @@ -559,8 +561,9 @@ static void transition(state_t s) { + current_state = s; for (;;) - s = (state_t) (*s)(); + current_state = (state_t) (*current_state)(); } /* @@ -796,7 +799,7 @@ runcom(void) * Returns 0 on success, otherwise the next transition to enter: * - single_user if fork/execv/waitpid failed, or if the script * terminated with a signal or exit code != 0. - * - death if a SIGTERM was delivered to init(8). + * - death_single if a SIGTERM was delivered to init(8). */ static state_func_t run_script(const char *script) @@ -852,8 +855,8 @@ run_script(const char *script) if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1) collect_child(wpid); if (wpid == -1) { - if (requested_transition == death) - return (state_func_t) death; + if (requested_transition == death_single) + return (state_func_t) death_single; if (errno == EINTR) continue; warning("wait for %s on %s failed: %m; going to " @@ -1306,7 +1309,9 @@ transition_handler(int sig) switch (sig) { case SIGHUP: - requested_transition = clean_ttys; + if (current_state == read_ttys || current_state == multi_user || + current_state == clean_ttys || current_state == catatonia) + requested_transition = clean_ttys; break; case SIGUSR2: howto = RB_POWEROFF; @@ -1315,10 +1320,17 @@ transition_handler(int sig) case SIGINT: Reboot = TRUE; case SIGTERM: - requested_transition = death; + if (current_state == read_ttys || current_state == multi_user || + current_state == clean_ttys || current_state == catatonia) + requested_transition = death; + else + requested_transition = death_single; break; case SIGTSTP: - requested_transition = catatonia; + if (current_state == runcom || current_state == read_ttys || + current_state == clean_ttys || + current_state == multi_user || current_state == catatonia) + requested_transition = catatonia; break; default: requested_transition = 0; @@ -1494,9 +1506,6 @@ death(void) { struct utmpx utx; session_t *sp; - int i; - pid_t pid; - static const int death_sigs[2] = { SIGTERM, SIGKILL }; /* NB: should send a message to the session logger to avoid blocking. */ utx.ut_type = SHUTDOWN_TIME; @@ -1518,6 +1527,22 @@ death(void) /* Try to run the rc.shutdown script within a period of time */ runshutdown(); + return (state_func_t) death_single; +} + +/* + * Do what is necessary to reinitialize single user mode or reboot + * from an incomplete state. + */ +static state_func_t +death_single(void) +{ + int i; + pid_t pid; + static const int death_sigs[2] = { SIGTERM, SIGKILL }; + + revoke(_PATH_CONSOLE); + for (i = 0; i < 2; ++i) { if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH) return (state_func_t) single_user;