X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=udev%2Flib%2Flibudev-device.c;h=8e29efff86b2ea18b6b2414f343b4fd0a7849d00;hp=c4714e4088d1a8dc6f1b5b0cc774fab307bf6e12;hb=cb14f4543a941ff8a22ef2725df86b3b0190a189;hpb=f454ecf7544077349c24e9fcfd418dbfca927063 diff --git a/udev/lib/libudev-device.c b/udev/lib/libudev-device.c index c4714e408..8e29efff8 100644 --- a/udev/lib/libudev-device.c +++ b/udev/lib/libudev-device.c @@ -3,18 +3,10 @@ * * Copyright (C) 2008 Kay Sievers * - * This program 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. - * - * This program 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 this program. If not, see . + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. */ #include @@ -40,10 +32,12 @@ struct udev_device { const char *sysnum; char *devnode; char *subsystem; + char *devtype; char *driver; char *action; char *devpath_old; char *physdevpath; + char *knodename; char **envp; char *monitor_buf; size_t monitor_buf_len; @@ -57,8 +51,10 @@ struct udev_device { int devlink_priority; int refcount; dev_t devnum; + int watch_handle; unsigned int parent_set:1; unsigned int subsystem_set:1; + unsigned int devtype_set:1; unsigned int devlinks_uptodate:1; unsigned int envp_uptodate:1; unsigned int driver_set:1; @@ -174,6 +170,9 @@ int udev_device_read_db(struct udev_device *udev_device) case 'E': udev_device_add_property_from_string(udev_device, val); break; + case 'W': + udev_device_set_watch_handle(udev_device, atoi(val)); + break; } } fclose(f); @@ -204,10 +203,14 @@ int udev_device_read_uevent_file(struct udev_device *udev_device) continue; pos[0] = '\0'; - if (strncmp(line, "MAJOR=", 6) == 0) + if (strncmp(line, "DEVTYPE=", 8) == 0) + udev_device_set_devtype(udev_device, &line[8]); + else if (strncmp(line, "MAJOR=", 6) == 0) maj = strtoull(&line[6], NULL, 10); else if (strncmp(line, "MINOR=", 6) == 0) min = strtoull(&line[6], NULL, 10); + else if (strncmp(line, "DEVNAME=", 8) == 0) + udev_device_set_knodename(udev_device, &line[8]); udev_device_add_property_from_string(udev_device, line); } @@ -247,6 +250,7 @@ struct udev_device *device_new(struct udev *udev) udev_list_init(&udev_device->properties_list); udev_list_init(&udev_device->sysattr_list); udev_device->event_timeout = -1; + udev_device->watch_handle = -1; /* copy global properties */ udev_list_entry_foreach(list_entry, udev_get_properties_list_entry(udev)) udev_device_add_property(udev_device, @@ -294,7 +298,7 @@ struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char * /* path is not a root directory */ subdir = &syspath[len+1]; pos = strrchr(subdir, '/'); - if (pos == NULL || pos < &subdir[2]) { + if (pos == NULL || pos[1] == '\0' || pos < &subdir[2]) { dbg(udev, "not a subdir :%s\n", syspath); return NULL; } @@ -537,17 +541,26 @@ struct udev_device *udev_device_get_parent(struct udev_device *udev_device) return udev_device->parent_device; } -struct udev_device *udev_device_get_parent_with_subsystem(struct udev_device *udev_device, const char *subsystem) +struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, const char *subsystem, const char *devtype) { struct udev_device *parent; + if (subsystem == NULL) + return NULL; + parent = udev_device_get_parent(udev_device); while (parent != NULL) { const char *parent_subsystem; + const char *parent_devtype; parent_subsystem = udev_device_get_subsystem(parent); - if (parent_subsystem != NULL && strcmp(parent_subsystem, subsystem) == 0) - break; + if (parent_subsystem != NULL && strcmp(parent_subsystem, subsystem) == 0) { + if (devtype == NULL) + break; + parent_devtype = udev_device_get_devtype(parent); + if (parent_devtype != NULL && strcmp(parent_devtype, devtype) == 0) + break; + } parent = udev_device_get_parent(parent); } return parent; @@ -605,11 +618,13 @@ void udev_device_unref(struct udev_device *udev_device) free(udev_device->sysname); free(udev_device->devnode); free(udev_device->subsystem); + free(udev_device->devtype); udev_list_cleanup_entries(udev_device->udev, &udev_device->devlinks_list); udev_list_cleanup_entries(udev_device->udev, &udev_device->properties_list); free(udev_device->action); free(udev_device->driver); free(udev_device->devpath_old); + free(udev_device->knodename); free(udev_device->physdevpath); udev_list_cleanup_entries(udev_device->udev, &udev_device->sysattr_list); free(udev_device->envp); @@ -723,6 +738,26 @@ const char *udev_device_get_subsystem(struct udev_device *udev_device) return udev_device->subsystem; } +/** + * udev_device_get_devtype: + * @udev_device: udev device + * + * Retrieve the devtype string of the udev device. + * + * Returns: the devtype name of the udev device, or #NULL if it can not be determined + **/ +const char *udev_device_get_devtype(struct udev_device *udev_device) +{ + if (udev_device == NULL) + return NULL; + if (!udev_device->devtype_set) { + udev_device->devtype_set = 1; + if (!udev_device->info_loaded) + udev_device_read_uevent_file(udev_device); + } + return udev_device->devtype; +} + /** * udev_device_get_devlinks_list_entry: * @udev_device: udev device @@ -828,7 +863,7 @@ const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const { struct udev_list_entry *list_entry; char path[UTIL_PATH_SIZE]; - char value[UTIL_NAME_SIZE]; + char value[4096]; struct stat statbuf; int fd; ssize_t size; @@ -859,11 +894,16 @@ const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const } if (S_ISLNK(statbuf.st_mode)) { - /* links return the last element of the target path */ char target[UTIL_NAME_SIZE]; int len; char *pos; + /* some core links return the last element of the target path */ + if (strcmp(sysattr, "driver") != 0 && + strcmp(sysattr, "subsystem") != 0 && + strcmp(sysattr, "module") != 0) + goto out; + len = readlink(path, target, sizeof(target)); if (len > 0) { target[len] = '\0'; @@ -958,6 +998,17 @@ int udev_device_set_subsystem(struct udev_device *udev_device, const char *subsy return 0; } +int udev_device_set_devtype(struct udev_device *udev_device, const char *devtype) +{ + free(udev_device->devtype); + udev_device->devtype = strdup(devtype); + if (udev_device->devtype == NULL) + return -ENOMEM; + udev_device->devtype_set = 1; + udev_device_add_property(udev_device, "DEVTYPE", udev_device->devtype); + return 0; +} + int udev_device_set_devnode(struct udev_device *udev_device, const char *devnode) { free(udev_device->devnode); @@ -1009,11 +1060,24 @@ struct udev_list_entry *udev_device_add_property_from_string(struct udev_device return udev_device_add_property(udev_device, name, val); } +const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key) +{ + struct udev_list_entry *list_entry; + + if (udev_device == NULL) + return NULL; + if (key == NULL) + return NULL; + + list_entry = udev_device_get_properties_list_entry(udev_device); + list_entry = udev_list_entry_get_by_name(list_entry, key); + return udev_list_entry_get_value(list_entry); +} + #define ENVP_SIZE 128 #define MONITOR_BUF_SIZE 4096 static int update_envp_monitor_buf(struct udev_device *udev_device) { - const char *action; struct udev_list_entry *list_entry; size_t bufpos; size_t len; @@ -1032,23 +1096,8 @@ static int update_envp_monitor_buf(struct udev_device *udev_device) if (udev_device->envp == NULL) return -ENOMEM; - /* header @ */ - action = udev_device_get_action(udev_device); - if (action == NULL) - return -EINVAL; - bufpos = util_strlcpy(udev_device->monitor_buf, action, MONITOR_BUF_SIZE); - len = util_strlcpy(&udev_device->monitor_buf[bufpos], "@", MONITOR_BUF_SIZE-bufpos); - if (len >= MONITOR_BUF_SIZE-bufpos) - return -EINVAL; - bufpos += len; - len = util_strlcpy(&udev_device->monitor_buf[bufpos], - udev_device_get_devpath(udev_device), - MONITOR_BUF_SIZE-bufpos); - if (len+1 >= MONITOR_BUF_SIZE-bufpos) - return -EINVAL; - bufpos += len+1; - i = 0; + bufpos = 0; udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device)) { /* add string to envp array */ udev_device->envp[i++] = &udev_device->monitor_buf[bufpos]; @@ -1130,6 +1179,19 @@ int udev_device_set_devpath_old(struct udev_device *udev_device, const char *dev return 0; } +const char *udev_device_get_knodename(struct udev_device *udev_device) +{ + return udev_device->knodename; +} + +int udev_device_set_knodename(struct udev_device *udev_device, const char *knodename) +{ + udev_device->knodename = strdup(knodename); + if (udev_device->knodename == NULL) + return -ENOMEM; + return 0; +} + const char *udev_device_get_physdevpath(struct udev_device *udev_device) { return udev_device->physdevpath; @@ -1227,3 +1289,16 @@ int udev_device_set_ignore_remove(struct udev_device *udev_device, int ignore) udev_device->ignore_remove = ignore; return 0; } + +int udev_device_get_watch_handle(struct udev_device *udev_device) +{ + if (!udev_device->info_loaded) + device_load_info(udev_device); + return udev_device->watch_handle; +} + +int udev_device_set_watch_handle(struct udev_device *udev_device, int handle) +{ + udev_device->watch_handle = handle; + return 0; +}