[systemd-commits] 14 commits - Makefile.am src/condition.c src/dbus-manager.c src/main.c src/manager.c src/manager.h src/service.c src/shutdown.c src/special.h src/systemctl.c src/systemd-interfaces.vala src/umount.c units/.gitignore units/kexec.service.in units/kexec.target units/session

Lennart Poettering lennart at kemper.freedesktop.org
Wed Oct 13 15:58:04 PDT 2010


 Makefile.am                   |    8 +++-
 src/condition.c               |    2 -
 src/dbus-manager.c            |   52 ++++++++++++++++++++++++++++++++
 src/main.c                    |   29 +++++++++++++++++
 src/manager.c                 |   33 ++++++++++++++++----
 src/manager.h                 |    6 +++
 src/service.c                 |    2 -
 src/shutdown.c                |   47 ++++++++++++-----------------
 src/special.h                 |    3 +
 src/systemctl.c               |   48 ++++++++++++++++++++++-------
 src/systemd-interfaces.vala   |    4 ++
 src/umount.c                  |   68 ++++++++++++++++++++++--------------------
 units/.gitignore              |    1 
 units/kexec.service.in        |   16 +++++++++
 units/kexec.target            |   18 +++++++++++
 units/session/exit.service.in |   13 ++++++--
 units/session/exit.target     |   18 +++++++++++
 17 files changed, 285 insertions(+), 83 deletions(-)

New commits:
commit 85ed27f699939f75b8422ae67e016bdf9f439da9
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Oct 14 00:57:52 2010 +0200

    units: introduce kexec.service, kexec.target and exit.target

diff --git a/Makefile.am b/Makefile.am
index e432dcb..b15cb12 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -162,6 +162,7 @@ dist_systemunit_DATA = \
 	units/basic.target \
 	units/getty.target \
 	units/halt.target \
+	units/kexec.target \
 	units/local-fs.target \
 	units/network.target \
 	units/nss-lookup.target \
@@ -229,10 +230,12 @@ nodist_systemunit_DATA = \
 	units/systemd-readahead-done.service \
 	units/systemd-tmpfiles.service \
 	units/systemd-user-sessions.service \
-	units/syslog.target
+	units/syslog.target \
+	units/kexec.service
 
 dist_sessionunit_DATA = \
-	units/session/default.target
+	units/session/default.target \
+	units/session/exit.target
 
 nodist_sessionunit_DATA = \
 	units/session/remote-fs.target \
@@ -262,6 +265,7 @@ EXTRA_DIST = \
 	units/systemd-tmpfiles.service.in \
 	units/systemd-user-sessions.service.in \
 	units/syslog.target.in \
+	units/kexec.service.in \
 	units/session/exit.service.in \
 	systemd.pc.in
 
diff --git a/units/.gitignore b/units/.gitignore
index 00a40d4..83fc32c 100644
--- a/units/.gitignore
+++ b/units/.gitignore
@@ -1,3 +1,4 @@
+kexec.service
 systemd-user-sessions.service
 systemd-readahead-done.service
 systemd-tmpfiles.service
diff --git a/units/kexec.service.in b/units/kexec.service.in
new file mode 100644
index 0000000..70ad227
--- /dev/null
+++ b/units/kexec.service.in
@@ -0,0 +1,16 @@
+#  This file is part of systemd.
+#
+#  systemd 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 of the License, or
+#  (at your option) any later version.
+
+[Unit]
+Description=Reboot via kexec
+DefaultDependencies=no
+Requires=shutdown.target umount.target
+After=shutdown.target umount.target
+
+[Service]
+Type=oneshot
+ExecStart=@SYSTEMCTL@ --force kexec
diff --git a/units/kexec.target b/units/kexec.target
new file mode 100644
index 0000000..b77e6a4
--- /dev/null
+++ b/units/kexec.target
@@ -0,0 +1,18 @@
+#  This file is part of systemd.
+#
+#  systemd 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 of the License, or
+#  (at your option) any later version.
+
+# See systemd.special(7) for details
+
+[Unit]
+Description=Reboot via kexec
+DefaultDependencies=no
+Requires=kexec.service
+After=kexec.service
+AllowIsolate=yes
+
+[Install]
+Alias=ctrl-alt-del.target
diff --git a/units/session/exit.service.in b/units/session/exit.service.in
index d098d0d..024fbe1 100644
--- a/units/session/exit.service.in
+++ b/units/session/exit.service.in
@@ -1,9 +1,18 @@
+#  This file is part of systemd.
+#
+#  systemd 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 of the License, or
+#  (at your option) any later version.
+
+# See systemd.special(7) for details
+
 [Unit]
-Description=Exit
+Description=Exit the Session
 DefaultDependencies=no
 Requires=shutdown.target
 After=shutdown.target
 
 [Service]
 Type=oneshot
