X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=device.c;h=f906fd50021dedc822b224bc88a7784167046de5;hp=32995fd159acbd82b936889a839b5d5e5032e22e;hb=09e80b16f2f9ee14949baee519b097a0962ff2ba;hpb=23a177ef7c8c38c238ef06666f900f581b48298f diff --git a/device.c b/device.c index 32995fd15..f906fd500 100644 --- a/device.c +++ b/device.c @@ -27,6 +27,7 @@ #include "device.h" #include "strv.h" #include "log.h" +#include "unit-name.h" static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = { [DEVICE_DEAD] = UNIT_INACTIVE, @@ -42,7 +43,18 @@ static void device_done(Unit *u) { Device *d = DEVICE(u); assert(d); + free(d->sysfs); + d->sysfs = NULL; +} + +static void device_init(Unit *u) { + Device *d = DEVICE(u); + + assert(d); + assert(u->meta.load_state == UNIT_STUB); + + d->state = 0; } static void device_set_state(Device *d, DeviceState state) { @@ -52,7 +64,8 @@ static void device_set_state(Device *d, DeviceState state) { 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]); + if (state != old_state) + log_debug("%s changed %s → %s", UNIT(d)->meta.id, state_string_table[old_state], state_string_table[state]); unit_notify(UNIT(d), state_translation_table[old_state], state_translation_table[state]); } @@ -87,6 +100,12 @@ static UnitActiveState device_active_state(Unit *u) { return state_translation_table[DEVICE(u)->state]; } +static const char *device_sub_state_to_string(Unit *u) { + assert(u); + + return state_string_table[DEVICE(u)->state]; +} + static int device_add_escaped_name(Unit *u, const char *dn, bool make_id) { char *e; int r; @@ -95,7 +114,7 @@ static int device_add_escaped_name(Unit *u, const char *dn, bool make_id) { assert(dn); assert(dn[0] == '/'); - if (!(e = unit_name_escape_path(dn+1, ".device"))) + if (!(e = unit_name_build_escape(dn+1, NULL, ".device"))) return -ENOMEM; r = unit_add_name(u, e); @@ -111,70 +130,105 @@ static int device_add_escaped_name(Unit *u, const char *dn, bool make_id) { return 0; } +static int device_find_escape_name(Manager *m, const char *dn, Unit **_u) { + char *e; + Unit *u; + + assert(m); + assert(dn); + assert(dn[0] == '/'); + assert(_u); + + if (!(e = unit_name_build_escape(dn+1, NULL, ".device"))) + return -ENOMEM; + + u = manager_get_unit(m, e); + free(e); + + if (u) { + *_u = u; + return 1; + } + + return 0; +} + static int device_process_new_device(Manager *m, struct udev_device *dev, bool update_state) { - const char *dn, *names, *wants, *sysfs; + const char *dn, *names, *wants, *sysfs, *expose, *model; Unit *u = NULL; int r; - char *e, *w, *state; + char *w, *state; size_t l; bool delete; struct udev_list_entry *item = NULL, *first = NULL; + int b; assert(m); + if (!(sysfs = udev_device_get_syspath(dev))) + return -ENOMEM; + + if (!(expose = udev_device_get_property_value(dev, "SYSTEMD_EXPOSE"))) + return 0; + + if ((b = parse_boolean(expose)) < 0) { + log_error("Failed to parse SYSTEMD_EXPOSE udev property for device %s: %s", sysfs, expose); + return 0; + } + + if (!b) + return 0; + /* Check whether this entry is even relevant for us. */ dn = udev_device_get_devnode(dev); names = udev_device_get_property_value(dev, "SYSTEMD_NAMES"); wants = udev_device_get_property_value(dev, "SYSTEMD_WANTS"); - if (!dn && !names && !wants) - return 0; + if ((r = device_find_escape_name(m, sysfs, &u)) < 0) + return r; - /* Ok, seems kinda interesting. Now, let's see if this one - * already exists. */ + if (r == 0 && dn) + if ((r = device_find_escape_name(m, dn, &u)) < 0) + return r; - if (!(sysfs = udev_device_get_syspath(dev))) - return -ENOMEM; + if (r == 0) { + first = udev_device_get_devlinks_list_entry(dev); + udev_list_entry_foreach(item, first) { + if ((r = device_find_escape_name(m, udev_list_entry_get_name(item), &u)) < 0) + return r; - assert(sysfs[0] == '/'); - if (!(e = unit_name_escape_path(sysfs+1, ".device"))) - return -ENOMEM; + if (r > 0) + break; + } + } + + /* FIXME: this needs proper merging */ - if (!(u = manager_get_unit(m, e))) { - const char *model; + assert((r > 0) == !!u); + /* If this is a different unit, then let's not merge things */ + if (u && DEVICE(u)->sysfs && !streq(DEVICE(u)->sysfs, sysfs)) + u = NULL; + + if (!u) { delete = true; - if (!(u = unit_new(m))) { - free(e); + if (!(u = unit_new(m))) return -ENOMEM; - } - - r = unit_add_name(u, e); - free(e); - if (r < 0) + if ((r = device_add_escaped_name(u, sysfs, true)) < 0) goto fail; + unit_add_to_load_queue(u); + } else + delete = false; + + if (!(DEVICE(u)->sysfs)) if (!(DEVICE(u)->sysfs = strdup(sysfs))) { r = -ENOMEM; goto fail; } - if ((model = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE")) || - (model = udev_device_get_property_value(dev, "ID_MODEL"))) { - if ((r = unit_set_description(u, model)) < 0) - goto fail; - } else if (dn) - if ((r = unit_set_description(u, dn)) < 0) - goto fail; - - unit_add_to_load_queue(u); - } else { - delete = false; - free(e); - } - if (dn) if ((r = device_add_escaped_name(u, dn, true)) < 0) goto fail; @@ -184,8 +238,22 @@ static int device_process_new_device(Manager *m, struct udev_device *dev, bool u if ((r = device_add_escaped_name(u, udev_list_entry_get_name(item), false)) < 0) goto fail; + if ((model = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE")) || + (model = udev_device_get_property_value(dev, "ID_MODEL"))) { + if ((r = unit_set_description(u, model)) < 0) + goto fail; + } else if (dn) + if ((r = unit_set_description(u, dn)) < 0) + goto fail; + + /* We don't remove names that are gone. But that should be + * fine and should probably be fixed only on a configuration + * refresh. */ + if (names) { FOREACH_WORD(w, l, names, state) { + char *e; + if (!(e = strndup(w, l))) { r = -ENOMEM; goto fail; @@ -201,12 +269,14 @@ static int device_process_new_device(Manager *m, struct udev_device *dev, bool u if (wants) { FOREACH_WORD(w, l, wants, state) { + char *e; + if (!(e = strndup(w, l))) { r = -ENOMEM; goto fail; } - r = unit_add_dependency_by_name(u, UNIT_WANTS, e); + r = unit_add_dependency_by_name(u, UNIT_WANTS, NULL, e); free(e); if (r < 0) @@ -259,7 +329,7 @@ static int device_process_removed_device(Manager *m, struct udev_device *dev) { return -ENOMEM; assert(sysfs[0] == '/'); - if (!(e = unit_name_escape_path(sysfs+1, ".device"))) + if (!(e = unit_name_build_escape(sysfs+1, NULL, ".device"))) return -ENOMEM; u = manager_get_unit(m, e); @@ -350,8 +420,6 @@ void device_fd_event(Manager *m, int events) { assert(m); assert(events == EPOLLIN); - log_debug("got udev event"); - if (!(dev = udev_monitor_receive_device(m->udev_monitor))) { log_error("Failed to receive device."); return; @@ -381,13 +449,18 @@ fail: const UnitVTable device_vtable = { .suffix = ".device", - .init = unit_load_fragment_and_dropin_optional, + .no_requires = true, + .no_instances = true, + + .init = device_init, + .load = unit_load_fragment_and_dropin_optional, .done = device_done, .coldplug = device_coldplug, .dump = device_dump, .active_state = device_active_state, + .sub_state_to_string = device_sub_state_to_string, .enumerate = device_enumerate, .shutdown = device_shutdown