chiark / gitweb /
systemctl: introduce reset-maintenance command
authorLennart Poettering <lennart@poettering.net>
Sun, 18 Jul 2010 02:58:01 +0000 (04:58 +0200)
committerLennart Poettering <lennart@poettering.net>
Mon, 19 Jul 2010 02:08:07 +0000 (04:08 +0200)
18 files changed:
fixme
man/systemctl.xml
man/systemd.xml
src/automount.c
src/dbus-manager.c
src/dbus-unit.c
src/dbus-unit.h
src/manager.c
src/manager.h
src/mount.c
src/path.c
src/service.c
src/socket.c
src/swap.c
src/systemctl.c
src/timer.c
src/unit.c
src/unit.h

diff --git a/fixme b/fixme
index 30cfaac..29e0fde 100644 (file)
--- a/fixme
+++ b/fixme
@@ -47,8 +47,6 @@
 
 * debian deadlock when partition auf noauto is.
 
-* maintenance units müssen vergessen werden
-
 * fingerprint.target, wireless.target, gps.target
 
 * fix merging of device units
@@ -57,6 +55,8 @@
 
 * pahole
 
+* color aus bei stdout auf !tty
+
 External:
 
 * default.target must be %ghosted...
index 42682b7..737bcbe 100644 (file)
                                 properties of the job is
                                 shown.</para></listitem>
                         </varlistentry>
+
+                        <varlistentry>
+                                <term><command>reset-maintenance [NAME...]</command></term>
+
+                                <listitem><para>Reset maintenance
+                                state of the specified units, or if no
+                                unit name is passed of all units. When
+                                a unit fails in some way (i.e. process
+                                exiting with non-zero error code,
+                                terminating abnormally or timing out)
+                                it will automatically enter
+                                maintenance state and its exit codes
+                                and status is recorded for
+                                introspection by the administrator
+                                until the service is restarted or
+                                reset with this
+                                command.</para></listitem>
+                        </varlistentry>
+
                         <varlistentry>
                                 <term><command>load [NAME...]</command></term>
 
index 25f24ce..c027b4f 100644 (file)
                 <para>systemd provides a dependency system between
                 various entities called "units". Units encapsulate
                 various objects that are relevant for system boot-up
-                and maintainance. The majority of units are configured
+                and maintenance. The majority of units are configured
                 in unit configuration files, whose syntax and basic
                 set of options is described in
                 <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
index e685c96..213b178 100644 (file)
@@ -791,6 +791,17 @@ static void automount_shutdown(Manager *m) {
                 close_nointr_nofail(m->dev_autofs_fd);
 }
 
+static void automount_reset_maintenance(Unit *u) {
+        Automount *a = AUTOMOUNT(u);
+
+        assert(a);
+
+        if (a->state == AUTOMOUNT_MAINTENANCE)
+                automount_set_state(a, AUTOMOUNT_DEAD);
+
+        a->failure = false;
+}
+
 static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = {
         [AUTOMOUNT_DEAD] = "dead",
         [AUTOMOUNT_WAITING] = "waiting",
@@ -827,6 +838,8 @@ const UnitVTable automount_vtable = {
 
         .fd_event = automount_fd_event,
 
+        .reset_maintenance = automount_reset_maintenance,
+
         .bus_message_handler = bus_automount_message_handler,
 
         .shutdown = automount_shutdown
index c717ccd..969c430 100644 (file)
         "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
         "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
         "  </method>\n"                                                 \
+        "  <method name=\"ResetMaintenanceUnit\">\n"                    \
+        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
+        "  </method>\n"                                                 \
         "  <method name=\"GetJob\">\n"                                  \
         "   <arg name=\"id\" type=\"u\" direction=\"in\"/>\n"           \
         "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
         "  </method>\n"                                                 \
         "  <method name=\"ClearJobs\"/>\n"                              \
+        "  <method name=\"ResetMaintenance\"/>\n"                       \
         "  <method name=\"ListUnits\">\n"                               \
         "   <arg name=\"units\" type=\"a(sssssouso)\" direction=\"out\"/>\n" \
         "  </method>\n"                                                 \
@@ -362,6 +366,34 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
                 if (!(reply = dbus_message_new_method_return(message)))
                         goto oom;
 
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetMaintenance")) {
+
+                manager_reset_maintenance(m);
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetMaintenanceUnit")) {
+                const char *name;
+                Unit *u;
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    DBUS_TYPE_STRING, &name,
+                                    DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(m, connection, message, &error, -EINVAL);
+
+                if (!(u = manager_get_unit(m, name))) {
+                        dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
+                        return bus_send_error_reply(m, connection, message, &error, -ENOENT);
+                }
+
+                unit_reset_maintenance(u);
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
                 DBusMessageIter iter, sub;
                 Iterator i;
@@ -733,7 +765,6 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
         } else
                 return bus_default_message_handler(m, connection, message, NULL, properties);
 
-
         if (job_type != _JOB_TYPE_INVALID) {
                 const char *name, *smode;
                 JobMode mode;
index ce34130..2dcd032 100644 (file)
@@ -298,6 +298,13 @@ static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *conn
         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "ReloadOrTryRestart")) {
                 reload_if_possible = true;
                 job_type = JOB_TRY_RESTART;
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "ResetMaintenance")) {
+
+                unit_reset_maintenance(u);
+
+                if (!(reply = dbus_message_new_method_return(message)))
+                        goto oom;
+
         } else if (UNIT_VTABLE(u)->bus_message_handler)
                 return UNIT_VTABLE(u)->bus_message_handler(u, connection, message);
         else
