From 5632e3743db350a67478acc107d76cdf648a1f99 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 18 Jul 2010 04:58:01 +0200 Subject: [PATCH] systemctl: introduce reset-maintenance command --- fixme | 4 +-- man/systemctl.xml | 19 +++++++++++++ man/systemd.xml | 2 +- src/automount.c | 13 +++++++++ src/dbus-manager.c | 33 ++++++++++++++++++++- src/dbus-unit.c | 7 +++++ src/dbus-unit.h | 1 + src/manager.c | 10 +++++++ src/manager.h | 2 ++ src/mount.c | 13 +++++++++ src/path.c | 13 +++++++++ src/service.c | 13 +++++++++ src/socket.c | 13 +++++++++ src/swap.c | 27 ++++++++++++------ src/systemctl.c | 71 ++++++++++++++++++++++++++++++++++++++++++---- src/timer.c | 13 +++++++++ src/unit.c | 7 +++++ src/unit.h | 5 ++++ 18 files changed, 249 insertions(+), 17 deletions(-) diff --git a/fixme b/fixme index 30cfaac3..29e0fde7 100644 --- 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... diff --git a/man/systemctl.xml b/man/systemctl.xml index 42682b78..737bcbe0 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -314,6 +314,25 @@ properties of the job is shown. + + + reset-maintenance [NAME...] + + 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. + + load [NAME...] diff --git a/man/systemd.xml b/man/systemd.xml index 25f24ce7..c027b4f6 100644 --- a/man/systemd.xml +++ b/man/systemd.xml @@ -226,7 +226,7 @@ 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 systemd.unit5, diff --git a/src/automount.c b/src/automount.c index e685c96a..213b178e 100644 --- a/src/automount.c +++ b/src/automount.c @@ -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 diff --git a/src/dbus-manager.c b/src/dbus-manager.c index c717ccd8..969c4305 100644 --- a/src/dbus-manager.c +++ b/src/dbus-manager.c @@ -72,11 +72,15 @@ " \n" \ " \n" \ " \n" \ + " \n" \ + " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ + " \n" \ " \n" \ " \n" \ " \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; diff --git a/src/dbus-unit.c b/src/dbus-unit.c index ce341309..2dcd032a 100644 --- a/src/dbus-unit.c +++ b/src/dbus-unit.c @@ -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 diff --git a/src/dbus-unit.h b/src/dbus-unit.h index 0b9c62f8..e49f82d8 100644 --- a/src/dbus-unit.h +++ b/src/dbus-unit.h @@ -56,6 +56,7 @@ " \n" \ " \n" \ " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ diff --git a/src/manager.c b/src/manager.c index 7b2586fb..8a9b9dd4 100644 --- a/src/manager.c +++ b/src/manager.c @@ -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" diff --git a/src/manager.h b/src/manager.h index c492ffa5..96de120d 100644 --- a/src/manager.h +++ b/src/manager.h @@ -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); diff --git a/src/mount.c b/src/mount.c index bee3c9a6..c1a1d511 100644 --- a/src/mount.c +++ b/src/mount.c @@ -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, diff --git a/src/path.c b/src/path.c index a9fa3771..f4c20940 100644 --- a/src/path.c +++ b/src/path.c @@ -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 }; diff --git a/src/service.c b/src/service.c index a5d1ebd8..6b786d1b 100644 --- a/src/service.c +++ b/src/service.c @@ -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, diff --git a/src/socket.c b/src/socket.c index 4cf21cf0..2c9d6939 100644 --- a/src/socket.c +++ b/src/socket.c @@ -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 }; diff --git a/src/swap.c b/src/swap.c index de468a04..6765a4ae 100644 --- a/src/swap.c +++ b/src/swap.c @@ -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 }; diff --git a/src/systemctl.c b/src/systemctl.c index 06b4caea..acb89a5a 100644 --- a/src/systemctl.c +++ b/src/systemctl.c @@ -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; diff --git a/src/timer.c b/src/timer.c index 15804789..cd6728a1 100644 --- a/src/timer.c +++ b/src/timer.c @@ -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 }; diff --git a/src/unit.c b/src/unit.c index 348d1395..5807e4f4 100644 --- a/src/unit.c +++ b/src/unit.c @@ -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", diff --git a/src/unit.h b/src/unit.h index cfad3ca5..1295d9ff 100644 --- a/src/unit.h +++ b/src/unit.h @@ -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); -- 2.39.5