summaryrefslogtreecommitdiff
path: root/src/util.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2011-02-15 00:30:11 +0100
committerLennart Poettering <lennart@poettering.net>2011-02-15 00:30:11 +0100
commit83cc030fadf71d63d488cf9015275f9e5a02e2cc (patch)
tree4bfa13d11be343cba555e9b629e16a0edb4c4c41 /src/util.c
parent3036c489fa503031acb9a2fba1f3537cbe59ae9e (diff)
shutdown: execute all binaries in /lib/systemd/system-shutdown as last step before invoking reboot()
Diffstat (limited to 'src/util.c')
-rw-r--r--src/util.c114
1 files changed, 114 insertions, 0 deletions
diff --git a/src/util.c b/src/util.c
index 80b88b0e4e..b0a01fde2f 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",