index 0b9c62f..e49f82d 100644 (file)
@@ -56,6 +56,7 @@
         "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
         "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
         "  </method>\n"                                                 \
+        "  <method name=\"ResetMaintenance\"/>\n"                       \
         "  <signal name=\"Changed\"/>\n"                                \
         "  <property name=\"Id\" type=\"s\" access=\"read\"/>\n"        \
         "  <property name=\"Names\" type=\"as\" access=\"read\"/>\n"    \
index 7b2586f..8a9b9dd 100644 (file)
@@ -2466,6 +2466,16 @@ bool manager_is_booting_or_shutting_down(Manager *m) {
         return false;
 }
 
+void manager_reset_maintenance(Manager *m) {
+        Unit *u;
+        Iterator i;
+
+        assert(m);
+
+        HASHMAP_FOREACH(u, m->units, i)
+                unit_reset_maintenance(u);
+}
+
 static const char* const manager_running_as_table[_MANAGER_RUNNING_AS_MAX] = {
         [MANAGER_SYSTEM] = "system",
         [MANAGER_SESSION] = "session"
index c492ffa..96de120 100644 (file)
@@ -247,6 +247,8 @@ int manager_reload(Manager *m);
 
 bool manager_is_booting_or_shutting_down(Manager *m);
 
+void manager_reset_maintenance(Manager *m);
+
 const char *manager_running_as_to_string(ManagerRunningAs i);
 ManagerRunningAs manager_running_as_from_string(const char *s);
 
index bee3c9a..c1a1d51 100644 (file)
@@ -1538,6 +1538,17 @@ finish:
         return r;
 }
 
