From e48fc108d9731f6f091742fe6588c495d1948fac Mon Sep 17 00:00:00 2001 From: "kay.sievers@vrfy.org" Date: Sat, 5 Mar 2005 05:35:31 +0100 Subject: [PATCH] [PATCH] allow unlimitied count of symlinks --- namedev.c | 27 +++++++---- udev.c | 1 + udev.h | 2 +- udev_add.c | 19 ++++---- udev_db.c | 95 ++++++++++++++++++++++++--------------- udev_db.h | 4 +- udev_remove.c | 31 +++++-------- udev_utils.c | 12 +++++ udev_utils.h | 2 + udevinfo.c | 122 ++++++++++++++++++++++---------------------------- 10 files changed, 169 insertions(+), 146 deletions(-) diff --git a/namedev.c b/namedev.c index 41f0bc0f..91841571 100644 --- a/namedev.c +++ b/namedev.c @@ -144,15 +144,14 @@ static int get_format_len(char **str) */ static int find_free_number(struct udevice *udev, const char *name) { + char devpath[NAME_SIZE]; char filename[NAME_SIZE]; int num = 0; - struct udevice db_udev; strfieldcpy(filename, name); while (1) { dbg("look for existing node '%s'", filename); - memset(&db_udev, 0x00, sizeof(struct udevice)); - if (udev_db_get_device_by_name(&db_udev, filename) != 0) { + if (udev_db_search_name(devpath, DEVPATH_SIZE, filename) != 0) { dbg("free num=%d", num); return num; } @@ -298,13 +297,14 @@ static void apply_format(struct udevice *udev, char *string, size_t maxsize, struct udevice udev_parent; dbg("found parent '%s', get the node name", class_dev_parent->path); - memset(&udev_parent, 0x00, sizeof(struct udevice)); + udev_init_device(&udev_parent, NULL, NULL); /* lookup the name in the udev_db with the DEVPATH of the parent */ - if (udev_db_get_device_by_devpath(&udev_parent, &class_dev_parent->path[strlen(sysfs_path)]) == 0) { + if (udev_db_get_device(&udev_parent, &class_dev_parent->path[strlen(sysfs_path)]) == 0) { strfieldcatmax(string, udev_parent.name, maxsize); dbg("substitute parent node name'%s'", udev_parent.name); } else dbg("parent not found in database"); + udev_cleanup_device(&udev_parent); } break; case 'N': @@ -749,14 +749,25 @@ int namedev_name_device(struct udevice *udev, struct sysfs_class_device *class_d /* collect symlinks */ if (dev->symlink[0] != '\0') { char temp[NAME_SIZE]; + char *pos, *next; info("configured rule in '%s[%i]' applied, added symlink '%s'", dev->config_file, dev->config_line, dev->symlink); strfieldcpy(temp, dev->symlink); apply_format(udev, temp, sizeof(temp), class_dev, sysfs_device); - if (udev->symlink[0] != '\0') - strfieldcat(udev->symlink, " "); - strfieldcat(udev->symlink, temp); + + /* add multiple symlinks separated by spaces */ + pos = temp; + next = strchr(temp, ' '); + while (next) { + next[0] = '\0'; + dbg("add symlink '%s'", pos); + name_list_add(&udev->symlink_list, pos, 0); + pos = &next[1]; + next = strchr(pos, ' '); + } + dbg("add symlink '%s'", pos); + name_list_add(&udev->symlink_list, pos, 0); } /* rule matches */ diff --git a/udev.c b/udev.c index 802e41d1..c26ce46b 100644 --- a/udev.c +++ b/udev.c @@ -236,6 +236,7 @@ int main(int argc, char *argv[], char *envp[]) } hotplug: + udev_cleanup_device(&udev); if (udev_hotplug_d && managed_event) udev_multiplex_directory(&udev, HOTPLUGD_DIR, HOTPLUG_SUFFIX); diff --git a/udev.h b/udev.h index f1236194..811439fa 100644 --- a/udev.h +++ b/udev.h @@ -63,7 +63,7 @@ struct udevice { char name[NAME_SIZE]; char devname[NAME_SIZE]; - char symlink[NAME_SIZE]; + struct list_head symlink_list; char owner[USER_SIZE]; char group[USER_SIZE]; mode_t mode; diff --git a/udev_add.c b/udev_add.c index eeab1ca1..7e0c57fc 100644 --- a/udev_add.c +++ b/udev_add.c @@ -113,12 +113,11 @@ static int create_node(struct udevice *udev, struct sysfs_class_device *class_de { char filename[NAME_SIZE]; char partitionname[NAME_SIZE]; + struct name_entry *name_loop; uid_t uid = 0; gid_t gid = 0; int tail; - char *pos; - int len; - int i; + int i; snprintf(filename, NAME_SIZE, "%s/%s", udev_root, udev->name); filename[NAME_SIZE-1] = '\0'; @@ -195,30 +194,28 @@ static int create_node(struct udevice *udev, struct sysfs_class_device *class_de } /* create symlink(s) if requested */ - foreach_strpart(udev->symlink, " ", pos, len) { - char linkname[NAME_SIZE]; + list_for_each_entry(name_loop, &udev->symlink_list, node) { char linktarget[NAME_SIZE]; - strfieldcpymax(linkname, pos, len+1); - snprintf(filename, NAME_SIZE, "%s/%s", udev_root, linkname); + snprintf(filename, NAME_SIZE, "%s/%s", udev_root, name_loop->name); filename[NAME_SIZE-1] = '\0'; dbg("symlink '%s' to node '%s' requested", filename, udev->name); if (!udev->test_run) - if (strrchr(linkname, '/')) + if (strchr(filename, '/')) create_path(filename); /* optimize relative link */ linktarget[0] = '\0'; i = 0; tail = 0; - while ((udev->name[i] == linkname[i]) && udev->name[i]) { + while (udev->name[i] && (udev->name[i] == name_loop->name[i])) { if (udev->name[i] == '/') tail = i+1; i++; } - while (linkname[i] != '\0') { - if (linkname[i] == '/') + while (name_loop->name[i] != '\0') { + if (name_loop->name[i] == '/') strfieldcat(linktarget, "../"); i++; } diff --git a/udev_db.c b/udev_db.c index a423247d..1015d212 100644 --- a/udev_db.c +++ b/udev_db.c @@ -60,6 +60,7 @@ static int get_db_filename(const char *devpath, char *filename, int len) int udev_db_add_device(struct udevice *udev) { char filename[SYSFS_PATH_MAX]; + struct name_entry *name_loop; FILE *f; if (udev->test_run) @@ -78,7 +79,8 @@ int udev_db_add_device(struct udevice *udev) fprintf(f, "P:%s\n", udev->devpath); fprintf(f, "N:%s\n", udev->name); - fprintf(f, "S:%s\n", udev->symlink); + list_for_each_entry(name_loop, &udev->symlink_list, node) + fprintf(f, "S:%s\n", name_loop->name); fprintf(f, "M:%u:%u\n", major(udev->devt), minor(udev->devt)); fprintf(f, "A:%u\n", udev->partitions); fprintf(f, "R:%u\n", udev->ignore_remove); @@ -134,8 +136,9 @@ static int parse_db_file(struct udevice *udev, const char *filename) case 'S': if (count > NAME_SIZE) count = NAME_SIZE-1; - strncpy(udev->symlink, &bufline[2], count-2); - udev->symlink[count-2] = '\0'; + strncpy(temp, &bufline[2], count-2); + temp[count-2] = '\0'; + name_list_add(&udev->symlink_list, temp, 0); break; case 'A': if (count > NAME_SIZE) @@ -171,21 +174,23 @@ int udev_db_delete_device(struct udevice *udev) return 0; } -int udev_db_get_device_by_devpath(struct udevice *udev, const char *devpath) +int udev_db_get_device(struct udevice *udev, const char *devpath) { char filename[SYSFS_PATH_MAX]; get_db_filename(devpath, filename, SYSFS_PATH_MAX); - return parse_db_file(udev, filename); + if (parse_db_file(udev, filename) != 0) + return -1; + + return 0; } -int udev_db_get_device_by_name(struct udevice *udev, const char *name) +int udev_db_search_name(char *devpath, size_t len, const char *name) { struct dirent *ent; DIR *dir; char filename[NAME_SIZE]; - struct udevice db_udev; dir = opendir(udev_db_path); if (dir == NULL) { @@ -194,6 +199,14 @@ int udev_db_get_device_by_name(struct udevice *udev, const char *name) } while (1) { + char path[DEVPATH_SIZE]; + char nodename[NAME_SIZE]; + char *bufline; + char *buf; + size_t bufsize; + size_t cur; + size_t count; + ent = readdir(dir); if (ent == NULL || ent->d_name[0] == '\0') break; @@ -203,42 +216,50 @@ int udev_db_get_device_by_name(struct udevice *udev, const char *name) snprintf(filename, NAME_SIZE, "%s/%s", udev_db_path, ent->d_name); filename[NAME_SIZE-1] = '\0'; + dbg("looking at '%s'", filename); - memset(&db_udev, 0x00, sizeof(struct udevice)); - if (parse_db_file(&db_udev, filename) == 0) { - char *pos; - unsigned int len; - - if (strncmp(name, db_udev.name, NAME_SIZE) == 0) { - goto found; - } - - foreach_strpart(db_udev.symlink, " ", pos, len) { - if (strncmp(name, pos, len) != 0) - continue; + if (file_map(filename, &buf, &bufsize) != 0) { + dbg("unable to read db file '%s'", filename); + continue; + } - if (len == strlen(name)) - goto found; + cur = 0; + while (cur < bufsize) { + count = buf_get_line(buf, bufsize, cur); + bufline = &buf[cur]; + cur += count+1; + + switch(bufline[0]) { + case 'P': + if (count > DEVPATH_SIZE) + count = DEVPATH_SIZE-1; + strncpy(path, &bufline[2], count-2); + path[count-2] = '\0'; + break; + case 'N': + case 'S': + if (count > NAME_SIZE) + count = NAME_SIZE-1; + strncpy(nodename, &bufline[2], count-2); + nodename[count-2] = '\0'; + dbg("compare '%s' '%s'", nodename, name); + if (strcmp(nodename, name) == 0) { + strncpy(devpath, path, len); + devpath[len] = '\0'; + file_unmap(buf, bufsize); + closedir(dir); + return 0; + } + break; + default: + continue; } - } + file_unmap(buf, bufsize); } closedir(dir); - return -1; - -found: - closedir(dir); - - strfieldcpy(udev->devpath, db_udev.devpath); - strfieldcpy(udev->name, db_udev.name); - strfieldcpy(udev->symlink, db_udev.symlink); - udev->partitions = db_udev.partitions; - udev->ignore_remove = db_udev.ignore_remove; - udev->devt = db_udev.devt; - - return 0; } int udev_db_call_foreach(int (*handler_function)(struct udevice *udev)) @@ -265,7 +286,9 @@ int udev_db_call_foreach(int (*handler_function)(struct udevice *udev)) snprintf(filename, NAME_SIZE, "%s/%s", udev_db_path, ent->d_name); filename[NAME_SIZE-1] = '\0'; - memset(&db_udev, 0x00, sizeof(struct udevice)); + dbg("found '%s'", filename); + + udev_init_device(&db_udev, NULL, NULL); if (parse_db_file(&db_udev, filename) == 0) { if (handler_function(&db_udev) != 0) break; diff --git a/udev_db.h b/udev_db.h index 2fce06be..8840142f 100644 --- a/udev_db.h +++ b/udev_db.h @@ -28,8 +28,8 @@ extern int udev_db_add_device(struct udevice *dev); extern int udev_db_delete_device(struct udevice *dev); -extern int udev_db_get_device_by_devpath(struct udevice *udev, const char *devpath); -extern int udev_db_get_device_by_name(struct udevice *udev, const char *name); +extern int udev_db_get_device(struct udevice *udev, const char *devpath); +extern int udev_db_search_name(char *devpath, size_t len, const char *name); extern int udev_db_call_foreach(int (*handler_function)(struct udevice *udev)); #endif /* _UDEV_DB_H_ */ diff --git a/udev_remove.c b/udev_remove.c index 22a363ed..756eef04 100644 --- a/udev_remove.c +++ b/udev_remove.c @@ -71,11 +71,10 @@ static int delete_node(struct udevice *udev) { char filename[NAME_SIZE]; char partitionname[NAME_SIZE]; + struct name_entry *name_loop; struct stat stats; int retval; int i; - char *pos; - int len; int num; snprintf(filename, NAME_SIZE, "%s/%s", udev_root, udev->name); @@ -114,11 +113,8 @@ static int delete_node(struct udevice *udev) if (strchr(udev->name, '/')) delete_path(filename); - foreach_strpart(udev->symlink, " ", pos, len) { - char linkname[NAME_SIZE]; - - strfieldcpymax(linkname, pos, len+1); - snprintf(filename, NAME_SIZE, "%s/%s", udev_root, linkname); + list_for_each_entry(name_loop, &udev->symlink_list, node) { + snprintf(filename, NAME_SIZE, "%s/%s", udev_root, name_loop->name); filename[NAME_SIZE-1] = '\0'; dbg("unlinking symlink '%s'", filename); @@ -130,7 +126,7 @@ static int delete_node(struct udevice *udev) filename, strerror(errno)); return retval; } - if (strchr(udev->symlink, '/')) { + if (strchr(filename, '/')) { delete_path(filename); } } @@ -145,13 +141,18 @@ static int delete_node(struct udevice *udev) int udev_remove_device(struct udevice *udev) { const char *temp; - int retval; if (udev->type != BLOCK && udev->type != CLASS) return 0; - retval = udev_db_get_device_by_devpath(udev, udev->devpath); - if (retval) { + if (udev_db_get_device(udev, udev->devpath) == 0) { + if (udev->ignore_remove) { + dbg("remove event for '%s' requested to be ignored by rule", udev->name); + return 0; + } + dbg("remove name='%s'", udev->name); + udev_db_delete_device(udev); + } else { /* fall back to kernel name */ temp = strrchr(udev->devpath, '/'); if (temp == NULL) @@ -160,14 +161,6 @@ int udev_remove_device(struct udevice *udev) dbg("'%s' not found in database, falling back on default name", udev->name); } - if (udev->ignore_remove) { - dbg("remove event for '%s' requested to be ignored by rule", udev->name); - return 0; - } - - dbg("remove name='%s'", udev->name); - udev_db_delete_device(udev); - /* use full path to the environment */ snprintf(udev->devname, NAME_SIZE, "%s/%s", udev_root, udev->name); diff --git a/udev_utils.c b/udev_utils.c index cfa4ab51..60f5ad85 100644 --- a/udev_utils.c +++ b/udev_utils.c @@ -42,6 +42,7 @@ int udev_init_device(struct udevice *udev, const char* devpath, const char *subs char *pos; memset(udev, 0x00, sizeof(struct udevice)); + INIT_LIST_HEAD(&udev->symlink_list); if (subsystem) strfieldcpy(udev->subsystem, subsystem); @@ -89,6 +90,17 @@ int udev_init_device(struct udevice *udev, const char* devpath, const char *subs return 0; } +void udev_cleanup_device(struct udevice *udev) +{ + struct name_entry *name_loop; + struct name_entry *temp_loop; + + list_for_each_entry_safe(name_loop, temp_loop, &udev->symlink_list, node) { + list_del(&name_loop->node); + free(name_loop); + } +} + int kernel_release_satisfactory(unsigned int version, unsigned int patchlevel, unsigned int sublevel) { static unsigned int kversion = 0; diff --git a/udev_utils.h b/udev_utils.h index 1ab4752c..2f2c2497 100644 --- a/udev_utils.h +++ b/udev_utils.h @@ -82,6 +82,8 @@ struct name_entry { }; extern int udev_init_device(struct udevice *udev, const char* devpath, const char *subsystem); +extern void udev_cleanup_device(struct udevice *udev); + extern int kernel_release_satisfactory(unsigned int version, unsigned int patchlevel, unsigned int sublevel); extern int create_path(const char *path); extern int parse_get_pair(char **orig_string, char **left, char **right); diff --git a/udevinfo.c b/udevinfo.c index 04539525..6dfb918d 100644 --- a/udevinfo.c +++ b/udevinfo.c @@ -83,10 +83,13 @@ static void print_all_attributes(struct dlist *attr_list) static int print_record(struct udevice *udev) { + struct name_entry *name_loop; + printf("P: %s\n", udev->devpath); printf("N: %s\n", udev->name); - printf("S: %s\n", udev->symlink); - printf("\n"); + list_for_each_entry(name_loop, &udev->symlink_list, node) + printf("S: %s\n", name_loop->name); + return 0; } @@ -95,7 +98,7 @@ enum query_type { NAME, PATH, SYMLINK, - ALL + ALL, }; static int print_device_chain(const char *path) @@ -183,20 +186,25 @@ static int print_dump(struct udevice *udev) { return 0; } -static int process_options(int argc, char *argv[]) +int main(int argc, char *argv[], char *envp[]) { static const char short_options[] = "adn:p:q:rVh"; int option; - int retval = 1; struct udevice udev; int root = 0; int attributes = 0; enum query_type query = NONE; - char result[1024] = ""; char path[NAME_SIZE] = ""; char name[NAME_SIZE] = ""; char temp[NAME_SIZE]; + struct name_entry *name_loop; char *pos; + int retval = 0; + + logging_init("udevinfo"); + + udev_init_config(); + udev_init_device(&udev, NULL, NULL); /* get command line options */ while (1) { @@ -240,7 +248,8 @@ static int process_options(int argc, char *argv[]) } printf("unknown query type\n"); - exit(1); + retval = 1; + goto exit; case 'r': root = 1; @@ -252,14 +261,14 @@ static int process_options(int argc, char *argv[]) case 'd': udev_db_call_foreach(print_dump); - exit(0); + goto exit; case 'V': printf("udevinfo, version %s\n", UDEV_VERSION); - exit(0); + goto exit; case 'h': - retval = 0; + retval = 2; case '?': default: goto help; @@ -275,15 +284,14 @@ static int process_options(int argc, char *argv[]) } else { if (path[0] != '/') { /* prepend '/' if missing */ - strfieldcat(temp, "/"); + strcpy(temp, "/"); strfieldcat(temp, path); pos = temp; } else { pos = path; } } - memset(&udev, 0x00, sizeof(struct udevice)); - retval = udev_db_get_device_by_devpath(&udev, pos); + retval = udev_db_get_device(&udev, pos); if (retval != 0) { printf("device not found in database\n"); goto exit; @@ -292,77 +300,64 @@ static int process_options(int argc, char *argv[]) } if (name[0] != '\0') { - /* remove udev_root if given */ - int len = strlen(udev_root); + char devpath[NAME_SIZE]; + int len; + /* remove udev_root if given */ + len = strlen(udev_root); if (strncmp(name, udev_root, len) == 0) { pos = &name[len+1]; } else pos = name; - memset(&udev, 0x00, sizeof(struct udevice)); - strfieldcpy(udev.name, pos); - retval = udev_db_get_device_by_name(&udev, pos); + retval = udev_db_search_name(devpath, DEVPATH_SIZE, pos); if (retval != 0) { printf("device not found in database\n"); goto exit; } - + udev_db_get_device(&udev, devpath); goto print; } printf("query needs device path(-p) or node name(-n) specified\n"); + retval = 3; goto exit; print: switch(query) { case NAME: - if (root) { - snprintf(result, NAME_SIZE-1, "%s/%s", udev_root, udev.name); - result[NAME_SIZE-1] = '\0'; - } else { - strfieldcpy(result, udev.name); - } - break; - + if (root) + printf("%s/%s\n", udev_root, udev.name); + else + printf("%s\n", udev.name); + goto exit; case SYMLINK: - if (root) { - int slen; - char *spos; - char slink[NAME_SIZE]; - - pos = result; - foreach_strpart(udev.symlink, " \n\r", spos, slen) { - strncpy(slink, spos, slen); - slink[slen] = '\0'; - pos += sprintf(pos, "%s/%s ", udev_root, slink); - } - } else { - strfieldcpy(result, udev.symlink); - } - break; - + if (list_empty(&udev.symlink_list)) + break; + if (root) + list_for_each_entry(name_loop, &udev.symlink_list, node) + printf("%s/%s ", udev_root, name_loop->name); + else + list_for_each_entry(name_loop, &udev.symlink_list, node) + printf("%s ", name_loop->name); + printf("\n"); + goto exit; case PATH: - strfieldcpy(result, udev.devpath); - break; - + printf("%s\n", udev.devpath); + goto exit; case ALL: print_record(&udev); goto exit; - default: - goto exit; + goto help; } - printf("%s\n", result); - -exit: - return retval; } if (attributes) { if (path[0] == '\0') { printf("attribute walk on device chain needs path(-p) specified\n"); - return -EINVAL; + retval = 4; + goto exit; } else { if (strncmp(path, sysfs_path, strlen(sysfs_path)) != 0) { /* prepend sysfs mountpoint if not given */ @@ -371,13 +366,13 @@ exit: strfieldcat(path, temp); } print_device_chain(path); - return 0; + goto exit; } } if (root) { printf("%s\n", udev_root); - return 0; + goto exit; } help: @@ -398,20 +393,9 @@ help: " -V print udev version\n" " -h print this help text\n" "\n"); - return retval; -} - -int main(int argc, char *argv[], char *envp[]) -{ - int rc = 0; - - logging_init("udevinfo"); - - /* initialize our configuration */ - udev_init_config(); - - rc = process_options(argc, argv); +exit: + udev_cleanup_device(&udev); logging_close(); - exit(rc); + return retval; } -- 2.39.5