X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=device.c;h=0a7c967fabb230d280935d4c3b933b94c1491ea7;hp=25661e05f80840a579f54e1fa41f71a8050292b9;hb=c3b3c274cf7911121f84746cd80a152455f7ec97;hpb=7f275a9f1d3854cae637280048c57cca64ce89fe diff --git a/device.c b/device.c index 25661e05f..0a7c967fa 100644 --- a/device.c +++ b/device.c @@ -42,7 +42,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 +63,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_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]); } @@ -111,11 +123,56 @@ 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_escape_path(dn+1, ".device"))) + return -ENOMEM; + + u = manager_get_unit(m, e); + free(e); + + if (u) { + *_u = u; + return 1; + } + + return 0; +} + +static bool devnode_is_api(const char *node) { + unsigned i; + + static const char * const table[] = { + "/dev/null", + "/dev/zero", + "/dev/urandom", + "/dev/random", + "/dev/port", + "/dev/oldmem", + "/dev/full", + "/dev/kmsg", + "/dev/mem" + }; + + for (i = 0; i < ELEMENTSOF(table); i++) + if (streq(table[i], node)) + return true; + + return false; +} + static int device_process_new_device(Manager *m, struct udev_device *dev, bool update_state) { - const char *dn, *names, *wants, *sysfs, *expose; + 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; @@ -142,51 +199,57 @@ static int device_process_new_device(Manager *m, struct udev_device *dev, bool u if (!b) return 0; } else - if (!dn && !names && !wants) + if ((!dn || devnode_is_api(dn)) && !names && !wants) return 0; /* Ok, seems kinda interesting. Now, let's see if this one * already exists. */ - assert(sysfs[0] == '/'); - if (!(e = unit_name_escape_path(sysfs+1, ".device"))) - return -ENOMEM; + if ((r = device_find_escape_name(m, sysfs, &u)) < 0) + return r; - if (!(u = manager_get_unit(m, e))) { - const char *model; + if (r == 0 && dn) + if ((r = device_find_escape_name(m, dn, &u)) < 0) + return r; - delete = true; + 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; - if (!(u = unit_new(m))) { - free(e); - return -ENOMEM; + if (r > 0) + break; } + } + + /* FIXME: this needs proper merging */ + + assert((r > 0) == !!u); - r = unit_add_name(u, e); - free(e); + /* 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 (r < 0) + if (!u) { + delete = true; + + if (!(u = unit_new(m))) + return -ENOMEM; + + 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; @@ -196,8 +259,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; @@ -213,6 +290,8 @@ 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; @@ -391,7 +470,8 @@ fail: const UnitVTable device_vtable = { .suffix = ".device", - .init = unit_load_fragment_and_dropin_optional, + .init = device_init, + .load = unit_load_fragment_and_dropin_optional, .done = device_done, .coldplug = device_coldplug,