X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=manager.c;h=fca1963af1a111782d982b20c8e50a24ce31ef5b;hp=a32755cedc492c3996bda1869111f095c30f3572;hb=94f043472a5af62dc9cd5767e89ba33872212d5e;hpb=ce578209aa4e061aa38d3a4727612bb388307bf9 diff --git a/manager.c b/manager.c index a32755ced..fca1963af 100644 --- a/manager.c +++ b/manager.c @@ -17,12 +17,6 @@ #include "log.h" #include "util.h" -static const char * const special_table[_SPECIAL_UNIT_MAX] = { - [SPECIAL_SYSLOG_SERVICE] = "syslog.service", - [SPECIAL_DBUS_SERVICE] = "messagebus.service", - [SPECIAL_LOGGER_SOCKET] = "systemd-logger.socket" -}; - static int manager_setup_signals(Manager *m) { sigset_t mask; struct epoll_event ev; @@ -42,7 +36,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,28 +50,13 @@ static int manager_setup_signals(Manager *m) { return 0; } -static int manager_load_special_units(Manager *m) { - SpecialUnit c; - int r; - - assert(m); - - /* Loads all 'special' units, so that we have easy access to them later */ - - for (c = 0; c < _SPECIAL_UNIT_MAX; c++) - if ((r = manager_load_unit(m, special_table[c], m->special_units+c)) < 0) - return r; - - return 0; -}; - Manager* manager_new(void) { Manager *m; if (!(m = new0(Manager, 1))) return NULL; - m->signal_watch.fd = m->epoll_fd = -1; + m->signal_watch.fd = m->mount_watch.fd = m->udev_watch.fd = m->epoll_fd = -1; if (!(m->units = hashmap_new(string_hash_func, string_compare_func))) goto fail; @@ -97,9 +76,6 @@ Manager* manager_new(void) { if (manager_setup_signals(m) < 0) goto fail; - if (manager_load_special_units(m) < 0) - goto fail; - return m; fail: @@ -108,6 +84,7 @@ fail: } void manager_free(Manager *m) { + UnitType c; Unit *u; Job *j; @@ -119,6 +96,10 @@ void manager_free(Manager *m) { while ((u = hashmap_first(m->units))) unit_free(u); + for (c = 0; c < _UNIT_TYPE_MAX; c++) + if (unit_vtable[c]->shutdown) + unit_vtable[c]->shutdown(m); + hashmap_free(m->units); hashmap_free(m->jobs); hashmap_free(m->transaction_jobs); @@ -132,6 +113,39 @@ void manager_free(Manager *m) { free(m); } +int manager_coldplug(Manager *m) { + int r; + UnitType c; + Iterator i; + Unit *u; + char *k; + + assert(m); + + /* First, let's ask every type to load all units from + * disk/kernel that it might know */ + for (c = 0; c < _UNIT_TYPE_MAX; c++) + if (unit_vtable[c]->enumerate) + if ((r = unit_vtable[c]->enumerate(m)) < 0) + return r; + + manager_dispatch_load_queue(m); + + /* Then, let's set up their initial state. */ + HASHMAP_FOREACH_KEY(u, k, m->units, i) { + + /* ignore aliases */ + if (unit_id(u) != k) + continue; + + if (UNIT_VTABLE(u)->coldplug) + if ((r = UNIT_VTABLE(u)->coldplug(u)) < 0) + return r; + } + + return 0; +} + static void transaction_delete_job(Manager *m, Job *j) { assert(m); assert(j); @@ -410,8 +424,12 @@ static int transaction_verify_order_one(Manager *m, Job *j, Job *from, unsigned * since smart how we are we stored our way back in * there. */ + log_debug("Found cycle on %s/%s", unit_id(j->unit), job_type_to_string(j->type)); + for (k = from; k; k = (k->generation == generation ? k->marker : NULL)) { + log_debug("Walked on cycle path to %s/%s", unit_id(j->unit), job_type_to_string(j->type)); + if (!k->installed && !unit_matters_to_anchor(k->unit, k)) { /* Ok, we can drop this one, so let's @@ -427,6 +445,8 @@ static int transaction_verify_order_one(Manager *m, Job *j, Job *from, unsigned break; } + log_debug("Unable to break cycle"); + return -ENOEXEC; } @@ -453,6 +473,10 @@ static int transaction_verify_order_one(Manager *m, Job *j, Job *from, unsigned return r; } + /* Ok, let's backtrack, and remember that this entry is not on + * our path anymore. */ + j->marker = NULL; + return 0; } @@ -539,6 +563,7 @@ static void transaction_minimize_impact(Manager *m) { HASHMAP_FOREACH(j, m->transaction_jobs, i) { LIST_FOREACH(transaction, j, j) { + bool stops_running_service, changes_existing_job; /* If it matters, we shouldn't drop it */ if (j->matters_to_anchor) @@ -547,12 +572,25 @@ static void transaction_minimize_impact(Manager *m) { /* Would this stop a running service? * Would this change an existing job? * If so, let's drop this entry */ - if ((j->type != JOB_STOP || UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(j->unit))) && - (!j->unit->meta.job || job_type_is_conflicting(j->type, j->unit->meta.job->state))) + + stops_running_service = + j->type == JOB_STOP && UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(j->unit)); + + changes_existing_job = + j->unit->meta.job && job_type_is_conflicting(j->type, j->unit->meta.job->state); + + if (!stops_running_service && !changes_existing_job) continue; + if (stops_running_service) + log_debug("%s/%s would stop a running service.", unit_id(j->unit), job_type_to_string(j->type)); + + if (changes_existing_job) + log_debug("%s/%s would change existing job.", unit_id(j->unit), job_type_to_string(j->type)); + /* Ok, let's get rid of this */ - log_debug("Deleting %s/%s to minimize impact", unit_id(j->unit), job_type_to_string(j->type)); + log_debug("Deleting %s/%s to minimize impact.", unit_id(j->unit), job_type_to_string(j->type)); + transaction_delete_job(m, j); again = true; break; @@ -647,8 +685,10 @@ static int transaction_activate(Manager *m, JobMode mode) { if ((r = transaction_verify_order(m, &generation)) >= 0) break; - if (r != -EAGAIN) + if (r != -EAGAIN) { + log_debug("Requested transaction contains an unfixable cyclic ordering dependency: %s", strerror(-r)); goto rollback; + } /* Let's see if the resulting transaction ordering * graph is still cyclic... */ @@ -661,8 +701,10 @@ static int transaction_activate(Manager *m, JobMode mode) { if ((r = transaction_merge_jobs(m)) >= 0) break; - if (r != -EAGAIN) + if (r != -EAGAIN) { + log_debug("Requested transaction contains unmergable jobs: %s", strerror(-r)); goto rollback; + } /* Sixth step: an entry got dropped, let's garbage * collect its dependencies. */ @@ -674,12 +716,16 @@ static int transaction_activate(Manager *m, JobMode mode) { /* Seventh step: check whether we can actually apply this */ if (mode == JOB_FAIL) - if ((r = transaction_is_destructive(m, mode)) < 0) + if ((r = transaction_is_destructive(m, mode)) < 0) { + log_debug("Requested transaction contradicts existing jobs: %s", strerror(-r)); goto rollback; + } /* Eights step: apply changes */ - if ((r = transaction_apply(m, mode)) < 0) + if ((r = transaction_apply(m, mode)) < 0) { + log_debug("Failed to apply transaction: %s", strerror(-r)); goto rollback; + } assert(hashmap_isempty(m->transaction_jobs)); assert(!m->transaction_anchor); @@ -842,6 +888,8 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool for assert(unit); assert(mode < _JOB_MODE_MAX); + 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))) { transaction_abort(m); return r; @@ -850,6 +898,8 @@ 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)); + if (_ret) *_ret = ret; @@ -869,7 +919,7 @@ Unit *manager_get_unit(Manager *m, const char *name) { return hashmap_get(m->units, name); } -static void dispatch_load_queue(Manager *m) { +void manager_dispatch_load_queue(Manager *m) { Meta *meta; assert(m); @@ -927,7 +977,7 @@ int manager_load_unit(Manager *m, const char *path, Unit **_ret) { } unit_add_to_load_queue(ret); - dispatch_load_queue(m); + manager_dispatch_load_queue(m); *_ret = ret; return 0; @@ -1010,7 +1060,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; @@ -1073,10 +1123,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) @@ -1107,6 +1157,16 @@ static int process_event(Manager *m, struct epoll_event *ev, bool *quit) { 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; + default: assert_not_reached("Unknown epoll event type."); }