-ExecStart=@SYSTEMCTL@ --session daemon-exit
+ExecStart=@SYSTEMCTL@ --session --force exit
diff --git a/units/session/exit.target b/units/session/exit.target
new file mode 100644
index 0000000..f34844c
--- /dev/null
+++ b/units/session/exit.target
@@ -0,0 +1,18 @@
+#  This file is part of systemd.
+#
+#  systemd 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 of the License, or
+#  (at your option) any later version.
+
+# See systemd.special(7) for details
+
+[Unit]
+Description=Exit the Session
+DefaultDependencies=no
+Requires=exit.service
+After=exit.service
+AllowIsolate=yes
+
+[Install]
+Alias=ctrl-alt-del.target
commit bec9996d6aab890f82fb58a470fe6cf37cbaf40d
Author: Fabiano Fidencio <fidencio at profusion.mobi>
Date:   Thu Oct 14 00:56:50 2010 +0200

    vala: register new D-Bus calls

diff --git a/src/systemd-interfaces.vala b/src/systemd-interfaces.vala
index b7229ce..1d202e0 100644
--- a/src/systemd-interfaces.vala
+++ b/src/systemd-interfaces.vala
@@ -74,6 +74,10 @@ public interface Manager : DBus.Object {
         public abstract void reload() throws DBus.Error;
         public abstract void reexecute() throws DBus.Error;
         public abstract void exit() throws DBus.Error;
+        public abstract void halt() throws DBus.Error;
+        public abstract void power_off() throws DBus.Error;
+        public abstract void reboot() throws DBus.Error;
+        public abstract void kexec() throws DBus.Error;
 
         public abstract ObjectPath create_snapshot(string name = "", bool cleanup = false) throws DBus.Error;
 
commit 20b09ca7fd4bf2be665951dbf908dc41c6fc903d
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Oct 14 00:56:12 2010 +0200

    systemctl: rework halt/reboot/poweroff/kexec/exit logic around --force

diff --git a/src/systemctl.c b/src/systemctl.c
index 671745b..ffb4f73 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -81,6 +81,8 @@ static enum action {
         ACTION_HALT,
         ACTION_POWEROFF,
         ACTION_REBOOT,
+        ACTION_KEXEC,
+        ACTION_EXIT,
         ACTION_RUNLEVEL2,
         ACTION_RUNLEVEL3,
         ACTION_RUNLEVEL4,
@@ -193,6 +195,7 @@ static void warn_wall(enum action action) {
                 [ACTION_HALT]      = "The system is going down for system halt NOW!",
                 [ACTION_REBOOT]    = "The system is going down for reboot NOW!",
                 [ACTION_POWEROFF]  = "The system is going down for power-off NOW!",
+                [ACTION_KEXEC]     = "The system is going down for kexec reboot NOW!",
                 [ACTION_RESCUE]    = "The system is going down to rescue mode NOW!",
                 [ACTION_EMERGENCY] = "The system is going down to emergency mode NOW!"
         };
@@ -1220,12 +1223,16 @@ static enum action verb_to_action(const char *verb) {
                 return ACTION_POWEROFF;
         else if (streq(verb, "reboot"))
                 return ACTION_REBOOT;
+        else if (streq(verb, "kexec"))
+                return ACTION_KEXEC;
         else if (streq(verb, "rescue"))
                 return ACTION_RESCUE;
         else if (streq(verb, "emergency"))
                 return ACTION_EMERGENCY;
         else if (streq(verb, "default"))
                 return ACTION_DEFAULT;
+        else if (streq(verb, "exit"))
+                return ACTION_EXIT;
         else
                 return ACTION_INVALID;
 }
@@ -1236,13 +1243,15 @@ static int start_unit(DBusConnection *bus, char **args, unsigned n) {
                 [ACTION_HALT] = SPECIAL_HALT_TARGET,
                 [ACTION_POWEROFF] = SPECIAL_POWEROFF_TARGET,
                 [ACTION_REBOOT] = SPECIAL_REBOOT_TARGET,
+                [ACTION_KEXEC] = SPECIAL_KEXEC_TARGET,
                 [ACTION_RUNLEVEL2] = SPECIAL_RUNLEVEL2_TARGET,
                 [ACTION_RUNLEVEL3] = SPECIAL_RUNLEVEL3_TARGET,
                 [ACTION_RUNLEVEL4] = SPECIAL_RUNLEVEL4_TARGET,
                 [ACTION_RUNLEVEL5] = SPECIAL_RUNLEVEL5_TARGET,
                 [ACTION_RESCUE] = SPECIAL_RESCUE_TARGET,
                 [ACTION_EMERGENCY] = SPECIAL_EMERGENCY_TARGET,
-                [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET
+                [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET,
+                [ACTION_EXIT] = SPECIAL_EXIT_TARGET
         };
 
         int r, ret = 0;
@@ -1337,6 +1346,14 @@ static int start_special(DBusConnection *bus, char **args, unsigned n) {
         assert(bus);
         assert(args);
 
+        if (arg_force &&
+            (streq(args[0], "halt") ||
+             streq(args[0], "poweroff") ||
+             streq(args[0], "reboot") ||
+             streq(args[0], "kexec") ||
+             streq(args[0], "exit")))
+                return daemon_reload(bus, args, n);
+
         r = start_unit(bus, args, n);
 
         if (r >= 0)
@@ -2968,12 +2985,16 @@ static int daemon_reload(DBusConnection *bus, char **args, unsigned n) {
                 assert(arg_action == ACTION_SYSTEMCTL);
 
                 method =
-                        streq(args[0], "clear-jobs")        ||
-                        streq(args[0], "cancel")            ? "ClearJobs" :
-                        streq(args[0], "daemon-reexec")     ? "Reexecute" :
-                        streq(args[0], "reset-failed")      ? "ResetFailed" :
-                        streq(args[0], "daemon-exit")       ? "Exit" :
-                                                              "Reload";
+                        streq(args[0], "clear-jobs")    ||
+                        streq(args[0], "cancel")        ? "ClearJobs" :
+                        streq(args[0], "daemon-reexec") ? "Reexecute" :
+                        streq(args[0], "reset-failed")  ? "ResetFailed" :
+                        streq(args[0], "halt")          ? "Halt" :
+                        streq(args[0], "poweroff")      ? "PowerOff" :
+                        streq(args[0], "reboot")        ? "Reboot" :
+                        streq(args[0], "kexec")         ? "KExec" :
+                        streq(args[0], "exit")          ? "Exit" :
+                                    /* "daemon-reload" */ "Reload";
         }
 
         if (!(m = dbus_message_new_method_call(
@@ -3919,6 +3940,7 @@ static int systemctl_help(void) {
                "     --no-reload     When enabling/disabling unit files, don't reload daemon\n"
                "                     configuration\n"
                "     --force         When enabling unit files, override existing symlinks\n"
+               "                     When shutting down, execute action immediately\n"
                "     --defaults      When disabling unit files, remove default symlinks only\n\n"
                "Commands:\n"
                "  list-units                      List units\n"
@@ -3951,16 +3973,17 @@ static int systemctl_help(void) {
                "  delete [NAME...]                Remove one or more snapshots\n"
                "  daemon-reload                   Reload systemd manager configuration\n"
                "  daemon-reexec                   Reexecute systemd manager\n"
-               "  daemon-exit                     Ask the systemd manager to quit\n"
                "  show-environment                Dump environment\n"
                "  set-environment [NAME=VALUE...] Set one or more environment variables\n"
                "  unset-environment [NAME...]     Unset one or more environment variables\n"
+               "  default                         Enter system default mode\n"
+               "  rescue                          Enter system rescue mode\n"
+               "  emergency                       Enter system emergency mode\n"
                "  halt                            Shut down and halt the system\n"
                "  poweroff                        Shut down and power-off the system\n"
                "  reboot                          Shut down and reboot the system\n"
-               "  rescue                          Enter system rescue mode\n"
-               "  emergency                       Enter system emergency mode\n"
-               "  default                         Enter system default mode\n",
+               "  kexec                           Shut down and reboot the system with kexec\n"
+               "  exit                            Ask for session termination\n",
                program_invocation_short_name);
 
         return 0;
@@ -4772,16 +4795,17 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
                 { "delete",                MORE,  2, delete_snapshot   },
                 { "daemon-reload",         EQUAL, 1, daemon_reload     },
                 { "daemon-reexec",         EQUAL, 1, daemon_reload     },
-                { "daemon-exit",           EQUAL, 1, daemon_reload     },
                 { "show-environment",      EQUAL, 1, show_enviroment   },
                 { "set-environment",       MORE,  2, set_environment   },
                 { "unset-environment",     MORE,  2, set_environment   },
                 { "halt",                  EQUAL, 1, start_special     },
                 { "poweroff",              EQUAL, 1, start_special     },
                 { "reboot",                EQUAL, 1, start_special     },
+                { "kexec",                 EQUAL, 1, start_special     },
                 { "default",               EQUAL, 1, start_special     },
                 { "rescue",                EQUAL, 1, start_special     },
                 { "emergency",             EQUAL, 1, start_special     },
+                { "exit",                  EQUAL, 1, start_special     },
                 { "reset-failed",          MORE,  1, reset_failed      },
                 { "enable",                MORE,  2, enable_unit       },
                 { "disable",               MORE,  2, enable_unit       },
commit 0003d1ab75f82dd6aa143582c5bd815b3b8f65e8
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Oct 14 00:54:48 2010 +0200

    manager: hookup shutdown helper and signals

diff --git a/src/manager.c b/src/manager.c
index 1fe8936..f2ec2b7 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -164,11 +164,16 @@ static int manager_setup_signals(Manager *m) {
                         SIGWINCH,    /* Kernel sends us this on kbrequest (alt-arrowup) */
                         SIGPWR,      /* Some kernel drivers and upsd send us this on power failure */
                         SIGRTMIN+0,  /* systemd: start default.target */
-                        SIGRTMIN+1,  /* systemd: start rescue.target */
+                        SIGRTMIN+1,  /* systemd: isolate rescue.target */
                         SIGRTMIN+2,  /* systemd: isolate emergency.target */
                         SIGRTMIN+3,  /* systemd: start halt.target */
                         SIGRTMIN+4,  /* systemd: start poweroff.target */
                         SIGRTMIN+5,  /* systemd: start reboot.target */
+                        SIGRTMIN+6,  /* systemd: start kexec.target */
+                        SIGRTMIN+13, /* systemd: Immediate halt */
+                        SIGRTMIN+14, /* systemd: Immediate poweroff */
+                        SIGRTMIN+15, /* systemd: Immediate reboot */
+                        SIGRTMIN+16, /* systemd: Immediate kexec */
                         -1);
         assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
 
@@ -1987,7 +1992,7 @@ static int manager_process_signal_fd(Manager *m) {
                         }
 
                         /* Run the exit target if there is one, if not, just exit. */
-                        if (manager_start_target(m, SPECIAL_EXIT_SERVICE, JOB_REPLACE) < 0) {
+                        if (manager_start_target(m, SPECIAL_EXIT_TARGET, JOB_REPLACE) < 0) {
                                 m->exit_code = MANAGER_EXIT;
                                 return 0;
                         }
@@ -2058,22 +2063,38 @@ static int manager_process_signal_fd(Manager *m) {
                         break;
 
                 default: {
-                        static const char * const table[] = {
+                        /* Starting SIGRTMIN+0 */
+                        static const char * const target_table[] = {
                                 [0] = SPECIAL_DEFAULT_TARGET,
                                 [1] = SPECIAL_RESCUE_TARGET,
                                 [2] = SPECIAL_EMERGENCY_TARGET,
                                 [3] = SPECIAL_HALT_TARGET,
                                 [4] = SPECIAL_POWEROFF_TARGET,
-                                [5] = SPECIAL_REBOOT_TARGET
+                                [5] = SPECIAL_REBOOT_TARGET,
+                                [6] = SPECIAL_KEXEC_TARGET
+                        };
+
+                        /* Starting SIGRTMIN+13, so that target halt and system halt are 10 apart */
+                        static const ManagerExitCode code_table[] = {
+                                [0] = MANAGER_HALT,
+                                [1] = MANAGER_POWEROFF,
+                                [2] = MANAGER_REBOOT,
+                                [3] = MANAGER_KEXEC
                         };
 
                         if ((int) sfsi.ssi_signo >= SIGRTMIN+0 &&
-                            (int) sfsi.ssi_signo < SIGRTMIN+(int) ELEMENTSOF(table)) {
-                                manager_start_target(m, table[sfsi.ssi_signo - SIGRTMIN],
+                            (int) sfsi.ssi_signo < SIGRTMIN+(int) ELEMENTSOF(target_table)) {
+                                manager_start_target(m, target_table[sfsi.ssi_signo - SIGRTMIN],
                                                      (sfsi.ssi_signo == 1 || sfsi.ssi_signo == 2) ? JOB_ISOLATE : JOB_REPLACE);
                                 break;
                         }
 
+                        if ((int) sfsi.ssi_signo >= SIGRTMIN+13 &&
+                            (int) sfsi.ssi_signo < SIGRTMIN+13+(int) ELEMENTSOF(code_table)) {
+                                m->exit_code = code_table[sfsi.ssi_signo - SIGRTMIN - 13];
+                                break;
+                        }
+
                         log_warning("Got unhandled signal <%s>.", strna(signal_to_string(sfsi.ssi_signo)));
                 }
                 }
diff --git a/src/service.c b/src/service.c
index 310aa28..3ebe60e 100644
--- a/src/service.c
+++ b/src/service.c
@@ -316,7 +316,7 @@ static int sysv_translate_facility(const char *name, const char *filename, char
         }
 
         /* If we don't know this name, fallback heuristics to figure
-         * out whether something is a target or an service alias. */
+         * out whether something is a target or a service alias. */
 
         if (*name == '$')
                 /* Facilities starting with $ are most likely targets */
diff --git a/src/special.h b/src/special.h
index ca24121..0b37353 100644
--- a/src/special.h
+++ b/src/special.h
@@ -54,11 +54,12 @@
 #define SPECIAL_SYSINIT_TARGET "sysinit.target"
 #define SPECIAL_FSCK_TARGET "fsck.target"
 #define SPECIAL_RESCUE_TARGET "rescue.target"
-#define SPECIAL_EXIT_SERVICE "exit.service"
+#define SPECIAL_EXIT_TARGET "exit.target"
 #define SPECIAL_EMERGENCY_TARGET "emergency.target"
 #define SPECIAL_HALT_TARGET "halt.target"
 #define SPECIAL_POWEROFF_TARGET "poweroff.target"
 #define SPECIAL_REBOOT_TARGET "reboot.target"
+#define SPECIAL_KEXEC_TARGET "kexec.target"
 #define SPECIAL_DBUS_SERVICE "dbus.service"
 #define SPECIAL_DBUS_SOCKET "dbus.socket"
 #define SPECIAL_GETTY_TARGET "getty.target"
commit 6652a2b9e5f837e8a7e6b0c7b890e5d0e7d85794
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Oct 14 00:53:51 2010 +0200

    dbus: expose shutdown helper via D-Bus

diff --git a/src/dbus-manager.c b/src/dbus-manager.c
index 3754a0c..c700abb 100644
--- a/src/dbus-manager.c
+++ b/src/dbus-manager.c
@@ -104,6 +104,10 @@
         "  <method name=\"Reload\"/>\n"                                 \
         "  <method name=\"Reexecute\"/>\n"                              \
         "  <method name=\"Exit\"/>\n"                                   \
+        "  <method name=\"Reboot\"/>\n"                                 \
+        "  <method name=\"PowerOff\"/>\n"                               \
+        "  <method name=\"Halt\"/>\n"                                   \
+        "  <method name=\"KExec\"/>\n"                                  \
         "  <method name=\"SetEnvironment\">\n"                          \
         "   <arg name=\"names\" type=\"as\" direction=\"in\"/>\n"       \
         "  </method>\n"                                                 \
@@ -808,6 +812,54 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
 
                 m->exit_code = MANAGER_EXIT;
 
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) {
+
+                if (m->running_as != MANAGER_SYSTEM) {
+                        dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
+                        return bus_send_error_reply(m, connection, message, &error, -ENOTSUP);
+                }
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+                m->exit_code = MANAGER_REBOOT;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
+
+                if (m->running_as != MANAGER_SYSTEM) {
+                        dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
+                        return bus_send_error_reply(m, connection, message, &error, -ENOTSUP);
+                }
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+                m->exit_code = MANAGER_POWEROFF;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
+
+                if (m->running_as != MANAGER_SYSTEM) {
+                        dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
+                        return bus_send_error_reply(m, connection, message, &error, -ENOTSUP);
+                }
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+                m->exit_code = MANAGER_HALT;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
+
+                if (m->running_as != MANAGER_SYSTEM) {
+                        dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
+                        return bus_send_error_reply(m, connection, message, &error, -ENOTSUP);
+                }
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+                m->exit_code = MANAGER_KEXEC;
+
         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
                 char **l = NULL, **e = NULL;
 
commit b9080b03a98252ccccb332d0c892403b8b841916
Author: Fabiano Fidencio <fidencio at profusion.mobi>
Date:   Thu Oct 14 00:52:26 2010 +0200

    manager: hookup execution of systemd-shutdown helper
    
    (Modified by Lennart Poettering)

diff --git a/src/main.c b/src/main.c
index 15bd2e4..88ba09d 100644
--- a/src/main.c
+++ b/src/main.c
@@ -889,6 +889,7 @@ int main(int argc, char *argv[]) {
         int r, retval = EXIT_FAILURE;
         FDSet *fds = NULL;
         bool reexecute = false;
+        const char *shutdown_verb = NULL;
 
         if (getpid() != 1 && strstr(program_invocation_short_name, "init")) {
                 /* This is compatbility support for SysV, where
@@ -1127,6 +1128,23 @@ int main(int argc, char *argv[]) {
                         log_notice("Reexecuting.");
                         goto finish;
 
+                case MANAGER_REBOOT:
+                case MANAGER_POWEROFF:
+                case MANAGER_HALT:
+                case MANAGER_KEXEC: {
+                        static const char * const table[_MANAGER_EXIT_CODE_MAX] = {
+                                [MANAGER_REBOOT] = "reboot",
+                                [MANAGER_POWEROFF] = "poweroff",
+                                [MANAGER_HALT] = "halt",
+                                [MANAGER_KEXEC] = "kexec"
+                        };
+
+                        assert_se(shutdown_verb = table[m->exit_code]);
+
+                        log_notice("Shutting down.");
+                        goto finish;
+                }
+
                 default:
                         assert_not_reached("Unknown exit code.");
                 }
@@ -1206,6 +1224,17 @@ finish:
         if (fds)
                 fdset_free(fds);
 
+        if (shutdown_verb) {
+                const char * command_line[] = {
+                        SYSTEMD_SHUTDOWN_BINARY_PATH,
+                        shutdown_verb,
+                        NULL
+                };
+
+                execv(SYSTEMD_SHUTDOWN_BINARY_PATH, (char **) command_line);
+                log_error("Failed to execute shutdown binary, freezing: %m");
+        }
+
         if (getpid() == 1)
                 freeze();
 
diff --git a/src/manager.h b/src/manager.h
index 15ffb2c..a573deb 100644
--- a/src/manager.h
+++ b/src/manager.h
@@ -41,6 +41,10 @@ typedef enum ManagerExitCode {
         MANAGER_EXIT,
         MANAGER_RELOAD,
         MANAGER_REEXECUTE,
+        MANAGER_REBOOT,
+        MANAGER_POWEROFF,
+        MANAGER_HALT,
+        MANAGER_KEXEC,
         _MANAGER_EXIT_CODE_MAX,
         _MANAGER_EXIT_CODE_INVALID = -1
 } ManagerExitCode;
@@ -197,7 +201,7 @@ struct Manager {
 
         /* Flags */
         ManagerRunningAs running_as;
-        ManagerExitCode exit_code:4;
+        ManagerExitCode exit_code:5;
 
         bool dispatching_load_queue:1;
         bool dispatching_run_queue:1;
commit e61cd18666de1c26d41b4f189c8fac8a0bf8ee61
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Oct 14 00:50:11 2010 +0200

    shutdown: make use of wait_for_terminate_and_warn()

diff --git a/src/shutdown.c b/src/shutdown.c
index 43165fe..176327b 100644
--- a/src/shutdown.c
+++ b/src/shutdown.c
@@ -307,28 +307,29 @@ int main(int argc, char *argv[]) {
         if (cmd == LINUX_REBOOT_CMD_KEXEC) {
                 /* we cheat and exec kexec to avoid doing all its work */
                 pid_t pid = fork();
-                if (pid < 0) {
-                        log_error("Could not fork: %m. Falling back to reboot.");
-                        cmd = RB_AUTOBOOT;
-                } else if (pid > 0) {
-                        waitpid(pid, NULL, 0);
-                        log_warning("Failed %s -e -x -f. Falling back to reboot", KEXEC_BINARY_PATH);
-                        cmd = RB_AUTOBOOT;
+                if (pid < 0)
+                        log_error("Could not fork: %m. Falling back to normal reboot.");
+                else if (pid > 0) {
+                        wait_for_terminate_and_warn("kexec", pid);
+                        log_warning("kexec failed. Falling back to normal reboot.");
                 } else {
-                        const char *args[5] = {KEXEC_BINARY_PATH, "-e", "-f", "-x", NULL};
+                        /* Child */
+                        const char *args[5] = { KEXEC_BINARY_PATH, "-e", "-f", "-x", NULL };
                         execv(args[0], (char * const *) args);
                         return EXIT_FAILURE;
                 }
+
+                cmd = RB_AUTOBOOT;
         }
 
         reboot(cmd);
-        r = errno;
+        log_error("Failed to invoke reboot(): %m");
+        r = -errno;
 
   error:
         sync();
-        if (r < 0)
-                r = -r;
-        log_error("Critical error while doing system shutdown: %s", strerror(r));
+        log_error("Critical error while doing system shutdown: %s", strerror(-r));
+
         freeze();
         return EXIT_FAILURE;
 }
commit d37fb98bbcf85115a03664437ae02aa95f6af4bc
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Oct 14 00:49:53 2010 +0200

    shutdown: execute rescue kill only once

diff --git a/src/shutdown.c b/src/shutdown.c
index 3c9a531..43165fe 100644
--- a/src/shutdown.c
+++ b/src/shutdown.c
@@ -286,18 +286,18 @@ int main(int argc, char *argv[]) {
                 if (need_umount || need_swapoff || need_loop_detach) {
                         retries--;
 
-                        if (retries <= FINALIZE_CRITICAL_ATTEMPTS) {
+                        if (retries == FINALIZE_CRITICAL_ATTEMPTS) {
                                 log_warning("Approaching critical level to finalize filesystem and devices, try to kill all processes.");
                                 rescue_send_signal(SIGTERM);
                                 rescue_send_signal(SIGKILL);
                         }
 
                         if (retries > 0)
-                                log_info("Action still required, %d tries left", retries);
+                                log_info("Action still required, %d tries left.", retries);
                         else {
-                                log_error("Tried enough but still action required need_umount=%d, need_swapoff=%d, need_loop_detach=%d", need_umount, need_swapoff, need_loop_detach);
-                                r = -EBUSY;
-                                goto error;
+                                log_error("Giving up. Actions left: Umount=%s, Swap off=%s, Loop detach=%s",
+                                          yes_no(need_umount), yes_no(need_swapoff), yes_no(need_loop_detach));
+                                break;
                         }
                 }
         }
commit 567ea02a89b358090032c8d1ec89286db07ab2ff
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Oct 14 00:49:22 2010 +0200

    shutdown: don't chdir to /, since init is running with / as cwd anyway

diff --git a/src/shutdown.c b/src/shutdown.c
index b78c741..3c9a531 100644
--- a/src/shutdown.c
+++ b/src/shutdown.c
@@ -36,7 +36,7 @@
 #include "umount.h"
 #include "util.h"
 
-#define TIMEOUT_USEC    (5 * USEC_PER_SEC)
+#define TIMEOUT_USEC (5 * USEC_PER_SEC)
 #define FINALIZE_ATTEMPTS 50
 #define FINALIZE_CRITICAL_ATTEMPTS 10
 
@@ -198,7 +198,6 @@ finish:
         return r;
 }
 
-
 int main(int argc, char *argv[]) {
         int cmd, r, retries;
         bool need_umount = true, need_swapoff = true, need_loop_detach = true;
@@ -208,7 +207,7 @@ int main(int argc, char *argv[]) {
         log_open();
 
         if (getpid() != 1) {
-                log_error("Not executed by init (pid-1).");
+                log_error("Not executed by init (pid 1).");
                 r = -EPERM;
                 goto error;
         }
@@ -247,12 +246,7 @@ int main(int argc, char *argv[]) {
         if (r < 0)
                 log_warning("Cannot send SIGKILL to all process: %s", strerror(r));
 
-
-        /* preventing that we won't block umounts */
-        if (chdir("/") != 0)
-                log_warning("Cannot chdir(\"/\"): %m. Unmounts likely to fail.");
-
-        /* umount all mountpoints, swaps, and loopback devices */
+        /* Unmount all mountpoints, swaps, and loopback devices */
         retries = FINALIZE_ATTEMPTS;
         while (need_umount || need_swapoff || need_loop_detach) {
                 if (need_umount) {
commit 7e23b34c7da85e24c92e984f1d99eead3e9817f5
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Oct 14 00:43:35 2010 +0200

    umount: be a bit more verbose when unable to umount/unswap/delete loopbacks

diff --git a/src/umount.c b/src/umount.c
index ff1296f..44bed61 100644
--- a/src/umount.c
+++ b/src/umount.c
@@ -293,7 +293,7 @@ static int mount_points_list_umount(MountPoint **mount_point_list_head) {
                 if (umount2(mp->path, MNT_FORCE) == 0)
                         mount_point_remove_and_free(mp, mount_point_list_head);
                 else {
-                        log_debug("Could not unmount %s: %m", mp->path);
+                        log_warning("Could not unmount %s: %m", mp->path);
                         failed++;
                 }
         }
@@ -310,7 +310,7 @@ static int mount_points_list_remount_read_only(MountPoint **mount_point_list_hea
                 if (mount(NULL, mp->path, NULL, MS_MGC_VAL|MS_REMOUNT|MS_RDONLY, NULL) == 0)
                         mount_point_remove_and_free(mp, mount_point_list_head);
                 else {
-                        log_debug("Could not remount as read-only %s: %m", mp->path);
+                        log_warning("Could not remount as read-only %s: %m", mp->path);
                         failed++;
                 }
         }
@@ -326,7 +326,7 @@ static int swap_points_list_off(MountPoint **swap_list_head) {
                 if (swapoff(swap->path) == 0)
                         mount_point_remove_and_free(swap, swap_list_head);
                 else {
-                        log_debug("Could not swapoff %s: %m", swap->path);
+                        log_warning("Could not deactivate swap %s: %m", swap->path);
                         failed++;
                 }
         }
@@ -342,7 +342,7 @@ static int loopback_points_list_detach(MountPoint **loopback_list_head) {
                 if (delete_loopback(loopback->path) == 0)
                         mount_point_remove_and_free(loopback, loopback_list_head);
                 else {
-                        log_debug("Could not delete loopback %s: %m", loopback->path);
+                        log_warning("Could not delete loopback %s: %m", loopback->path);
                         failed++;
                 }
         }
commit ce726252a9a9487a694cbd68f4d13542ba965258
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Oct 14 00:43:13 2010 +0200

    umount: simplify code for deactivating loop devices

diff --git a/src/umount.c b/src/umount.c
index bd4f01f..ff1296f 100644
--- a/src/umount.c
+++ b/src/umount.c
@@ -271,23 +271,14 @@ finish:
 static int delete_loopback(const char *device) {
         int fd, r;
 
-        if ((fd = open(device, O_RDONLY|O_CLOEXEC)) < 0) {
-                if (errno == ENOENT) {
-                        log_debug("Loop device %s does not exist.", device);
-                        errno = 0;
-                        return 0;
-                }
+        if ((fd = open(device, O_RDONLY|O_CLOEXEC)) < 0)
                 return -errno;
-        }
 
-        ioctl(fd, LOOP_CLR_FD, 0);
-        r = errno;
+        r = ioctl(fd, LOOP_CLR_FD, 0);
         close_nointr_nofail(fd);
 
-        if (r == ENXIO) /* not bound, so no error */
-                r = 0;
-        errno = r;
-        return -errno;
+        /* ENXIO: not bound, so no error */
+        return (r >= 0 || errno == ENXIO) ? 0 : -errno;
 }
 
 static int mount_points_list_umount(MountPoint **mount_point_list_head) {
commit b854a7e7289e0b136c6a4fa03ad76640c59bcfa0
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Oct 14 00:42:44 2010 +0200

    umount: properly enumerate loopback devices

diff --git a/src/umount.c b/src/umount.c
index 79fbba7..bd4f01f 100644
--- a/src/umount.c
+++ b/src/umount.c
@@ -227,16 +227,27 @@ static int loopback_list_get(MountPoint **loopback_list_head) {
 
         udev_list_entry_foreach(item, first) {
                 MountPoint *lb;
+                struct udev_device *d;
                 char *loop;
+                const char *dn;
 
-                loop = cunescape(udev_list_entry_get_name(item));
-                if (!loop) {
+                if (!(d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)))) {
                         r = -ENOMEM;
                         goto finish;
                 }
 
-                lb = mount_point_alloc(loop);
-                if (!lb) {
+                if ((dn = udev_device_get_devnode(d))) {
+                        loop = strdup(dn);
+                        udev_device_unref(d);
+
+                        if (!loop) {
+                                r = -ENOMEM;
+                                goto finish;
+                        }
+                } else
+                        udev_device_unref(d);
+
+                if (!(lb = mount_point_alloc(loop))) {
                         free(loop);
                         r = -ENOMEM;
                         goto finish;
@@ -251,7 +262,9 @@ finish:
         if (e)
                 udev_enumerate_unref(e);
 
-        free(udev);
+        if (udev)
+                udev_unref(udev);
+
         return r;
 }
 
commit 2054a5b8cb52a66462b7d967ed9a6c179777bc0f
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Oct 14 00:41:57 2010 +0200

    umount: unescape path from /proc/self/mountinfo first, then check against api mount list

diff --git a/src/umount.c b/src/umount.c
index 468eb71..79fbba7 100644
--- a/src/umount.c
+++ b/src/umount.c
@@ -38,6 +38,7 @@ typedef struct MountPoint {
         LIST_FIELDS (struct MountPoint, mount_point);
 } MountPoint;
 
+/* Takes over possession of path */
 static MountPoint *mount_point_alloc(char *path) {
         MountPoint *mp;
 
@@ -98,23 +99,26 @@ static int mount_points_list_get(MountPoint **mount_point_list_head) {
                         continue;
                 }
 
-                if (mount_point_is_api(path)) {
-                        free(path);
-                        continue;
-                }
+                p = cunescape(path);
+                free(path);
 
-                if (!(p = cunescape(path))) {
+                if (!p) {
                         r = -ENOMEM;
                         goto finish;
                 }
 
+                if (mount_point_is_api(p)) {
+                        free(p);
+                        continue;
+                }
+
                 if (!(mp = mount_point_alloc(p))) {
+                        free(p);
                         r = -ENOMEM;
                         goto finish;
                 }
-                LIST_PREPEND(MountPoint, mount_point, *mount_point_list_head, mp);
 
-                free(path);
+                LIST_PREPEND(MountPoint, mount_point, *mount_point_list_head, mp);
         }
 
         r = 0;
@@ -122,8 +126,6 @@ static int mount_points_list_get(MountPoint **mount_point_list_head) {
 finish:
         fclose(proc_self_mountinfo);
 
-        free(path);
-
         return r;
 }
 
commit f23c09b0fdec4a421cc002a38621e5be05ed770b
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Oct 14 00:40:39 2010 +0200

    condition: fix copyright

diff --git a/src/condition.c b/src/condition.c
index 8c2db2d..1e69b61 100644
--- a/src/condition.c
+++ b/src/condition.c
@@ -3,7 +3,7 @@
 /***
   This file is part of systemd.
 
-  Copyright 2010 ProFUSION embedded systems
+  Copyright 2010 Lennart Poettering
 
   systemd is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by


More information about the systemd-commits mailing list