diff --git a/udev_device.c b/udev_device.c index 86d1e983..8eb8c0a1 100644 --- a/udev_device.c +++ b/udev_device.c @@ -47,8 +47,8 @@ #endif struct udev_device { - struct udev_list_entry properties; - struct udev_list_entry sysattrs; + struct udev_list_table *properties; + struct udev_list_table *sysattrs; struct udev_device *parent; struct udev *udev; int refcount; @@ -214,7 +214,7 @@ const char *udev_device_get_action(struct udev_device *udev_device) struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device) { - return udev_device ? udev_list_entry_get_next(&udev_device->properties) : NULL; + return udev_device ? udev_list_table_get_head(udev_device->properties) : NULL; } /* XXX NOT IMPLEMENTED */ struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device) @@ -224,16 +224,24 @@ struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device) { - return udev_device ? udev_list_entry_get_next(&udev_device->sysattrs) : NULL; + return udev_device ? udev_list_table_get_head(udev_device->sysattrs) : NULL; } const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key) { + struct udev_list_entry *list_entry; + if (!udev_device || !key) { return NULL; } - return udev_list_entry_get_value(udev_list_entry_get_by_name(&udev_device->properties, key)); + list_entry = udev_list_table_get_head(udev_device->properties); + + if (!list_entry) { + return NULL; + } + + return udev_list_entry_get_value(udev_list_entry_get_by_name(list_entry, key)); } const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr) @@ -248,10 +256,14 @@ const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const return NULL; } - list_entry = udev_list_entry_get_by_name(&udev_device->sysattrs, sysattr); + list_entry = udev_list_table_get_head(udev_device->sysattrs); if (list_entry) { - return udev_list_entry_get_value(list_entry); + list_entry = udev_list_entry_get_by_name(list_entry, sysattr); + + if (list_entry) { + return udev_list_entry_get_value(list_entry); + } } snprintf(path, sizeof(path), "%s/%s", udev_device_get_syspath(udev_device), sysattr); @@ -281,7 +293,7 @@ const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const data[len] = '\0'; } - list_entry = udev_list_entry_add(&udev_device->sysattrs, sysattr, data, 0); + list_entry = udev_list_entry_add(udev_device->sysattrs, sysattr, data); return udev_list_entry_get_value(list_entry); } @@ -316,8 +328,7 @@ int udev_device_set_sysattr_value(struct udev_device *udev_device, const char *s } fclose(file); - udev_list_entry_add(&udev_device->sysattrs, sysattr, value, 1); - return 0; + return !!udev_list_entry_add(udev_device->sysattrs, sysattr, value) - 1; } static char *read_symlink(const char *syspath, const char *name) @@ -354,11 +365,11 @@ static void set_properties_from_uevent(struct udev_device *udev_device) if (strncmp(line, "DEVNAME=", 8) == 0) { snprintf(devnode, sizeof(devnode), "/dev/%s", line + 8); - udev_list_entry_add(&udev_device->properties, "DEVNAME", devnode, 0); + udev_list_entry_add(udev_device->properties, "DEVNAME", devnode); } else if ((pos = strchr(line, '='))) { *pos = '\0'; - udev_list_entry_add(&udev_device->properties, line, pos + 1, 1); + udev_list_entry_add(udev_device->properties, line, pos + 1); } } @@ -430,53 +441,53 @@ static void set_properties_from_evdev(struct udev_device *udev_device) make_bit(key_bits, sizeof(key_bits) / sizeof(key_bits[0]), udev_device_get_property_value(parent, "KEY")); make_bit(prop_bits, sizeof(prop_bits) / sizeof(prop_bits[0]), udev_device_get_property_value(parent, "PROP")); - udev_list_entry_add(&udev_device->properties, "ID_INPUT", "1", 0); + udev_list_entry_add(udev_device->properties, "ID_INPUT", "1"); if (test_bit(prop_bits, INPUT_PROP_POINTING_STICK)) { - udev_list_entry_add(&udev_device->properties, "ID_INPUT_POINTINGSTICK", "1", 0); + udev_list_entry_add(udev_device->properties, "ID_INPUT_POINTINGSTICK", "1"); } if (test_bit(prop_bits, INPUT_PROP_ACCELEROMETER)) { - udev_list_entry_add(&udev_device->properties, "ID_INPUT_ACCELEROMETER", "1", 0); + udev_list_entry_add(udev_device->properties, "ID_INPUT_ACCELEROMETER", "1"); } if (test_bit(ev_bits, EV_SW)) { - udev_list_entry_add(&udev_device->properties, "ID_INPUT_SWITCH", "1", 0); + udev_list_entry_add(udev_device->properties, "ID_INPUT_SWITCH", "1"); } if (test_bit(ev_bits, EV_REL)) { if (test_bit(rel_bits, REL_Y) && test_bit(rel_bits, REL_X) && test_bit(key_bits, BTN_MOUSE)) { - udev_list_entry_add(&udev_device->properties, "ID_INPUT_MOUSE", "1", 0); + udev_list_entry_add(udev_device->properties, "ID_INPUT_MOUSE", "1"); } } else if (test_bit(ev_bits, EV_ABS)) { if (test_bit(key_bits, BTN_SELECT) || test_bit(key_bits, BTN_TR) || test_bit(key_bits, BTN_START) || test_bit(key_bits, BTN_TL)) { if (test_bit(key_bits, BTN_TOUCH)) { - udev_list_entry_add(&udev_device->properties, "ID_INPUT_TOUCHSCREEN", "1", 0); + udev_list_entry_add(udev_device->properties, "ID_INPUT_TOUCHSCREEN", "1"); } else { - udev_list_entry_add(&udev_device->properties, "ID_INPUT_JOYSTICK", "1", 0); + udev_list_entry_add(udev_device->properties, "ID_INPUT_JOYSTICK", "1"); } } else if (test_bit(abs_bits, ABS_Y) && test_bit(abs_bits, ABS_X)) { if (test_bit(abs_bits, ABS_Z) && !test_bit(ev_bits, EV_KEY)) { - udev_list_entry_add(&udev_device->properties, "ID_INPUT_ACCELEROMETER", "1", 0); + udev_list_entry_add(udev_device->properties, "ID_INPUT_ACCELEROMETER", "1"); } else if (test_bit(key_bits, BTN_STYLUS) || test_bit(key_bits, BTN_TOOL_PEN)) { - udev_list_entry_add(&udev_device->properties, "ID_INPUT_TABLET", "1", 0); + udev_list_entry_add(udev_device->properties, "ID_INPUT_TABLET", "1"); } else if (test_bit(key_bits, BTN_TOUCH)) { if (test_bit(key_bits, BTN_TOOL_FINGER)) { - udev_list_entry_add(&udev_device->properties, "ID_INPUT_TOUCHPAD", "1", 0); + udev_list_entry_add(udev_device->properties, "ID_INPUT_TOUCHPAD", "1"); } else { - udev_list_entry_add(&udev_device->properties, "ID_INPUT_TOUCHSCREEN", "1", 0); + udev_list_entry_add(udev_device->properties, "ID_INPUT_TOUCHSCREEN", "1"); } } else if (test_bit(key_bits, BTN_MOUSE)) { - udev_list_entry_add(&udev_device->properties, "ID_INPUT_MOUSE", "1", 0); + udev_list_entry_add(udev_device->properties, "ID_INPUT_MOUSE", "1"); } } } @@ -493,10 +504,10 @@ static void set_properties_from_evdev(struct udev_device *udev_device) continue; } - udev_list_entry_add(&udev_device->properties, "ID_INPUT_KEY", "1", 0); + udev_list_entry_add(udev_device->properties, "ID_INPUT_KEY", "1"); if (test_bit(key_bits, KEY_ENTER)) { - udev_list_entry_add(&udev_device->properties, "ID_INPUT_KEYBOARD", "1", 0); + udev_list_entry_add(udev_device->properties, "ID_INPUT_KEYBOARD", "1"); } return; @@ -523,7 +534,7 @@ static void set_properties_from_props(struct udev_device *udev_device) } snprintf(id, sizeof(id), "pci-%s", sysname); - udev_list_entry_add(&udev_device->properties, "ID_PATH", id, 0); + udev_list_entry_add(udev_device->properties, "ID_PATH", id); } struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath) @@ -557,23 +568,35 @@ struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char * udev_device->refcount = 1; udev_device->parent = NULL; - udev_list_entry_init(&udev_device->properties); - udev_list_entry_init(&udev_device->sysattrs); + udev_device->properties = udev_list_table_init(50, strcmp); + + if (!udev_device->properties) { + free(udev_device); + return NULL; + } - udev_list_entry_add(&udev_device->properties, "SYSPATH", path, 0); - udev_list_entry_add(&udev_device->properties, "DEVPATH", path + 4, 0); + udev_device->sysattrs = udev_list_table_init(10, strcmp); + + if (!udev_device->sysattrs) { + udev_list_table_deinit(udev_device->properties); + free(udev_device); + return NULL; + } + + udev_list_entry_add(udev_device->properties, "SYSPATH", path); + udev_list_entry_add(udev_device->properties, "DEVPATH", path + 4); sysname = strrchr(path, '/') + 1; driver = read_symlink(path, "driver"); subsystem = read_symlink(path, "subsystem"); - udev_list_entry_add(&udev_device->properties, "SUBSYSTEM", subsystem, 0); - udev_list_entry_add(&udev_device->properties, "SYSNAME", sysname, 0); - udev_list_entry_add(&udev_device->properties, "DRIVER", driver, 0); + udev_list_entry_add(udev_device->properties, "SUBSYSTEM", subsystem); + udev_list_entry_add(udev_device->properties, "SYSNAME", sysname); + udev_list_entry_add(udev_device->properties, "DRIVER", driver); for (i = 0; sysname[i] != '\0'; i++) { if (sysname[i] >= '0' && sysname[i] <= '9') { - udev_list_entry_add(&udev_device->properties, "SYSNUM", sysname + i, 0); + udev_list_entry_add(udev_device->properties, "SYSNUM", sysname + i); break; } } @@ -653,8 +676,7 @@ struct udev_device *udev_device_new_from_file(struct udev *udev, const char *pat udev_device = calloc(1, sizeof(struct udev_device)); if (!udev_device) { - fclose(file); - return NULL; + goto close_file; } cnt = 0; @@ -663,23 +685,32 @@ struct udev_device *udev_device_new_from_file(struct udev *udev, const char *pat udev_device->refcount = 1; udev_device->parent = NULL; - udev_list_entry_init(&udev_device->properties); - udev_list_entry_init(&udev_device->sysattrs); + udev_device->properties = udev_list_table_init(50, strcmp); + + if (!udev_device->properties) { + goto free_device; + } + + udev_device->sysattrs = udev_list_table_init(10, strcmp); + + if (!udev_device->sysattrs) { + goto deinit_properties; + } while (fgets(line, sizeof(line), file)) { line[strlen(line) - 1] = '\0'; if (strncmp(line, "DEVPATH=", 8) == 0) { snprintf(syspath, sizeof(syspath), "/sys%s", line + 8); - udev_list_entry_add(&udev_device->properties, "SYSPATH", syspath, 0); - udev_list_entry_add(&udev_device->properties, "DEVPATH", line + 8, 0); + udev_list_entry_add(udev_device->properties, "SYSPATH", syspath); + udev_list_entry_add(udev_device->properties, "DEVPATH", line + 8); sysname = strrchr(syspath, '/') + 1; - udev_list_entry_add(&udev_device->properties, "SYSNAME", sysname, 0); + udev_list_entry_add(udev_device->properties, "SYSNAME", sysname); for (i = 0; sysname[i] != '\0'; i++) { if (sysname[i] >= '0' && sysname[i] <= '9') { - udev_list_entry_add(&udev_device->properties, "SYSNUM", sysname + i, 0); + udev_list_entry_add(udev_device->properties, "SYSNUM", sysname + i); break; } } @@ -688,7 +719,7 @@ struct udev_device *udev_device_new_from_file(struct udev *udev, const char *pat } else if (strncmp(line, "DEVNAME=", 8) == 0) { snprintf(devnode, sizeof(devnode), "/dev/%s", line + 8); - udev_list_entry_add(&udev_device->properties, "DEVNAME", devnode, 0); + udev_list_entry_add(udev_device->properties, "DEVNAME", devnode); } else { pos = strchr(line, '='); @@ -707,7 +738,7 @@ struct udev_device *udev_device_new_from_file(struct udev *udev, const char *pat cnt++; } - udev_list_entry_add(&udev_device->properties, line, pos + 1, 0); + udev_list_entry_add(udev_device->properties, line, pos + 1); } } @@ -723,6 +754,16 @@ struct udev_device *udev_device_new_from_file(struct udev *udev, const char *pat set_properties_from_props(udev_device); set_properties_from_evdev(udev_device); return udev_device; + +deinit_properties: + udev_list_table_deinit(udev_device->properties); + +free_device: + free(udev_device); + +close_file: + fclose(file); + return NULL; } /* XXX NOT IMPLEMENTED */ struct udev_device *udev_device_new_from_device_id(struct udev *udev, const char *id) @@ -759,8 +800,8 @@ struct udev_device *udev_device_unref(struct udev_device *udev_device) udev_device_unref(udev_device->parent); } - udev_list_entry_free_all(&udev_device->properties); - udev_list_entry_free_all(&udev_device->sysattrs); + udev_list_table_deinit(udev_device->properties); + udev_list_table_deinit(udev_device->sysattrs); free(udev_device); return NULL; diff --git a/udev_enumerate.c b/udev_enumerate.c index 6f026108..7c64599d 100644 --- a/udev_enumerate.c +++ b/udev_enumerate.c @@ -27,13 +27,13 @@ #include "udev_list.h" struct udev_enumerate { - struct udev_list_entry subsystem_nomatch; - struct udev_list_entry subsystem_match; - struct udev_list_entry sysattr_nomatch; - struct udev_list_entry property_match; - struct udev_list_entry sysattr_match; - struct udev_list_entry sysname_match; - struct udev_list_entry devices; + struct udev_list_table *subsystem_nomatch; + struct udev_list_table *subsystem_match; + struct udev_list_table *sysattr_nomatch; + struct udev_list_table *property_match; + struct udev_list_table *sysattr_match; + struct udev_list_table *sysname_match; + struct udev_list_table *devices; struct udev *udev; int refcount; }; @@ -47,32 +47,32 @@ struct udev_enumerate_thread { int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) { - return udev_enumerate ? !!udev_list_entry_add(&udev_enumerate->subsystem_match, subsystem, NULL, 0) - 1 : -1; + return udev_enumerate ? !!udev_list_entry_add(udev_enumerate->subsystem_match, subsystem, NULL) - 1 : -1; } int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) { - return udev_enumerate ? !!udev_list_entry_add(&udev_enumerate->subsystem_nomatch, subsystem, NULL, 0) - 1 : -1; + return udev_enumerate ? !!udev_list_entry_add(udev_enumerate->subsystem_nomatch, subsystem, NULL) - 1 : -1; } int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) { - return udev_enumerate ? !!udev_list_entry_add(&udev_enumerate->sysattr_match, sysattr, value, 0) - 1 : -1; + return udev_enumerate ? !!udev_list_entry_add(udev_enumerate->sysattr_match, sysattr, value) - 1 : -1; } int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) { - return udev_enumerate ? !!udev_list_entry_add(&udev_enumerate->sysattr_nomatch, sysattr, value, 0) - 1 : -1; + return udev_enumerate ? !!udev_list_entry_add(udev_enumerate->sysattr_nomatch, sysattr, value) - 1 : -1; } int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value) { - return udev_enumerate ? !!udev_list_entry_add(&udev_enumerate->property_match, property, value, 0) - 1 : -1; + return udev_enumerate ? !!udev_list_entry_add(udev_enumerate->property_match, property, value) - 1 : -1; } int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname) { - return udev_enumerate ? !!udev_list_entry_add(&udev_enumerate->sysname_match, sysname, NULL, 0) - 1 : -1; + return udev_enumerate ? !!udev_list_entry_add(udev_enumerate->sysname_match, sysname, NULL) - 1 : -1; } /* XXX NOT IMPLEMENTED */ int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag) @@ -96,98 +96,78 @@ static int filter_subsystem(struct udev_enumerate *udev_enumerate, struct udev_d const char *subsystem; subsystem = udev_device_get_subsystem(udev_device); - list_entry = udev_list_entry_get_next(&udev_enumerate->subsystem_nomatch); if (!subsystem) { return 0; } - while (list_entry) { - if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0) { - return 0; - } + list_entry = udev_list_table_get_head(udev_enumerate->subsystem_nomatch); - list_entry = udev_list_entry_get_next(list_entry); + if (udev_list_entry_get_by_name(list_entry, subsystem)) { + return 0; } - list_entry = udev_list_entry_get_next(&udev_enumerate->subsystem_match); - - if (list_entry) { - while (list_entry) { - if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0) { - return 1; - } - - list_entry = udev_list_entry_get_next(list_entry); - } + list_entry = udev_list_table_get_head(udev_enumerate->subsystem_match); + if (!list_entry) { return 0; } - return 1; + return !!udev_list_entry_get_by_name(list_entry, subsystem); } static int filter_sysname(struct udev_enumerate *udev_enumerate, struct udev_device *udev_device) { struct udev_list_entry *list_entry; - const char *sysname; - sysname = udev_device_get_sysname(udev_device); - list_entry = udev_list_entry_get_next(&udev_enumerate->sysname_match); + list_entry = udev_list_table_get_head(udev_enumerate->sysname_match); if (!list_entry) { return 1; } - while (list_entry) { - if (fnmatch(udev_list_entry_get_name(list_entry), sysname, 0) == 0) { - return 1; - } - - list_entry = udev_list_entry_get_next(list_entry); - } + return !!udev_list_entry_get_by_name(list_entry, udev_device_get_sysname(udev_device)); +} - return 0; +static int strmatch(const char *pat, const char *str) +{ + return fnmatch(pat, str, 0); } static int filter_property(struct udev_enumerate *udev_enumerate, struct udev_device *udev_device) { - const char *property, *property2, *value, *value2; - struct udev_list_entry *list_entry, *list_entry2; + struct udev_list_entry *list_entry_match, *list_entry_properties, *list_entry_by_name; + const char *property, *value, *value_by_name; - list_entry = udev_list_entry_get_next(&udev_enumerate->property_match); + list_entry_match = udev_list_table_get_head(udev_enumerate->property_match); - if (!list_entry) { + if (!list_entry_match) { return 1; } - while (list_entry) { - property = udev_list_entry_get_name(list_entry); - value = udev_list_entry_get_value(list_entry); + list_entry_properties = udev_device_get_properties_list_entry(udev_device); - list_entry2 = udev_device_get_properties_list_entry(udev_device); + if (!list_entry_properties) { + return 0; + } - if (!list_entry2) { - return 0; - } + while (list_entry_properties) { + property = udev_list_entry_get_name(list_entry_properties); + value = udev_list_entry_get_value(list_entry_properties); - while (list_entry2) { - property2 = udev_list_entry_get_name(list_entry2); - value2 = udev_list_entry_get_value(list_entry2); + list_entry_by_name = udev_list_entry_get_by_name(list_entry_match, property); - if (!value || !value2) { - continue; - } + if (list_entry_by_name) { + value_by_name = udev_list_entry_get_value(list_entry_by_name); - if (fnmatch(property, property2, 0) == 0 && - fnmatch(value, value2, 0) == 0) { - return 1; + if (value_by_name && value) { + if (strmatch(value_by_name, value) == 0) { + return 1; + } } - - list_entry2 = udev_list_entry_get_next(list_entry2); } - list_entry = udev_list_entry_get_next(list_entry); + list_entry_properties = udev_list_entry_get_next(list_entry_properties); } return 0; @@ -198,7 +178,7 @@ static int filter_sysattr(struct udev_enumerate *udev_enumerate, struct udev_dev struct udev_list_entry *list_entry; const char *sysattr, *value; - list_entry = udev_list_entry_get_next(&udev_enumerate->sysattr_nomatch); + list_entry = udev_list_table_get_head(udev_enumerate->sysattr_nomatch); while (list_entry) { sysattr = udev_list_entry_get_name(list_entry); @@ -208,35 +188,35 @@ static int filter_sysattr(struct udev_enumerate *udev_enumerate, struct udev_dev return 1; } - if (fnmatch(udev_list_entry_get_value(list_entry), value, 0) == 0) { + if (strmatch(udev_list_entry_get_value(list_entry), value) == 0) { return 0; } list_entry = udev_list_entry_get_next(list_entry); } - list_entry = udev_list_entry_get_next(&udev_enumerate->sysattr_match); + list_entry = udev_list_table_get_head(udev_enumerate->sysattr_match); - if (list_entry) { - while (list_entry) { - sysattr = udev_list_entry_get_name(list_entry); - value = udev_device_get_sysattr_value(udev_device, sysattr); + if (!list_entry) { + return 1; + } - if (!value) { - return 0; - } + while (list_entry) { + sysattr = udev_list_entry_get_name(list_entry); + value = udev_device_get_sysattr_value(udev_device, sysattr); - if (fnmatch(udev_list_entry_get_value(list_entry), value, 0) == 0) { - return 1; - } + if (!value) { + return 0; + } - list_entry = udev_list_entry_get_next(list_entry); + if (strmatch(udev_list_entry_get_value(list_entry), value) == 0) { + return 1; } - return 0; + list_entry = udev_list_entry_get_next(list_entry); } - return 1; + return 0; } static void *add_device(void *ptr) @@ -259,7 +239,7 @@ static void *add_device(void *ptr) } pthread_mutex_lock(thread->mutex); - udev_list_entry_add(&thread->udev_enumerate->devices, udev_device_get_syspath(udev_device), NULL, 0); + udev_list_entry_add(thread->udev_enumerate->devices, udev_device_get_syspath(udev_device), NULL); pthread_mutex_unlock(thread->mutex); udev_device_unref(udev_device); @@ -347,7 +327,7 @@ int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate) struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate) { - return udev_enumerate ? udev_list_entry_get_next(&udev_enumerate->devices) : NULL; + return udev_enumerate ? udev_list_table_get_head(udev_enumerate->devices) : NULL; } /* XXX NOT IMPLEMENTED */ int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath) @@ -377,15 +357,71 @@ struct udev_enumerate *udev_enumerate_new(struct udev *udev) udev_enumerate->refcount = 1; udev_enumerate->udev = udev; - udev_list_entry_init(&udev_enumerate->subsystem_nomatch); - udev_list_entry_init(&udev_enumerate->subsystem_match); - udev_list_entry_init(&udev_enumerate->sysattr_nomatch); - udev_list_entry_init(&udev_enumerate->property_match); - udev_list_entry_init(&udev_enumerate->sysattr_match); - udev_list_entry_init(&udev_enumerate->sysname_match); - udev_list_entry_init(&udev_enumerate->devices); + udev_enumerate->subsystem_nomatch = udev_list_table_init(10, strmatch); + + if (!udev_enumerate->subsystem_nomatch) { + goto free_enumerate; + } + + udev_enumerate->subsystem_match = udev_list_table_init(10, strmatch); + + if (!udev_enumerate->subsystem_match) { + goto deinit_subsystem_nomatch; + } + + udev_enumerate->sysattr_nomatch = udev_list_table_init(10, strmatch); + + if (!udev_enumerate->sysattr_nomatch) { + goto deinit_subsystem_match; + } + + udev_enumerate->property_match = udev_list_table_init(10, strmatch); + + if (!udev_enumerate->property_match) { + goto deinit_sysattr_nomatch; + } + + udev_enumerate->sysattr_match = udev_list_table_init(10, strmatch); + + if (!udev_enumerate->sysattr_match) { + goto deinit_property_match; + } + + udev_enumerate->sysname_match = udev_list_table_init(10, strmatch); + + if (!udev_enumerate->sysname_match) { + goto deinit_sysattr_match; + } + + udev_enumerate->devices = udev_list_table_init(100, strcmp); + + if (!udev_enumerate->devices) { + goto deinit_sysname_match; + } return udev_enumerate; + +deinit_sysname_match: + udev_list_table_deinit(udev_enumerate->sysname_match); + +deinit_sysattr_match: + udev_list_table_deinit(udev_enumerate->sysattr_match); + +deinit_property_match: + udev_list_table_deinit(udev_enumerate->property_match); + +deinit_sysattr_nomatch: + udev_list_table_deinit(udev_enumerate->sysattr_nomatch); + +deinit_subsystem_match: + udev_list_table_deinit(udev_enumerate->subsystem_match); + +deinit_subsystem_nomatch: + udev_list_table_deinit(udev_enumerate->subsystem_nomatch); + +free_enumerate: + free(udev_enumerate); + return NULL; } struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate) @@ -408,13 +444,13 @@ struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerat return NULL; } - udev_list_entry_free_all(&udev_enumerate->subsystem_nomatch); - udev_list_entry_free_all(&udev_enumerate->subsystem_match); - udev_list_entry_free_all(&udev_enumerate->sysattr_nomatch); - udev_list_entry_free_all(&udev_enumerate->property_match); - udev_list_entry_free_all(&udev_enumerate->sysattr_match); - udev_list_entry_free_all(&udev_enumerate->sysname_match); - udev_list_entry_free_all(&udev_enumerate->devices); + udev_list_table_deinit(udev_enumerate->subsystem_nomatch); + udev_list_table_deinit(udev_enumerate->subsystem_match); + udev_list_table_deinit(udev_enumerate->sysattr_nomatch); + udev_list_table_deinit(udev_enumerate->property_match); + udev_list_table_deinit(udev_enumerate->sysattr_match); + udev_list_table_deinit(udev_enumerate->sysname_match); + udev_list_table_deinit(udev_enumerate->devices); free(udev_enumerate); return NULL; diff --git a/udev_list.c b/udev_list.c index a41ec43e..808c2a79 100644 --- a/udev_list.c +++ b/udev_list.c @@ -15,83 +15,242 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include #include #include "udev.h" #include "udev_list.h" -void udev_list_entry_init(struct udev_list_entry *list_entry) +struct udev_list_table { + int (*cmp)(const char *, const char *); + struct udev_list_entry **entries; + struct udev_list_entry *head; + size_t cap; + size_t len; +}; + +struct udev_list_entry { + struct udev_list_table *list_table; + struct udev_list_entry *next; + uint64_t sum; + char *value; + char *name; +}; + +void udev_list_table_deinit(struct udev_list_table *list_table) { - list_entry->value = NULL; - list_entry->name = NULL; - list_entry->next = NULL; + struct udev_list_entry *list_entry; + size_t i; + + // TODO iterate over linked list? + for (i = 0; i < list_table->cap; i++) { + list_entry = list_table->entries[i]; + + if (!list_entry) { + continue; + } + + free(list_entry->value); + free(list_entry->name); + free(list_entry); + } + + free(list_table->entries); + free(list_table); } -void udev_list_entry_free(struct udev_list_entry *list_entry) +struct udev_list_table *udev_list_table_init(size_t cap, int (*cmp)(const char *, const char *)) { - free(list_entry->value); - free(list_entry->name); - free(list_entry); + struct udev_list_table *list_table; + + list_table = calloc(1, sizeof(struct udev_list_table)); + + if (!list_table) { + return NULL; + } + + list_table->entries = calloc(cap, sizeof(struct udev_list_entry *)); + + if (!list_table->entries) { + return NULL; + } + + list_table->cmp = cmp; + list_table->cap = cap; + list_table->len = 0; + return list_table; } -void udev_list_entry_free_all(struct udev_list_entry *list_entry) +static uint64_t hash_murmur64a(const char *str) { - struct udev_list_entry *list_entry2 = list_entry->next; + const uint64_t seed = 0x3a1ddf174ff104c3; + const uint64_t m = 0xc6a4a7935bd1e995; + const uint64_t *data, *end; + const unsigned char *data2; + const int r = 47; + uint64_t h, k; + size_t len; + + len = strlen(str); + h = seed ^ (len * m); + data = (const uint64_t *)str; + end = data + (len / 8); + + while (data != end) { + k = *data++; + + k *= m; + k ^= k >> r; + k *= m; - while (list_entry2) { - list_entry = list_entry2; - list_entry2 = list_entry->next; - udev_list_entry_free(list_entry); + h ^= k; + h *= m; } + + data2 = (const unsigned char *)data; + + switch (len & 0x7) { + case 7: h ^= (uint64_t)data2[6] << 48; + // fallthrough + case 6: h ^= (uint64_t)data2[5] << 40; + // fallthrough + case 5: h ^= (uint64_t)data2[4] << 32; + // fallthrough + case 4: h ^= (uint64_t)data2[3] << 24; + // fallthrough + case 3: h ^= (uint64_t)data2[2] << 16; + // fallthrough + case 2: h ^= (uint64_t)data2[1] << 8; + // fallthrough + case 1: h ^= (uint64_t)data2[0]; + h *= m; + } + + h ^= h >> r; + h *= m; + h ^= h >> r; + + return h; } -struct udev_list_entry *udev_list_entry_add(struct udev_list_entry *list_entry, const char *name, const char *value, int uniq) +static int udev_list_table_expand(struct udev_list_table *list_table) { - struct udev_list_entry *list_entry2; + struct udev_list_entry *list_entry; + struct udev_list_entry **entries; + size_t cap, i, j; - if (uniq) { - list_entry2 = udev_list_entry_get_by_name(list_entry, name); + cap = list_table->cap * 2; - if (list_entry2 && value) { - if (list_entry2->value && strcmp(list_entry2->value, value) == 0) { - return list_entry2; - } + // TODO cap overflow check + + entries = calloc(cap, sizeof(struct udev_list_entry *)); + + if (!entries) { + return 0; + } + + // TODO iterate over linked list? + for (i = 0; i < list_table->cap; i++) { + list_entry = list_table->entries[i]; - free(list_entry2->value); - list_entry2->value = strdup(value); + if (!list_entry) { + continue; + } - if (!list_entry2->value) { - return NULL; + // TODO ensure that endless loop is not possible + for (j = list_entry->sum % cap; entries[j]; j++) { + if (j == cap) { + j = 0; } + } - return list_entry2; + entries[j] = list_entry; + } + + free(list_table->entries); + list_table->entries = entries; + list_table->cap = cap; + return 1; +} + +struct udev_list_entry *udev_list_entry_add(struct udev_list_table *list_table, const char *name, const char *value) +{ + struct udev_list_entry *list_entry; + uint64_t sum; + char *val; + size_t i; + + if (list_table->len > list_table->cap / 2) { + if (!udev_list_table_expand(list_table)) { + return NULL; } } - list_entry2 = calloc(1, sizeof(struct udev_list_entry)); + sum = hash_murmur64a(name); + + for (i = sum % list_table->cap; list_table->entries[i]; i++) { + if (i == list_table->cap) { + i = 0; + continue; + } + + list_entry = list_table->entries[i]; + + // TODO compare sum? + if (list_table->cmp(list_entry->name, name) != 0) { + continue; + } + + if (!list_entry->value || list_table->cmp(list_entry->value, value) == 0) { + return list_entry; + } + + val = strdup(value); - if (!list_entry2) { + if (!val) { + return list_entry; // TODO NULL? + } + + free(list_entry->value); + list_entry->value = val; + return list_entry; + } + + list_entry = calloc(1, sizeof(struct udev_list_entry)); + + if (!list_entry) { return NULL; } - list_entry2->name = strdup(name); + list_entry->name = strdup(name); - if (!list_entry2->name) { + if (!list_entry->name) { return NULL; } if (value) { - list_entry2->value = strdup(value); + list_entry->value = strdup(value); - if (!list_entry2->value) { + if (!list_entry->value) { return NULL; } } - list_entry2->next = list_entry->next; - list_entry->next = list_entry2; - return list_entry2; + list_entry->next = list_table->head; + list_table->head = list_entry; + + list_table->entries[i] = list_entry; + list_table->len++; + + list_entry->list_table = list_table; + list_entry->sum = sum; + return list_entry; +} + +struct udev_list_entry *udev_list_table_get_head(struct udev_list_table *list_table) +{ + return list_table ? list_table->head : NULL; } struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry) @@ -101,16 +260,30 @@ struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_en struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name) { + struct udev_list_table *list_table; + uint64_t sum; + size_t i; + if (!list_entry || !name) { return NULL; } - do { - if (list_entry->name && strcmp(list_entry->name, name) == 0) { + sum = hash_murmur64a(name); + list_table = list_entry->list_table; + + for (i = sum % list_table->cap; list_table->entries[i]; i++) { + if (i == list_table->cap) { + i = 0; + continue; + } + + list_entry = list_table->entries[i]; + + // TODO compare sum? + if (list_table->cmp(list_entry->name, name) == 0) { return list_entry; } } - while ((list_entry = list_entry->next)); return NULL; } diff --git a/udev_list.h b/udev_list.h index 99528253..7e7a9d82 100644 --- a/udev_list.h +++ b/udev_list.h @@ -15,13 +15,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -struct udev_list_entry { - struct udev_list_entry *next; - char *value; - char *name; -}; +struct udev_list_table *udev_list_table_init(size_t cap, int (*cmp)(const char *, const char *)); +void udev_list_table_deinit(struct udev_list_table *list_table); -void udev_list_entry_init(struct udev_list_entry *list_entry); -void udev_list_entry_free(struct udev_list_entry *list_entry); -void udev_list_entry_free_all(struct udev_list_entry *list_entry); -struct udev_list_entry *udev_list_entry_add(struct udev_list_entry *list_entry, const char *name, const char *value, int uniq); +struct udev_list_entry *udev_list_entry_add(struct udev_list_table *list_table, const char *name, const char *value); +struct udev_list_entry *udev_list_table_get_head(struct udev_list_table *list_table); diff --git a/udev_monitor.c b/udev_monitor.c index 28437429..5514f9e2 100644 --- a/udev_monitor.c +++ b/udev_monitor.c @@ -36,8 +36,8 @@ #endif struct udev_monitor { - struct udev_list_entry subsystem_match; - struct udev_list_entry devtype_match; + struct udev_list_table *subsystem_match; + struct udev_list_table *devtype_match; struct udev *udev; pthread_t thread; const char *dir; @@ -52,26 +52,19 @@ static int filter_devtype(struct udev_monitor *udev_monitor, struct udev_device struct udev_list_entry *list_entry; const char *devtype; - devtype = udev_device_get_devtype(udev_device); - list_entry = udev_list_entry_get_next(&udev_monitor->devtype_match); + list_entry = udev_list_table_get_head(udev_monitor->devtype_match); if (!list_entry) { return 1; } + devtype = udev_device_get_devtype(udev_device); + if (!devtype) { return 0; } - while (list_entry) { - if (strcmp(devtype, udev_list_entry_get_name(list_entry)) == 0) { - return 1; - } - - list_entry = udev_list_entry_get_next(list_entry); - } - - return 0; + return !!udev_list_entry_get_by_name(list_entry, devtype); } static int filter_subsystem(struct udev_monitor *udev_monitor, struct udev_device *udev_device) @@ -79,26 +72,19 @@ static int filter_subsystem(struct udev_monitor *udev_monitor, struct udev_devic struct udev_list_entry *list_entry; const char *subsystem; - subsystem = udev_device_get_subsystem(udev_device); - list_entry = udev_list_entry_get_next(&udev_monitor->subsystem_match); + list_entry = udev_list_table_get_head(udev_monitor->subsystem_match); if (!list_entry) { return 1; } + subsystem = udev_device_get_subsystem(udev_device); + if (!subsystem) { return 0; } - while (list_entry) { - if (strcmp(subsystem, udev_list_entry_get_name(list_entry)) == 0) { - return 1; - } - - list_entry = udev_list_entry_get_next(list_entry); - } - - return 0; + return !!udev_list_entry_get_by_name(list_entry, subsystem); } struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor) @@ -106,6 +92,7 @@ struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monito char file[PATH_MAX], data[4096]; struct udev_device *udev_device; + // TODO use recvmsg to detect truncated msgs? if (recv(udev_monitor->sfd[0], data, sizeof(data), 0) == -1) { return NULL; } @@ -226,13 +213,15 @@ int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_mo return -1; } - udev_list_entry_add(&udev_monitor->subsystem_match, subsystem, NULL, 0); + if (!udev_list_entry_add(udev_monitor->subsystem_match, subsystem, NULL)) { + return -1; + } - if (devtype) { - udev_list_entry_add(&udev_monitor->devtype_match, devtype, NULL, 0); + if (!devtype) { + return 0; } - return 0; + return !!udev_list_entry_add(udev_monitor->devtype_match, devtype, NULL) - 1; } /* XXX NOT IMPLEMENTED */ int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag) @@ -254,10 +243,22 @@ struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char return NULL; } + udev_monitor->subsystem_match = udev_list_table_init(10, strcmp); + + if (!udev_monitor->subsystem_match) { + goto free_monitor; + } + + udev_monitor->devtype_match = udev_list_table_init(10, strcmp); + + if (!udev_monitor->subsystem_match) { + goto deinit_subsystem_match; + } + udev_monitor->signal_fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); if (udev_monitor->signal_fd == -1) { - goto free_monitor; + goto deinit_devtype_match; } udev_monitor->ifd = inotify_init1(IN_CLOEXEC | IN_NONBLOCK); @@ -305,6 +306,12 @@ struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char close_signal_fd: close(udev_monitor->signal_fd); +deinit_subsystem_match: + udev_list_table_deinit(udev_monitor->subsystem_match); + +deinit_devtype_match: + udev_list_table_deinit(udev_monitor->devtype_match); + free_monitor: free(udev_monitor); return NULL; @@ -337,8 +344,8 @@ struct udev_monitor *udev_monitor_unref(struct udev_monitor *udev_monitor) // waiting for event thread to end before freeing udev_monitor pthread_join(udev_monitor->thread, NULL); - udev_list_entry_free_all(&udev_monitor->devtype_match); - udev_list_entry_free_all(&udev_monitor->subsystem_match); + udev_list_table_deinit(udev_monitor->subsystem_match); + udev_list_table_deinit(udev_monitor->devtype_match); for (i = 0; i < 2; i++) { close(udev_monitor->sfd[i]);