From f50e0a012340fa8dfe6ec7f0cd869f5f3a052d7a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 29 Jan 2010 03:18:09 +0100 Subject: [PATCH 1/1] implement coldpluggin --- Makefile | 1 - automount.c | 4 -- device.c | 66 ++++++++++++++++------- job.c | 9 ++++ load-fragment.c | 7 +-- load-fstab.c | 11 ---- load-fstab.h | 12 ----- main.c | 15 ++++-- manager.c | 82 +++++++++++++--------------- manager.h | 20 +++---- mount.c | 139 +++++++++++++++++++++++++++--------------------- mount.h | 3 ++ unit.c | 15 +++++- unit.h | 9 ++++ 14 files changed, 222 insertions(+), 171 deletions(-) delete mode 100644 load-fstab.c delete mode 100644 load-fstab.h diff --git a/Makefile b/Makefile index 22c84db77..d35620e0c 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,6 @@ COMMON= \ snapshot.o \ socket.o \ timer.o \ - load-fstab.o \ load-dropin.o \ execute.o diff --git a/automount.c b/automount.c index eb9c3d3c1..5d4a240aa 100644 --- a/automount.c +++ b/automount.c @@ -20,10 +20,6 @@ static int automount_init(Unit *u) { if ((r = unit_load_fragment(u)) < 0) return r; - /* Load entry from /etc/fstab */ - if ((r = unit_load_fstab(u)) < 0) - return r; - /* Load drop-in directory data */ if ((r = unit_load_dropin(u)) < 0) return r; diff --git a/device.c b/device.c index 6d7e2c6fa..34d760a48 100644 --- a/device.c +++ b/device.c @@ -8,6 +8,16 @@ #include "strv.h" #include "log.h" +static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = { + [DEVICE_DEAD] = UNIT_INACTIVE, + [DEVICE_AVAILABLE] = UNIT_ACTIVE +}; + +static const char* const state_string_table[_DEVICE_STATE_MAX] = { + [DEVICE_DEAD] = "dead", + [DEVICE_AVAILABLE] = "available" +}; + static void device_done(Unit *u) { Device *d = DEVICE(u); @@ -15,13 +25,31 @@ static void device_done(Unit *u) { free(d->sysfs); } -static void device_dump(Unit *u, FILE *f, const char *prefix) { +static void device_set_state(Device *d, DeviceState state) { + DeviceState old_state; + assert(d); - static const char* const state_table[_DEVICE_STATE_MAX] = { - [DEVICE_DEAD] = "dead", - [DEVICE_AVAILABLE] = "available" - }; + old_state = d->state; + d->state = state; + log_debug("%s changed %s → %s", unit_id(UNIT(d)), state_string_table[old_state], state_string_table[state]); + + unit_notify(UNIT(d), state_translation_table[old_state], state_translation_table[state]); +} + +static int device_coldplug(Unit *u) { + Device *d = DEVICE(u); + + assert(d); + assert(d->state == DEVICE_DEAD); + + if (d->sysfs) + device_set_state(d, DEVICE_AVAILABLE); + + return 0; +} + +static void device_dump(Unit *u, FILE *f, const char *prefix) { Device *d = DEVICE(u); assert(d); @@ -29,8 +57,14 @@ static void device_dump(Unit *u, FILE *f, const char *prefix) { fprintf(f, "%sDevice State: %s\n" "%sSysfs Path: %s\n", - prefix, state_table[d->state], - prefix, d->sysfs); + prefix, state_string_table[d->state], + prefix, strna(d->sysfs)); +} + +static UnitActiveState device_active_state(Unit *u) { + assert(u); + + return state_translation_table[DEVICE(u)->state]; } static int device_add_escaped_name(Unit *u, const char *prefix, const char *dn, bool make_id) { @@ -108,11 +142,9 @@ static int device_process_device(Manager *m, struct udev_device *dev) { } if ((model = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE")) || - (model = udev_device_get_property_value(dev, "ID_MODEL"))) - if (!(u->meta.description = strdup(model))) { - r = -ENOMEM; + (model = udev_device_get_property_value(dev, "ID_MODEL"))) + if ((r = unit_set_description(u, model)) < 0) goto fail; - } } else { delete = false; @@ -229,19 +261,17 @@ fail: return r; } -static UnitActiveState device_active_state(Unit *u) { - return DEVICE(u)->state == DEVICE_DEAD ? UNIT_INACTIVE : UNIT_ACTIVE; -} - const UnitVTable device_vtable = { .suffix = ".device", .init = unit_load_fragment_and_dropin, .done = device_done, + .coldplug = device_coldplug, + .dump = device_dump, - .enumerate = device_enumerate, - .shutdown = device_shutdown, + .active_state = device_active_state, - .active_state = device_active_state + .enumerate = device_enumerate, + .shutdown = device_shutdown }; diff --git a/job.c b/job.c index ff30864e4..148c7458b 100644 --- a/job.c +++ b/job.c @@ -5,6 +5,7 @@ #include "macro.h" #include "job.h" +#include "log.h" Job* job_new(Manager *m, JobType type, Unit *unit) { Job *j; @@ -405,10 +406,18 @@ int job_finish_and_invalidate(Job *j, bool success) { assert(j); assert(j->installed); + log_debug("Job %s/%s finished, success=%s", unit_id(j->unit), job_type_to_string(j->type), yes_no(success)); + /* Patch restart jobs so that they become normal start jobs */ if (success && (j->type == JOB_RESTART || j->type == JOB_TRY_RESTART)) { + + log_debug("Converting job %s/%s → %s/%s", + unit_id(j->unit), job_type_to_string(j->type), + unit_id(j->unit), job_type_to_string(JOB_START)); + j->state = JOB_RUNNING; j->type = JOB_START; + job_schedule_run(j); return 0; } diff --git a/load-fragment.c b/load-fragment.c index 94bdf171a..0cdaaa204 100644 --- a/load-fragment.c +++ b/load-fragment.c @@ -807,10 +807,11 @@ static int load_from_path(Unit *u, const char *path) { goto finish; + if (id == k) + unit_choose_id(u, id); free(k); } - unit_choose_id(u, id); free(u->meta.load_path); u->meta.load_path = filename; @@ -860,10 +861,10 @@ int unit_load_fragment(Unit *u) { /* If syslog or kernel logging is requested, make sure * our own logging daemon is run first. */ - if ((k = unit_add_dependency(u, UNIT_AFTER, u->meta.manager->special_units[SPECIAL_LOGGER_SOCKET])) < 0) + if ((k = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_LOGGER_SOCKET)) < 0) return k; - if ((k = unit_add_dependency(u, UNIT_REQUIRES, u->meta.manager->special_units[SPECIAL_LOGGER_SOCKET])) < 0) + if ((k = unit_add_dependency_by_name(u, UNIT_REQUIRES, SPECIAL_LOGGER_SOCKET)) < 0) return k; } diff --git a/load-fstab.c b/load-fstab.c deleted file mode 100644 index d611426ce..000000000 --- a/load-fstab.c +++ /dev/null @@ -1,11 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8 -*-*/ - -#include "load-fstab.h" - -int unit_load_fstab(Unit *u) { - assert(u); - - /* Load dependencies from /etc/fstab */ - - return 0; -} diff --git a/load-fstab.h b/load-fstab.h deleted file mode 100644 index b0cef7ddf..000000000 --- a/load-fstab.h +++ /dev/null @@ -1,12 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8 -*-*/ - -#ifndef fooloadfstabhfoo -#define fooloadfstabhfoo - -#include "unit.h" - -/* Read service data from /etc/fstab */ - -int unit_load_fstab(Unit *u); - -#endif diff --git a/main.c b/main.c index 2486f0629..be733f0cd 100644 --- a/main.c +++ b/main.c @@ -21,7 +21,12 @@ int main(int argc, char *argv[]) { goto finish; } - if ((r = manager_load_unit(m, "default.target", &target)) < 0) { + if ((r = manager_coldplug(m)) < 0) { + log_error("Failed to retrieve coldplug information: %s", strerror(-r)); + goto finish; + } + + if ((r = manager_load_unit(m, SPECIAL_DEFAULT_TARGET, &target)) < 0) { log_error("Failed to load default target: %s", strerror(-r)); goto finish; } @@ -37,10 +42,10 @@ int main(int argc, char *argv[]) { printf("→ By jobs:\n"); manager_dump_jobs(m, stdout, "\t"); - if ((r = manager_loop(m)) < 0) { - log_error("Failed to run mainloop: %s", strerror(-r)); - goto finish; - } + /* if ((r = manager_loop(m)) < 0) { */ + /* log_error("Failed to run mainloop: %s", strerror(-r)); */ + /* goto finish; */ + /* } */ retval = 0; diff --git a/manager.c b/manager.c index 23d450d33..9355a6a6f 100644 --- a/manager.c +++ b/manager.c @@ -17,14 +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", - [SPECIAL_KBREQUEST_TARGET] = "kbrequest.target", - [SPECIAL_CTRL_ALT_DEL_TARGET] = "ctrl-alt-del.target" -}; - static int manager_setup_signals(Manager *m) { sigset_t mask; struct epoll_event ev; @@ -58,35 +50,6 @@ 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; -} - -static int manager_enumerate(Manager *m) { - int r; - UnitType c; - - assert(m); - - for (c = 0; c < _UNIT_TYPE_MAX; c++) - if (unit_vtable[c]->enumerate) - if ((r = unit_vtable[c]->enumerate(m)) < 0) - return r; - - return 0; -} - Manager* manager_new(void) { Manager *m; @@ -113,12 +76,6 @@ Manager* manager_new(void) { if (manager_setup_signals(m) < 0) goto fail; - if (manager_load_special_units(m) < 0) - goto fail; - - if (manager_enumerate(m) < 0) - goto fail; - return m; fail: @@ -156,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); @@ -874,6 +864,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; @@ -893,7 +885,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); @@ -951,7 +943,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; diff --git a/manager.h b/manager.h index 64c9b8064..793a55fb4 100644 --- a/manager.h +++ b/manager.h @@ -30,14 +30,12 @@ struct Watch { #include "list.h" #include "set.h" -typedef enum SpecialUnit { - SPECIAL_SYSLOG_SERVICE, - SPECIAL_DBUS_SERVICE, - SPECIAL_LOGGER_SOCKET, - SPECIAL_CTRL_ALT_DEL_TARGET, - SPECIAL_KBREQUEST_TARGET, - _SPECIAL_UNIT_MAX -} SpecialUnit; +#define SPECIAL_DEFAULT_TARGET "default.target" +#define SPECIAL_SYSLOG_SERVICE "syslog.service" +#define SPECIAL_DBUS_SERVICE "messagebus.service" +#define SPECIAL_LOGGER_SOCKET "systemd-logger.socket" +#define SPECIAL_KBREQUEST_TARGET "kbrequest.target" +#define SPECIAL_CTRL_ALT_DEL_TARGET "ctrl-alt-del.target" struct Manager { uint32_t current_job_id; @@ -69,14 +67,14 @@ struct Manager { Watch signal_watch; - Unit *special_units[_SPECIAL_UNIT_MAX]; /* some special units */ - struct udev* udev; }; Manager* manager_new(void); void manager_free(Manager *m); +int manager_coldplug(Manager *m); + Job *manager_get_job(Manager *m, uint32_t id); Unit *manager_get_unit(Manager *m, const char *name); @@ -90,7 +88,9 @@ void manager_transaction_unlink_job(Manager *m, Job *j); void manager_clear_jobs(Manager *m); +void manager_dispatch_load_queue(Manager *m); void manager_dispatch_run_queue(Manager *m); + int manager_loop(Manager *m); #endif diff --git a/mount.c b/mount.c index ddf0520ed..d9d461a59 100644 --- a/mount.c +++ b/mount.c @@ -7,30 +7,24 @@ #include "unit.h" #include "mount.h" #include "load-fragment.h" -#include "load-fstab.h" #include "load-dropin.h" #include "log.h" -static int mount_init(Unit *u) { - int r; - Mount *m = MOUNT(u); - - assert(m); - - /* Load a .mount file */ - if ((r = unit_load_fragment(u)) < 0) - return r; - - /* Load entry from /etc/fstab */ - if ((r = unit_load_fstab(u)) < 0) - return r; - - /* Load drop-in directory data */ - if ((r = unit_load_dropin(u)) < 0) - return r; +static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = { + [MOUNT_DEAD] = UNIT_INACTIVE, + [MOUNT_MOUNTING] = UNIT_ACTIVATING, + [MOUNT_MOUNTED] = UNIT_ACTIVE, + [MOUNT_UNMOUNTING] = UNIT_DEACTIVATING, + [MOUNT_MAINTAINANCE] = UNIT_INACTIVE, +}; - return r; -} +static const char* const state_string_table[_MOUNT_STATE_MAX] = { + [MOUNT_DEAD] = "dead", + [MOUNT_MOUNTING] = "mounting", + [MOUNT_MOUNTED] = "mounted", + [MOUNT_UNMOUNTING] = "unmounting", + [MOUNT_MAINTAINANCE] = "maintainance" +}; static void mount_done(Unit *u) { Mount *d = MOUNT(u); @@ -40,16 +34,31 @@ static void mount_done(Unit *u) { free(d->where); } -static void mount_dump(Unit *u, FILE *f, const char *prefix) { +static void mount_set_state(Mount *m, MountState state) { + MountState old_state; + assert(m); + + old_state = m->state; + m->state = state; + + log_debug("%s changed %s → %s", unit_id(UNIT(m)), state_string_table[old_state], state_string_table[state]); + + unit_notify(UNIT(m), state_translation_table[old_state], state_translation_table[state]); +} + +static int mount_coldplug(Unit *u) { + Mount *m = MOUNT(u); + + assert(m); + assert(m->state == MOUNT_DEAD); - static const char* const state_table[_MOUNT_STATE_MAX] = { - [MOUNT_DEAD] = "dead", - [MOUNT_MOUNTING] = "mounting", - [MOUNT_MOUNTED] = "mounted", - [MOUNT_UNMOUNTING] = "unmounting", - [MOUNT_MAINTAINANCE] = "maintainance" - }; + if (m->from_proc_self_mountinfo) + mount_set_state(m, MOUNT_MOUNTED); + return 0; +} + +static void mount_dump(Unit *u, FILE *f, const char *prefix) { Mount *s = MOUNT(u); assert(s); @@ -57,10 +66,20 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) { fprintf(f, "%sMount State: %s\n" "%sWhere: %s\n" - "%sWhat: %s\n", - prefix, state_table[s->state], + "%sWhat: %s\n" + "%sFrom /etc/fstab: %s\n" + "%sFrom /proc/self/mountinfo: %s\n", + prefix, state_string_table[s->state], prefix, s->where, - prefix, s->what); + prefix, s->what, + prefix, yes_no(s->from_etc_fstab), + prefix, yes_no(s->from_proc_self_mountinfo)); +} + +static UnitActiveState mount_active_state(Unit *u) { + assert(u); + + return state_translation_table[MOUNT(u)->state]; } static void mount_shutdown(Manager *m) { @@ -136,12 +155,13 @@ static int mount_add_path_links(Mount *m) { return 0; } -static int mount_add_one(Manager *m, const char *what, const char *where) { +static int mount_add_one(Manager *m, const char *what, const char *where, bool live) { char *e; int r; Unit *u; bool delete; + assert(m); assert(what); assert(where); @@ -172,16 +192,23 @@ static int mount_add_one(Manager *m, const char *what, const char *where) { goto fail; if (!(MOUNT(u)->what = strdup(what)) || - !(MOUNT(u)->where = strdup(where)) || - !(u->meta.description = strdup(where))) { - r = -ENOMEM; + !(MOUNT(u)->where = strdup(where))) { + r = -ENOMEM; + goto fail; + } + + if ((r = unit_set_description(u, where)) < 0) goto fail; - } } else { delete = false; free(e); } + if (live) + MOUNT(u)->from_proc_self_mountinfo = true; + else + MOUNT(u)->from_etc_fstab = true; + if ((r = mount_add_node_links(MOUNT(u))) < 0) goto fail; @@ -189,6 +216,7 @@ static int mount_add_one(Manager *m, const char *what, const char *where) { goto fail; unit_add_to_load_queue(u); + return 0; fail: @@ -207,10 +235,10 @@ static char *fstab_node_to_udev_node(char *p) { if (startswith(p, "LABEL=")) { - if (!(t = strdup(p+6))) + if (!(t = xescape(p+6, "/ "))) return NULL; - r = asprintf(&dn, "/dev/disk/by-label/%s", xescape(t, "/ ")); + r = asprintf(&dn, "/dev/disk/by-label/%s", t); free(t); if (r < 0) @@ -221,10 +249,10 @@ static char *fstab_node_to_udev_node(char *p) { if (startswith(p, "UUID=")) { - if (!(t = strdup(p+5))) + if (!(t = xescape(p+5, "/ "))) return NULL; - r = asprintf(&dn, "/dev/disk/by-uuid/%s", ascii_strlower(xescape(t, "/ "))); + r = asprintf(&dn, "/dev/disk/by-uuid/%s", ascii_strlower(t)); free(t); if (r < 0) @@ -267,7 +295,7 @@ static int mount_load_etc_fstab(Manager *m) { if (where[0] == '/') path_kill_slashes(where); - r = mount_add_one(m, what, where); + r = mount_add_one(m, what, where, false); free(what); free(where); @@ -282,7 +310,7 @@ finish: return r; } -static int mount_load_proc_mounts(Manager *m) { +static int mount_load_proc_self_mountinfo(Manager *m) { FILE *f; int r; @@ -338,7 +366,7 @@ static int mount_load_proc_mounts(Manager *m) { } free(path); - r = mount_add_one(m, d, p); + r = mount_add_one(m, d, p, true); free(d); free(p); @@ -361,7 +389,7 @@ static int mount_enumerate(Manager *m) { if ((r = mount_load_etc_fstab(m)) < 0) goto fail; - if ((r = mount_load_proc_mounts(m)) < 0) + if ((r = mount_load_proc_self_mountinfo(m)) < 0) goto fail; return 0; @@ -371,28 +399,17 @@ fail: return r; } -static UnitActiveState mount_active_state(Unit *u) { - - static const UnitActiveState table[_MOUNT_STATE_MAX] = { - [MOUNT_DEAD] = UNIT_INACTIVE, - [MOUNT_MOUNTING] = UNIT_ACTIVATING, - [MOUNT_MOUNTED] = UNIT_ACTIVE, - [MOUNT_UNMOUNTING] = UNIT_DEACTIVATING, - [MOUNT_MAINTAINANCE] = UNIT_INACTIVE, - }; - - return table[MOUNT(u)->state]; -} - const UnitVTable mount_vtable = { .suffix = ".mount", - .init = mount_init, + .init = unit_load_fragment_and_dropin, .done = mount_done, + .coldplug = mount_coldplug, + .dump = mount_dump, - .enumerate = mount_enumerate, - .shutdown = mount_shutdown, + .active_state = mount_active_state, - .active_state = mount_active_state + .enumerate = mount_enumerate, + .shutdown = mount_shutdown }; diff --git a/mount.h b/mount.h index 5b5d5a38c..9a8079f48 100644 --- a/mount.h +++ b/mount.h @@ -22,6 +22,9 @@ struct Mount { MountState state; char *what, *where; + + bool from_etc_fstab:1; + bool from_proc_self_mountinfo:1; }; extern const UnitVTable mount_vtable; diff --git a/unit.c b/unit.c index 7723393db..7954c0418 100644 --- a/unit.c +++ b/unit.c @@ -170,6 +170,19 @@ int unit_choose_id(Unit *u, const char *name) { return 0; } +int unit_set_description(Unit *u, const char *description) { + char *s; + + assert(u); + + if (!(s = strdup(description))) + return -ENOMEM; + + free(u->meta.description); + u->meta.description = s; + return 0; +} + void unit_add_to_load_queue(Unit *u) { assert(u); @@ -586,7 +599,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) { else { assert(u->meta.job->state == JOB_RUNNING); - /* Let's check of this state change + /* Let's check whether this state change * constitutes a finished job, or maybe * cotradicts a running job and hence needs to * invalidate jobs. */ diff --git a/unit.h b/unit.h index 0cd09fe5a..3e42ebe90 100644 --- a/unit.h +++ b/unit.h @@ -144,6 +144,7 @@ struct UnitVTable { int (*init)(Unit *u); void (*done)(Unit *u); + int (*coldplug)(Unit *u); void (*dump)(Unit *u, FILE *f, const char *prefix); @@ -161,7 +162,14 @@ struct UnitVTable { void (*sigchld_event)(Unit *u, pid_t pid, int code, int status); void (*timer_event)(Unit *u, uint64_t n_elapsed, Watch *w); + /* This is called for each unit type and should be used to + * enumerate existing devices and load them. However, + * everything that is loaded here should still stay in + * inactive state. It is the job of the coldplug() call above + * to put the units into the initial state. */ int (*enumerate)(Manager *m); + + /* Type specific cleanups. */ void (*shutdown)(Manager *m); }; @@ -202,6 +210,7 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other); int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name); int unit_choose_id(Unit *u, const char *name); +int unit_set_description(Unit *u, const char *description); void unit_add_to_load_queue(Unit *u); -- 2.30.2