+static void mount_reset_maintenance(Unit *u) {
+        Mount *m = MOUNT(u);
+
+        assert(m);
+
+        if (m->state == MOUNT_MAINTENANCE)
+                mount_set_state(m, MOUNT_DEAD);
+
+        m->failure = false;
+}
+
 static const char* const mount_state_table[_MOUNT_STATE_MAX] = {
         [MOUNT_DEAD] = "dead",
         [MOUNT_MOUNTING] = "mounting",
@@ -1595,6 +1606,8 @@ const UnitVTable mount_vtable = {
         .sigchld_event = mount_sigchld_event,
         .timer_event = mount_timer_event,
 
+        .reset_maintenance = mount_reset_maintenance,
+
         .bus_message_handler = bus_mount_message_handler,
 
         .enumerate = mount_enumerate,
index a9fa377..f4c2094 100644 (file)
@@ -560,6 +560,17 @@ fail:
         log_error("Failed find path unit: %s", strerror(-r));
 }
 
+static void path_reset_maintenance(Unit *u) {
+        Path *p = PATH(u);
+
+        assert(p);
+
+        if (p->state == PATH_MAINTENANCE)
+                path_set_state(p, PATH_DEAD);
+
+        p->failure = false;
+}
+
 static const char* const path_state_table[_PATH_STATE_MAX] = {
         [PATH_DEAD] = "dead",
         [PATH_WAITING] = "waiting",
@@ -598,5 +609,7 @@ const UnitVTable path_vtable = {
 
         .fd_event = path_fd_event,
 
+        .reset_maintenance = path_reset_maintenance,
+
         .bus_message_handler = bus_path_message_handler
 };
index a5d1ebd..6b786d1 100644 (file)
@@ -2734,6 +2734,17 @@ int service_set_socket_fd(Service *s, int fd, Socket *sock) {
         return 0;
 }
 
+static void service_reset_maintenance(Unit *u) {
+        Service *s = SERVICE(u);
+
+        assert(s);
+
+        if (s->state == SERVICE_MAINTENANCE)
+                service_set_state(s, SERVICE_DEAD);
+
+        s->failure = false;
+}
+
 static const char* const service_state_table[_SERVICE_STATE_MAX] = {
         [SERVICE_DEAD] = "dead",
         [SERVICE_START_PRE] = "start-pre",
@@ -2821,6 +2832,8 @@ const UnitVTable service_vtable = {
         .sigchld_event = service_sigchld_event,
         .timer_event = service_timer_event,
 
+        .reset_maintenance = service_reset_maintenance,
+
         .cgroup_notify_empty = service_cgroup_notify_event,
         .notify_message = service_notify_message,
 
index 4cf21cf..2c9d693 100644 (file)
@@ -1698,6 +1698,17 @@ void socket_connection_unref(Socket *s) {
         log_debug("%s: One connection closed, %u left.", s->meta.id, s->n_connections);
 }
 
+static void socket_reset_maintenance(Unit *u) {
+        Socket *s = SOCKET(u);
+
+        assert(s);
+
+        if (s->state == SOCKET_MAINTENANCE)
+                socket_set_state(s, SOCKET_DEAD);
+
+        s->failure = false;
+}
+
 static const char* const socket_state_table[_SOCKET_STATE_MAX] = {
         [SOCKET_DEAD] = "dead",
         [SOCKET_START_PRE] = "start-pre",
@@ -1750,5 +1761,7 @@ const UnitVTable socket_vtable = {
         .sigchld_event = socket_sigchld_event,
         .timer_event = socket_timer_event,
 
+        .reset_maintenance = socket_reset_maintenance,
+
         .bus_message_handler = bus_socket_message_handler
 };
index de468a0..6765a4a 100644 (file)
@@ -542,14 +542,6 @@ static void swap_shutdown(Manager *m) {
         }
 }
 
-static const char* const swap_state_table[_SWAP_STATE_MAX] = {
-        [SWAP_DEAD] = "dead",
-        [SWAP_ACTIVE] = "active",
-        [SWAP_MAINTENANCE] = "maintenance"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState);
-
 static int swap_enumerate(Manager *m) {
         int r;
         assert(m);
@@ -564,6 +556,23 @@ static int swap_enumerate(Manager *m) {
         return r;
 }
 
+static void swap_reset_maintenance(Unit *u) {
+        Swap *s = SWAP(u);
+
+        assert(s);
+
+        if (s->state == SWAP_MAINTENANCE)
+                swap_set_state(s, SWAP_DEAD);
+}
+
+static const char* const swap_state_table[_SWAP_STATE_MAX] = {
+        [SWAP_DEAD] = "dead",
+        [SWAP_ACTIVE] = "active",
+        [SWAP_MAINTENANCE] = "maintenance"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState);
+
 const UnitVTable swap_vtable = {
         .suffix = ".swap",
 
@@ -592,6 +601,8 @@ const UnitVTable swap_vtable = {
 
         .bus_message_handler = bus_swap_message_handler,
 
+        .reset_maintenance = swap_reset_maintenance,
+
         .enumerate = swap_enumerate,
         .shutdown = swap_shutdown
 };
index 06b4cae..acb89a5 100644 (file)
@@ -2639,10 +2639,11 @@ static int clear_jobs(DBusConnection *bus, char **args, unsigned n) {
                 assert(arg_action == ACTION_SYSTEMCTL);
 
                 method =
-                        streq(args[0], "clear-jobs")    ? "ClearJobs" :
-                        streq(args[0], "daemon-reload") ? "Reload" :
-                        streq(args[0], "daemon-reexec") ? "Reexecute" :
-                                                          "Exit";
+                        streq(args[0], "clear-jobs")        ? "ClearJobs" :
+                        streq(args[0], "daemon-reload")     ? "Reload" :
+                        streq(args[0], "daemon-reexec")     ? "Reexecute" :
+                        streq(args[0], "reset-maintenance") ? "ResetMaintenance" :
+                                                              "Exit";
         }
 
         if (!(m = dbus_message_new_method_call(
@@ -2682,6 +2683,63 @@ finish:
         return r;
 }
 
+static int reset_maintenance(DBusConnection *bus, char **args, unsigned n) {
+        DBusMessage *m = NULL, *reply = NULL;
+        unsigned i;
+        int r;
+        DBusError error;
+
+        assert(bus);
+        dbus_error_init(&error);
+
+        if (n <= 1)
+                return clear_jobs(bus, args, n);
+
+        for (i = 1; i < n; i++) {
+
+                if (!(m = dbus_message_new_method_call(
+                                      "org.freedesktop.systemd1",
+                                      "/org/freedesktop/systemd1",
+                                      "org.freedesktop.systemd1.Manager",
+                                      "ResetMaintenanceUnit"))) {
+                        log_error("Could not allocate message.");
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                if (!dbus_message_append_args(m,
+                                              DBUS_TYPE_STRING, args + i,
+                                              DBUS_TYPE_INVALID)) {
+                        log_error("Could not append arguments to message.");
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
+                        log_error("Failed to issue method call: %s", error.message);
+                        r = -EIO;
+                        goto finish;
+                }
+
+                dbus_message_unref(m);
+                dbus_message_unref(reply);
+                m = reply = NULL;
+        }
+
+        r = 0;
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        if (reply)
+                dbus_message_unref(reply);
+
+        dbus_error_free(&error);
+
+        return r;
+}
+
 static int show_enviroment(DBusConnection *bus, char **args, unsigned n) {
         DBusMessage *m = NULL, *reply = NULL;
         DBusError error;
@@ -2832,7 +2890,7 @@ finish:
 static int systemctl_help(void) {
 
         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
-               "Send control commands to the systemd manager.\n\n"
+               "Send control commands to or query the systemd manager.\n\n"
                "  -h --help          Show this help\n"
                "  -t --type=TYPE     List only units of a particular type\n"
                "  -p --property=NAME Show only properties by this name\n"
@@ -2862,6 +2920,8 @@ static int systemctl_help(void) {
                "  status [NAME...]                Show status of one or more units\n"
                "  show [NAME...|JOB...]           Show properties of one or more\n"
                "                                  units/jobs/manager\n"
+               "  reset-maintenance [NAME...]     Reset maintenance state for all, one\n"
+               "                                  or more units\n"
                "  load [NAME...]                  Load one or more units\n"
                "  list-jobs                       List jobs\n"
                "  cancel [JOB...]                 Cancel one or more jobs\n"
@@ -3579,6 +3639,7 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[]) {
                 { "default",           EQUAL, 1, start_special   },
                 { "rescue",            EQUAL, 1, start_special   },
                 { "emergency",         EQUAL, 1, start_special   },
+                { "reset-maintenance", MORE,  1, reset_maintenance },
         };
 
         int left;
index 1580478..cd6728a 100644 (file)
@@ -450,6 +450,17 @@ fail:
         log_error("Failed find timer unit: %s", strerror(-r));
 }
 
+static void timer_reset_maintenance(Unit *u) {
+        Timer *t = TIMER(u);
+
+        assert(t);
+
+        if (t->state == TIMER_MAINTENANCE)
+                timer_set_state(t, TIMER_DEAD);
+
+        t->failure = false;
+}
+
 static const char* const timer_state_table[_TIMER_STATE_MAX] = {
         [TIMER_DEAD] = "dead",
         [TIMER_WAITING] = "waiting",
@@ -492,5 +503,7 @@ const UnitVTable timer_vtable = {
 
         .timer_event = timer_timer_event,
 
+        .reset_maintenance = timer_reset_maintenance,
+
         .bus_message_handler = bus_timer_message_handler
 };
index 348d139..5807e4f 100644 (file)
@@ -2071,6 +2071,13 @@ bool unit_need_daemon_reload(Unit *u) {
                 timespec_load(&st.st_mtim) != u->meta.fragment_mtime;
 }
 
+void unit_reset_maintenance(Unit *u) {
+        assert(u);
+
+        if (UNIT_VTABLE(u)->reset_maintenance)
+                UNIT_VTABLE(u)->reset_maintenance(u);
+}
+
 static const char* const unit_type_table[_UNIT_TYPE_MAX] = {
         [UNIT_SERVICE] = "service",
         [UNIT_TIMER] = "timer",
index cfad3ca..1295d9f 100644 (file)
@@ -290,6 +290,9 @@ struct UnitVTable {
         void (*sigchld_event)(Unit *u, pid_t pid, int code, int status);
         void (*timer_event)(Unit *u, uint64_t n_elapsed, Watch *w);
 
+        /* Reset maintenance state if we are in maintainance state */
+        void (*reset_maintenance)(Unit *u);
+
         /* Called whenever any of the cgroups this unit watches for
          * ran empty */
         void (*cgroup_notify_empty)(Unit *u);
@@ -467,6 +470,8 @@ void unit_status_printf(Unit *u, const char *format, ...);
 
 bool unit_need_daemon_reload(Unit *u);
 
+void unit_reset_maintenance(Unit *u);
+
 const char *unit_type_to_string(UnitType i);
 UnitType unit_type_from_string(const char *s);