From: Lennart Poettering Date: Mon, 14 Feb 2011 23:30:11 +0000 (+0100) Subject: shutdown: execute all binaries in /lib/systemd/system-shutdown as last step before... X-Git-Tag: v18~18 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=83cc030fadf71d63d488cf9015275f9e5a02e2cc;p=systemd shutdown: execute all binaries in /lib/systemd/system-shutdown as last step before invoking reboot() --- diff --git a/Makefile.am b/Makefile.am index dd872f88..f508163d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -41,6 +41,7 @@ rootsbindir=$(rootdir)/sbin rootlibexecdir=$(rootdir)/lib/systemd systemunitdir=$(rootdir)/lib/systemd/system systemgeneratordir=$(rootdir)/lib/systemd/system-generators +systemshutdowndir=$(rootdir)/lib/systemd/system-shutdown AM_CPPFLAGS = \ -include $(top_builddir)/config.h \ @@ -62,6 +63,7 @@ AM_CPPFLAGS = \ -DSYSTEMD_CRYPTSETUP_PATH=\"$(rootlibexecdir)/systemd-cryptsetup\" \ -DSYSTEM_GENERATOR_PATH=\"$(systemgeneratordir)\" \ -DUSER_GENERATOR_PATH=\"$(usergeneratordir)\" \ + -DSYSTEM_SHUTDOWN_PATH=\"$(systemshutdowndir)\" \ -I $(top_srcdir)/src if TARGET_GENTOO @@ -375,7 +377,8 @@ libsystemd_basic_la_SOURCES = \ src/conf-parser.c \ src/socket-util.c \ src/log.c \ - src/ratelimit.c + src/ratelimit.c \ + src/exit-status.c libsystemd_basic_la_CFLAGS = \ $(AM_CFLAGS) \ @@ -403,7 +406,6 @@ libsystemd_core_la_SOURCES = \ src/load-dropin.c \ src/execute.c \ src/utmp-wtmp.c \ - src/exit-status.c \ src/dbus.c \ src/dbus-manager.c \ src/dbus-unit.c \ diff --git a/src/manager.c b/src/manager.c index 92b27459..7d0b351c 100644 --- a/src/manager.c +++ b/src/manager.c @@ -2836,9 +2836,8 @@ void manager_check_finished(Manager *m) { void manager_run_generators(Manager *m) { DIR *d = NULL; - struct dirent *de; - Hashmap *pids = NULL; const char *generator_path; + const char *argv[3]; assert(m); @@ -2868,83 +2867,11 @@ void manager_run_generators(Manager *m) { } } - if (!(pids = hashmap_new(trivial_hash_func, trivial_compare_func))) { - log_error("Failed to allocate set."); - goto finish; - } - - while ((de = readdir(d))) { - char *path; - pid_t pid; - int k; - - if (ignore_file(de->d_name)) - continue; + argv[0] = NULL; /* Leave this empty, execute_directory() will fill something in */ + argv[1] = m->generator_unit_path; + argv[2] = NULL; - if (de->d_type != DT_REG && - de->d_type != DT_LNK && - de->d_type != DT_UNKNOWN) - continue; - - if (asprintf(&path, "%s/%s", generator_path, de->d_name) < 0) { - log_error("Out of memory"); - continue; - } - - if ((pid = fork()) < 0) { - log_error("Failed to fork: %m"); - free(path); - continue; - } - - if (pid == 0) { - const char *arguments[5]; - /* Child */ - - arguments[0] = path; - arguments[1] = m->generator_unit_path; - arguments[2] = NULL; - - execv(path, (char **) arguments); - - log_error("Failed to execute %s: %m", path); - _exit(EXIT_FAILURE); - } - - log_debug("Spawned generator %s as %lu", path, (unsigned long) pid); - - if ((k = hashmap_put(pids, UINT_TO_PTR(pid), path)) < 0) { - log_error("Failed to add PID to set: %s", strerror(-k)); - free(path); - } - } - - while (!hashmap_isempty(pids)) { - siginfo_t si; - char *path; - - zero(si); - if (waitid(P_ALL, 0, &si, WEXITED) < 0) { - - if (errno == EINTR) - continue; - - log_error("waitid() failed: %m"); - goto finish; - } - - if ((path = hashmap_remove(pids, UINT_TO_PTR(si.si_pid)))) { - if (!is_clean_exit(si.si_code, si.si_status)) { - if (si.si_code == CLD_EXITED) - log_error("%s exited with exit status %i.", path, si.si_status); - else - log_error("%s terminated by signal %s.", path, signal_to_string(si.si_status)); - } else - log_debug("Generator %s exited successfully.", path); - - free(path); - } - } + execute_directory(generator_path, d, (char**) argv); if (rmdir(m->generator_unit_path) >= 0) { /* Uh? we were able to remove this dir? I guess that @@ -2973,9 +2900,6 @@ void manager_run_generators(Manager *m) { finish: if (d) closedir(d); - - if (pids) - hashmap_free_free(pids); } void manager_undo_generators(Manager *m) { diff --git a/src/shutdown.c b/src/shutdown.c index 94deb854..23b9f1b5 100644 --- a/src/shutdown.c +++ b/src/shutdown.c @@ -336,6 +336,8 @@ int main(int argc, char *argv[]) { if (retries >= FINALIZE_ATTEMPTS) log_error("Too many interations, giving up."); + execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, NULL); + sync(); if (cmd == LINUX_REBOOT_CMD_KEXEC) { diff --git a/src/util.c b/src/util.c index 80b88b0e..b0a01fde 100644 --- a/src/util.c +++ b/src/util.c @@ -59,6 +59,7 @@ #include "strv.h" #include "label.h" #include "exit-status.h" +#include "hashmap.h" bool streq_ptr(const char *a, const char *b) { @@ -3664,6 +3665,119 @@ bool running_in_vm(void) { return false; } +void execute_directory(const char *directory, DIR *d, char *argv[]) { + DIR *_d = NULL; + struct dirent *de; + Hashmap *pids = NULL; + + assert(directory); + + /* Executes all binaries in a directory in parallel and waits + * until all they all finished. */ + + if (!d) { + if (!(_d = opendir(directory))) { + + if (errno == ENOENT) + return; + + log_error("Failed to enumerate directory %s: %m", directory); + return; + } + + d = _d; + } + + if (!(pids = hashmap_new(trivial_hash_func, trivial_compare_func))) { + log_error("Failed to allocate set."); + goto finish; + } + + while ((de = readdir(d))) { + char *path; + pid_t pid; + int k; + + if (ignore_file(de->d_name)) + continue; + + if (de->d_type != DT_REG && + de->d_type != DT_LNK && + de->d_type != DT_UNKNOWN) + continue; + + if (asprintf(&path, "%s/%s", directory, de->d_name) < 0) { + log_error("Out of memory"); + continue; + } + + if ((pid = fork()) < 0) { + log_error("Failed to fork: %m"); + free(path); + continue; + } + + if (pid == 0) { + char *_argv[2]; + /* Child */ + + if (!argv) { + _argv[0] = path; + _argv[1] = NULL; + argv = _argv; + } else + if (!argv[0]) + argv[0] = path; + + execv(path, argv); + + log_error("Failed to execute %s: %m", path); + _exit(EXIT_FAILURE); + } + + log_debug("Spawned %s as %lu", path, (unsigned long) pid); + + if ((k = hashmap_put(pids, UINT_TO_PTR(pid), path)) < 0) { + log_error("Failed to add PID to set: %s", strerror(-k)); + free(path); + } + } + + while (!hashmap_isempty(pids)) { + siginfo_t si; + char *path; + + zero(si); + if (waitid(P_ALL, 0, &si, WEXITED) < 0) { + + if (errno == EINTR) + continue; + + log_error("waitid() failed: %m"); + goto finish; + } + + if ((path = hashmap_remove(pids, UINT_TO_PTR(si.si_pid)))) { + if (!is_clean_exit(si.si_code, si.si_status)) { + if (si.si_code == CLD_EXITED) + log_error("%s exited with exit status %i.", path, si.si_status); + else + log_error("%s terminated by signal %s.", path, signal_to_string(si.si_status)); + } else + log_debug("%s exited successfully.", path); + + free(path); + } + } + +finish: + if (_d) + closedir(_d); + + if (pids) + hashmap_free_free(pids); +} + static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_NONE] = "none", [IOPRIO_CLASS_RT] = "realtime", diff --git a/src/util.h b/src/util.h index a534dcfe..3898b89f 100644 --- a/src/util.h +++ b/src/util.h @@ -375,6 +375,8 @@ const char *default_term_for_tty(const char *tty); bool running_in_vm(void); +void execute_directory(const char *directory, DIR *_d, char *argv[]); + #define NULSTR_FOREACH(i, l) \ for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)