X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=manager.c;h=25bc7528825650489e04c18e4c5e813c211a01be;hb=5f9a22c3745a588883695e90bca00776b79610a4;hp=06a171ff2ebb7b6041980caa9e06192eae5767c3;hpb=c20cae324d93e7fcdb8618e37c3ac377d87edb97;p=elogind.git diff --git a/manager.c b/manager.c index 06a171ff2..25bc75288 100644 --- a/manager.c +++ b/manager.c @@ -1,5 +1,24 @@ /*-*- Mode: C; c-basic-offset: 8 -*-*/ +/*** + This file is part of systemd. + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with systemd; If not, see . +***/ + #include #include #include @@ -16,6 +35,7 @@ #include "strv.h" #include "log.h" #include "util.h" +#include "ratelimit.h" static int manager_setup_signals(Manager *m) { sigset_t mask; @@ -36,7 +56,7 @@ static int manager_setup_signals(Manager *m) { assert_se(sigaddset(&mask, SIGPIPE) == 0); assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); - m->signal_watch.type = WATCH_SIGNAL_FD; + m->signal_watch.type = WATCH_SIGNAL; if ((m->signal_watch.fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) return -errno; @@ -56,7 +76,17 @@ Manager* manager_new(void) { if (!(m = new0(Manager, 1))) return NULL; - m->signal_watch.fd = m->epoll_fd = -1; + if (getpid() == 1) + m->running_as = MANAGER_INIT; + else if (getuid() == 0) + m->running_as = MANAGER_SYSTEM; + else + m->running_as = MANAGER_USER; + + log_debug("systemd running in %s mode.", manager_running_as_to_string(m->running_as)); + + m->signal_watch.fd = m->mount_watch.fd = m->udev_watch.fd = m->epoll_fd = -1; + m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */ if (!(m->units = hashmap_new(string_hash_func, string_compare_func))) goto fail; @@ -76,6 +106,10 @@ Manager* manager_new(void) { if (manager_setup_signals(m) < 0) goto fail; + /* FIXME: this should be called only when the D-Bus bus daemon is running */ + if (bus_init(m) < 0) + goto fail; + return m; fail: @@ -100,6 +134,8 @@ void manager_free(Manager *m) { if (unit_vtable[c]->shutdown) unit_vtable[c]->shutdown(m); + bus_done(m); + hashmap_free(m->units); hashmap_free(m->jobs); hashmap_free(m->transaction_jobs); @@ -638,7 +674,8 @@ static int transaction_apply(Manager *m, JobMode mode) { assert(!j->transaction_next); assert(!j->transaction_prev); - job_schedule_run(j); + job_add_to_run_queue(j); + job_add_to_dbus_queue(j); } /* As last step, kill all remaining job dependencies. */ @@ -873,6 +910,9 @@ static int transaction_add_job_and_dependencies(Manager *m, JobType type, Unit * /* JOB_VERIFY_STARTED, JOB_RELOAD require no dependency handling */ } + if (_ret) + *_ret = ret; + return 0; fail: @@ -890,7 +930,7 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool for log_debug("Trying to enqueue job %s/%s", unit_id(unit), job_type_to_string(type)); - if ((r = transaction_add_job_and_dependencies(m, type, unit, NULL, true, force, &ret))) { + if ((r = transaction_add_job_and_dependencies(m, type, unit, NULL, true, force, &ret)) < 0) { transaction_abort(m); return r; } @@ -898,7 +938,7 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool for if ((r = transaction_activate(m, mode)) < 0) return r; - log_debug("Enqueued job %s/%s", unit_id(unit), job_type_to_string(type)); + log_debug("Enqueued job %s/%s as %u", unit_id(unit), job_type_to_string(type), (unsigned) ret->id); if (_ret) *_ret = ret; @@ -919,14 +959,15 @@ Unit *manager_get_unit(Manager *m, const char *name) { return hashmap_get(m->units, name); } -void manager_dispatch_load_queue(Manager *m) { +unsigned manager_dispatch_load_queue(Manager *m) { Meta *meta; + unsigned n = 0; assert(m); /* Make sure we are not run recursively */ if (m->dispatching_load_queue) - return; + return 0; m->dispatching_load_queue = true; @@ -937,9 +978,11 @@ void manager_dispatch_load_queue(Manager *m) { assert(meta->in_load_queue); unit_load(UNIT(meta)); + n++; } m->dispatching_load_queue = false; + return n; } int manager_load_unit(Manager *m, const char *path, Unit **_ret) { @@ -977,6 +1020,8 @@ int manager_load_unit(Manager *m, const char *path, Unit **_ret) { } unit_add_to_load_queue(ret); + unit_add_to_dbus_queue(ret); + manager_dispatch_load_queue(m); *_ret = ret; @@ -1018,11 +1063,12 @@ void manager_clear_jobs(Manager *m) { job_free(j); } -void manager_dispatch_run_queue(Manager *m) { +unsigned manager_dispatch_run_queue(Manager *m) { Job *j; + unsigned n = 0; if (m->dispatching_run_queue) - return; + return 0; m->dispatching_run_queue = true; @@ -1031,9 +1077,42 @@ void manager_dispatch_run_queue(Manager *m) { assert(j->in_run_queue); job_run_and_invalidate(j); + n++; } m->dispatching_run_queue = false; + return n; +} + +unsigned manager_dispatch_dbus_queue(Manager *m) { + Job *j; + Meta *meta; + unsigned n = 0; + + assert(m); + + if (m->dispatching_dbus_queue) + return 0; + + m->dispatching_dbus_queue = true; + + while ((meta = m->dbus_unit_queue)) { + Unit *u = (Unit*) meta; + assert(u->meta.in_dbus_queue); + + bus_unit_send_change_signal(u); + n++; + } + + while ((j = m->dbus_job_queue)) { + assert(j->in_dbus_queue); + + bus_job_send_change_signal(j); + n++; + } + + m->dispatching_dbus_queue = false; + return n; } static int manager_dispatch_sigchld(Manager *m) { @@ -1060,7 +1139,7 @@ static int manager_dispatch_sigchld(Manager *m) { if (si.si_code != CLD_EXITED && si.si_code != CLD_KILLED && si.si_code != CLD_DUMPED) continue; - log_debug("child %llu died (code=%s, status=%i)", (long long unsigned) si.si_pid, sigchld_code(si.si_code), si.si_status); + log_debug("child %llu died (code=%s, status=%i)", (long long unsigned) si.si_pid, sigchld_code_to_string(si.si_code), si.si_status); if (!(u = hashmap_remove(m->watch_pids, UINT32_TO_PTR(si.si_pid)))) continue; @@ -1123,10 +1202,10 @@ static int process_event(Manager *m, struct epoll_event *ev, bool *quit) { switch (w->type) { - case WATCH_SIGNAL_FD: + case WATCH_SIGNAL: /* An incoming signal? */ - if (ev->events != POLLIN) + if (ev->events != EPOLLIN) return -EINVAL; if ((r = manager_process_signal_fd(m, quit)) < 0) @@ -1137,7 +1216,7 @@ static int process_event(Manager *m, struct epoll_event *ev, bool *quit) { case WATCH_FD: /* Some fd event, to be dispatched to the units */ - UNIT_VTABLE(w->unit)->fd_event(w->unit, w->fd, ev->events, w); + UNIT_VTABLE(w->data.unit)->fd_event(w->data.unit, w->fd, ev->events, w); break; case WATCH_TIMER: { @@ -1145,7 +1224,7 @@ static int process_event(Manager *m, struct epoll_event *ev, bool *quit) { ssize_t k; /* Some timer event, to be dispatched to the units */ - if ((k = read(ev->data.fd, &v, sizeof(v))) != sizeof(v)) { + if ((k = read(w->fd, &v, sizeof(v))) != sizeof(v)) { if (k < 0 && (errno == EINTR || errno == EAGAIN)) break; @@ -1153,10 +1232,28 @@ static int process_event(Manager *m, struct epoll_event *ev, bool *quit) { return k < 0 ? -errno : -EIO; } - UNIT_VTABLE(w->unit)->timer_event(w->unit, v, w); + UNIT_VTABLE(w->data.unit)->timer_event(w->data.unit, v, w); break; } + case WATCH_MOUNT: + /* Some mount table change, intended for the mount subsystem */ + mount_fd_event(m, ev->events); + break; + + case WATCH_UDEV: + /* Some notification from udev, intended for the device subsystem */ + device_fd_event(m, ev->events); + break; + + case WATCH_DBUS_WATCH: + bus_watch_event(m, w, ev->events); + break; + + case WATCH_DBUS_TIMEOUT: + bus_timeout_event(m, w, ev->events); + break; + default: assert_not_reached("Unknown epoll event type."); } @@ -1168,13 +1265,31 @@ int manager_loop(Manager *m) { int r; bool quit = false; + RATELIMIT_DEFINE(rl, 1*USEC_PER_SEC, 1000); + assert(m); for (;;) { struct epoll_event event; int n; - manager_dispatch_run_queue(m); + if (!ratelimit_test(&rl)) { + /* Yay, something is going seriously wrong, pause a little */ + log_warning("Looping too fast. Throttling execution a little."); + sleep(1); + } + + if (manager_dispatch_load_queue(m) > 0) + continue; + + if (manager_dispatch_run_queue(m) > 0) + continue; + + if (bus_dispatch(m) > 0) + continue; + + if (manager_dispatch_dbus_queue(m) > 0) + continue; if ((n = epoll_wait(m->epoll_fd, &event, 1, -1)) < 0) { @@ -1193,3 +1308,59 @@ int manager_loop(Manager *m) { return 0; } } + +int manager_get_unit_from_dbus_path(Manager *m, const char *s, Unit **_u) { + char *n; + Unit *u; + + assert(m); + assert(s); + assert(_u); + + if (!startswith(s, "/org/freedesktop/systemd1/unit/")) + return -EINVAL; + + if (!(n = bus_path_unescape(s+31))) + return -ENOMEM; + + u = manager_get_unit(m, n); + free(n); + + if (!u) + return -ENOENT; + + *_u = u; + + return 0; +} + +int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j) { + Job *j; + unsigned id; + int r; + + assert(m); + assert(s); + assert(_j); + + if (!startswith(s, "/org/freedesktop/systemd1/job/")) + return -EINVAL; + + if ((r = safe_atou(s + 30, &id)) < 0) + return r; + + if (!(j = manager_get_job(m, id))) + return -ENOENT; + + *_j = j; + + return 0; +} + +static const char* const manager_running_as_table[_MANAGER_RUNNING_AS_MAX] = { + [MANAGER_INIT] = "init", + [MANAGER_SYSTEM] = "system", + [MANAGER_USER] = "user" +}; + +DEFINE_STRING_TABLE_LOOKUP(manager_running_as, ManagerRunningAs);