X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=unit.c;h=cb9fe7cdaaa6429c2de4dc52cd142c62ad8eb5a4;hp=4fbf586c8d1cf7a7487d02c53cfecf8961ce73ec;hb=5f9a22c3745a588883695e90bca00776b79610a4;hpb=94f043472a5af62dc9cd5767e89ba33872212d5e diff --git a/unit.c b/unit.c index 4fbf586c8..cb9fe7cda 100644 --- a/unit.c +++ b/unit.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 @@ -155,6 +174,7 @@ int unit_add_name(Unit *u, const char *text) { if (!u->meta.id) u->meta.id = s; + unit_add_to_dbus_queue(u); return 0; } @@ -170,6 +190,8 @@ int unit_choose_id(Unit *u, const char *name) { return -ENOENT; u->meta.id = s; + + unit_add_to_dbus_queue(u); return 0; } @@ -183,6 +205,8 @@ int unit_set_description(Unit *u, const char *description) { free(u->meta.description); u->meta.description = s; + + unit_add_to_dbus_queue(u); return 0; } @@ -196,6 +220,16 @@ void unit_add_to_load_queue(Unit *u) { u->meta.in_load_queue = true; } +void unit_add_to_dbus_queue(Unit *u) { + assert(u); + + if (u->meta.load_state == UNIT_STUB || u->meta.in_dbus_queue || set_isempty(u->meta.manager->subscribed)) + return; + + LIST_PREPEND(Meta, dbus_queue, u->meta.manager->dbus_unit_queue, &u->meta); + u->meta.in_dbus_queue = true; +} + static void bidi_set_free(Unit *u, Set *s) { Iterator i; Unit *other; @@ -222,6 +256,8 @@ void unit_free(Unit *u) { assert(u); + bus_unit_send_removed_signal(u); + /* Detach from next 'bigger' objects */ SET_FOREACH(t, u->meta.names, i) @@ -233,6 +269,9 @@ void unit_free(Unit *u) { if (u->meta.in_load_queue) LIST_REMOVE(Meta, load_queue, u->meta.manager->load_queue, &u->meta); + if (u->meta.in_dbus_queue) + LIST_REMOVE(Meta, dbus_queue, u->meta.manager->dbus_unit_queue, &u->meta); + if (u->meta.load_state == UNIT_LOADED) if (UNIT_VTABLE(u)->done) UNIT_VTABLE(u)->done(u); @@ -306,6 +345,8 @@ int unit_merge(Unit *u, Unit *other) { if ((r = ensure_merge(&u->meta.dependencies[d], other->meta.dependencies[d])) < 0) return r; + unit_add_to_dbus_queue(u); + return 0; } @@ -332,15 +373,15 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { char *t; UnitDependency d; Iterator i; - char *prefix2; + char *p2; + const char *prefix2; assert(u); if (!prefix) prefix = ""; - prefix2 = strappend(prefix, "\t"); - if (!prefix2) - prefix2 = ""; + p2 = strappend(prefix, "\t"); + prefix2 = p2 ? p2 : prefix; fprintf(f, "%s→ Unit %s:\n" @@ -378,7 +419,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { if (u->meta.job) job_dump(u->meta.job, f, prefix2); - free(prefix2); + free(p2); } /* Common implementation for multiple backends */ @@ -418,10 +459,12 @@ int unit_load(Unit *u) { goto fail; u->meta.load_state = UNIT_LOADED; + unit_add_to_dbus_queue(u); return 0; fail: u->meta.load_state = UNIT_FAILED; + unit_add_to_dbus_queue(u); return r; } @@ -435,19 +478,25 @@ int unit_start(Unit *u) { assert(u); - if (!UNIT_VTABLE(u)->start) - return -EBADR; - + /* If this is already (being) started, then this will + * succeed. Note that this will even succeed if this unit is + * not startable by the user. This is relied on to detect when + * we need to wait for units and when waiting is finished. */ state = unit_active_state(u); if (UNIT_IS_ACTIVE_OR_RELOADING(state)) return -EALREADY; + /* If it is stopped, but we cannot start it, then fail */ + if (!UNIT_VTABLE(u)->start) + return -EBADR; + /* We don't suppress calls to ->start() here when we are * already starting, to allow this request to be used as a * "hurry up" call, for example when the unit is in some "auto * restart" state where it waits for a holdoff timer to elapse * before it will start again. */ + unit_add_to_dbus_queue(u); return UNIT_VTABLE(u)->start(u); } @@ -467,16 +516,17 @@ int unit_stop(Unit *u) { assert(u); - if (!UNIT_VTABLE(u)->stop) - return -EBADR; - state = unit_active_state(u); if (state == UNIT_INACTIVE) return -EALREADY; + if (!UNIT_VTABLE(u)->stop) + return -EBADR; + if (state == UNIT_DEACTIVATING) return 0; + unit_add_to_dbus_queue(u); return UNIT_VTABLE(u)->stop(u); } @@ -500,6 +550,7 @@ int unit_reload(Unit *u) { if (unit_active_state(u) != UNIT_ACTIVE) return -ENOEXEC; + unit_add_to_dbus_queue(u); return UNIT_VTABLE(u)->reload(u); } @@ -630,7 +681,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) { /* So we reached a different state for this * job. Let's see if we can run it now if it * failed previously due to EAGAIN. */ - job_schedule_run(u->meta.job); + job_add_to_run_queue(u->meta.job); else { assert(u->meta.job->state == JOB_RUNNING); @@ -699,6 +750,8 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) { /* Maybe we finished startup and are now ready for being * stopped because unneeded? */ unit_check_uneeded(u); + + unit_add_to_dbus_queue(u); } int unit_watch_fd(Unit *u, int fd, uint32_t events, Watch *w) { @@ -707,7 +760,7 @@ int unit_watch_fd(Unit *u, int fd, uint32_t events, Watch *w) { assert(u); assert(fd >= 0); assert(w); - assert(w->type == WATCH_INVALID || (w->type == WATCH_FD && w->fd == fd && w->unit == u)); + assert(w->type == WATCH_INVALID || (w->type == WATCH_FD && w->fd == fd && w->data.unit == u)); zero(ev); ev.data.ptr = w; @@ -721,7 +774,7 @@ int unit_watch_fd(Unit *u, int fd, uint32_t events, Watch *w) { w->fd = fd; w->type = WATCH_FD; - w->unit = u; + w->data.unit = u; return 0; } @@ -733,12 +786,13 @@ void unit_unwatch_fd(Unit *u, Watch *w) { if (w->type == WATCH_INVALID) return; - assert(w->type == WATCH_FD && w->unit == u); + assert(w->type == WATCH_FD); + assert(w->data.unit == u); assert_se(epoll_ctl(u->meta.manager->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0); w->fd = -1; w->type = WATCH_INVALID; - w->unit = NULL; + w->data.unit = NULL; } int unit_watch_pid(Unit *u, pid_t pid) { @@ -762,7 +816,7 @@ int unit_watch_timer(Unit *u, usec_t delay, Watch *w) { assert(u); assert(w); - assert(w->type == WATCH_INVALID || (w->type == WATCH_TIMER && w->unit == u)); + assert(w->type == WATCH_INVALID || (w->type == WATCH_TIMER && w->data.unit == u)); /* This will try to reuse the old timer if there is one */ @@ -806,13 +860,13 @@ int unit_watch_timer(Unit *u, usec_t delay, Watch *w) { w->fd = fd; w->type = WATCH_TIMER; - w->unit = u; + w->data.unit = u; return 0; fail: if (ours) - assert_se(close_nointr(fd) == 0); + close_nointr_nofail(fd); return -errno; } @@ -824,14 +878,14 @@ void unit_unwatch_timer(Unit *u, Watch *w) { if (w->type == WATCH_INVALID) return; - assert(w->type == WATCH_TIMER && w->unit == u); + assert(w->type == WATCH_TIMER && w->data.unit == u); assert_se(epoll_ctl(u->meta.manager->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0); assert_se(close_nointr(w->fd) == 0); w->fd = -1; w->type = WATCH_INVALID; - w->unit = NULL; + w->data.unit = NULL; } bool unit_job_is_applicable(Unit *u, JobType j) { @@ -901,6 +955,7 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other) { return r; } + unit_add_to_dbus_queue(u); return 0; } @@ -1004,6 +1059,23 @@ char *unit_name_escape_path(const char *prefix, const char *path, const char *su return r; } +char *unit_dbus_path(Unit *u) { + char *p, *e; + + assert(u); + + if (!(e = bus_path_escape(unit_id(u)))) + return NULL; + + if (asprintf(&p, "/org/freedesktop/systemd1/unit/%s", e) < 0) { + free(e); + return NULL; + } + + free(e); + return p; +} + static const char* const unit_type_table[_UNIT_TYPE_MAX] = { [UNIT_SERVICE] = "service", [UNIT_TIMER] = "timer",