X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=udev%2Fudevadm-info.c;h=f7e7e86b6a4a8f43cf9207b85f4176ab4874191c;hp=094c6ce2a8da64e637758d8ecc0c26d4d57e56e9;hb=2fdaa983a958822d79821c1afe51e22e7a3e00ff;hpb=c08337da5c988e3e65d2ff63a1b554ca365deda7 diff --git a/udev/udevadm-info.c b/udev/udevadm-info.c index 094c6ce2a..f7e7e86b6 100644 --- a/udev/udevadm-info.c +++ b/udev/udevadm-info.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Kay Sievers + * Copyright (C) 2004-2009 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 @@ -25,58 +25,64 @@ #include #include #include +#include #include #include #include "udev.h" -static void print_all_attributes(struct udev_device *device, const char *key) +static bool skip_attribute(const char *name) { - struct udev *udev = udev_device_get_udev(device); - DIR *dir; - struct dirent *dent; + static const char const *skip[] = { + "uevent", + "dev", + "modalias", + "resource", + "driver", + "subsystem", + "module", + }; + unsigned int i; - dir = opendir(udev_device_get_syspath(device)); - if (dir != NULL) { - for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { - struct stat statbuf; - char filename[UTIL_PATH_SIZE]; - const char *value; - size_t len; - - if (dent->d_name[0] == '.') - continue; - - if (strcmp(dent->d_name, "uevent") == 0) - continue; - if (strcmp(dent->d_name, "dev") == 0) - continue; - - util_strlcpy(filename, udev_device_get_syspath(device), sizeof(filename)); - util_strlcat(filename, "/", sizeof(filename)); - util_strlcat(filename, dent->d_name, sizeof(filename)); - if (lstat(filename, &statbuf) != 0) - continue; - if (S_ISLNK(statbuf.st_mode)) - continue; - - value = udev_device_get_sysattr_value(device, dent->d_name); - if (value == NULL) - continue; - dbg(udev, "attr '%s'='%s'(%zi)\n", dent->d_name, value, len); - - /* skip nonprintable attributes */ - len = strlen(value); - while (len > 0 && isprint(value[len-1])) - len--; - if (len > 0) { - dbg(udev, "attribute value of '%s' non-printable, skip\n", dent->d_name); - continue; - } + for (i = 0; i < ARRAY_SIZE(skip); i++) + if (strcmp(name, skip[i]) == 0) + return true; + return false; +} - printf(" %s{%s}==\"%s\"\n", key, dent->d_name, value); +static void print_all_attributes(struct udev_device *device, const char *key) +{ + struct udev *udev = udev_device_get_udev(device); + struct udev_list_entry *sysattr; + + udev_list_entry_foreach(sysattr, udev_device_get_sysattr_list_entry(device)) { + const char *name; + const char *value; + size_t len; + + name = udev_list_entry_get_name(sysattr); + if (skip_attribute(name)) + continue; + + value = udev_device_get_sysattr_value(device, name); + if (value == NULL) + continue; + dbg(udev, "attr '%s'='%s'\n", name, value); + + /* skip any values that look like a path */ + if (value[0] == '/') + continue; + + /* skip nonprintable attributes */ + len = strlen(value); + while (len > 0 && isprint(value[len-1])) + len--; + if (len > 0) { + dbg(udev, "attribute value of '%s' non-printable, skip\n", name); + continue; } - closedir(dir); + + printf(" %s{%s}==\"%s\"\n", key, name, value); } printf("\n"); } @@ -145,18 +151,6 @@ static void print_record(struct udev_device *device) if (i != 0) printf("L: %i\n", i); - i = udev_device_get_num_fake_partitions(device); - if (i != 0) - printf("A:%u\n", i); - - i = udev_device_get_ignore_remove(device); - if (i != 0) - printf("R:%u\n", i); - - i = udev_device_get_watch_handle(device); - if (i >= 0) - printf("W:%u\n", i); - udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) { len = strlen(udev_get_dev_path(udev_device_get_udev(device))); printf("S: %s\n", &udev_list_entry_get_name(list_entry)[len+1]); @@ -169,7 +163,7 @@ static void print_record(struct udev_device *device) printf("\n"); } -static int stat_device(const char *name, int export, const char *prefix) +static int stat_device(const char *name, bool export, const char *prefix) { struct stat statbuf; @@ -202,8 +196,7 @@ static int export_devices(struct udev *udev) device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry)); if (device != NULL) { - if (udev_device_get_devnode(device) != NULL) - print_record(device); + print_record(device); udev_device_unref(device); } } @@ -211,11 +204,86 @@ static int export_devices(struct udev *udev) return 0; } -int udevadm_info(struct udev *udev, int argc, char *argv[]) +static void cleanup_dir(DIR *dir, mode_t mask, int depth) +{ + struct dirent *dent; + + if (depth <= 0) + return; + + for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { + struct stat stats; + + if (dent->d_name[0] == '.') + continue; + if (fstatat(dirfd(dir), dent->d_name, &stats, AT_SYMLINK_NOFOLLOW) != 0) + continue; + if ((stats.st_mode & mask) != 0) + continue; + if (S_ISDIR(stats.st_mode)) { + DIR *dir2; + + dir2 = fdopendir(openat(dirfd(dir), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC)); + if (dir2 != NULL) { + cleanup_dir(dir2, mask, depth-1); + closedir(dir2); + } + unlinkat(dirfd(dir), dent->d_name, AT_REMOVEDIR); + } else { + unlinkat(dirfd(dir), dent->d_name, 0); + } + } +} + +static void cleanup_db(struct udev *udev) +{ + char filename[UTIL_PATH_SIZE]; + DIR *dir; + + util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/queue.bin", NULL); + unlink(filename); + + util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/data", NULL); + dir = opendir(filename); + if (dir != NULL) { + cleanup_dir(dir, S_ISVTX, 1); + closedir(dir); + } + + util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/links", NULL); + dir = opendir(filename); + if (dir != NULL) { + cleanup_dir(dir, 0, 2); + closedir(dir); + } + + util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/tags", NULL); + dir = opendir(filename); + if (dir != NULL) { + cleanup_dir(dir, 0, 2); + closedir(dir); + } + + util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/watch", NULL); + dir = opendir(filename); + if (dir != NULL) { + cleanup_dir(dir, 0, 1); + closedir(dir); + } + + util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/firmware-missing", NULL); + dir = opendir(filename); + if (dir != NULL) { + cleanup_dir(dir, 0, 1); + closedir(dir); + } +} + +static int uinfo(struct udev *udev, int argc, char *argv[]) { struct udev_device *device = NULL; - int root = 0; - int export = 0; + bool root = 0; + bool export = 0; const char *export_prefix = NULL; char path[UTIL_PATH_SIZE]; char name[UTIL_PATH_SIZE]; @@ -227,8 +295,10 @@ int udevadm_info(struct udev *udev, int argc, char *argv[]) { "path", required_argument, NULL, 'p' }, { "query", required_argument, NULL, 'q' }, { "attribute-walk", no_argument, NULL, 'a' }, + { "cleanup-db", no_argument, NULL, 'c' }, { "export-db", no_argument, NULL, 'e' }, { "root", no_argument, NULL, 'r' }, + { "run", no_argument, NULL, 'R' }, { "device-id-of-file", required_argument, NULL, 'd' }, { "export", no_argument, NULL, 'x' }, { "export-prefix", required_argument, NULL, 'P' }, @@ -250,15 +320,15 @@ int udevadm_info(struct udev *udev, int argc, char *argv[]) QUERY_NAME, QUERY_PATH, QUERY_SYMLINK, - QUERY_ENV, + QUERY_PROPERTY, QUERY_ALL, } query = QUERY_NONE; - while (1) { + for (;;) { int option; struct stat statbuf; - option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL); + option = getopt_long(argc, argv, "aced:n:p:q:rxP:RVh", options, NULL); if (option == -1) break; @@ -271,13 +341,10 @@ int udevadm_info(struct udev *udev, int argc, char *argv[]) goto exit; } /* remove /dev if given */ - if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0) { - util_strlcpy(name, udev_get_dev_path(udev), sizeof(name)); - util_strlcat(name, "/", sizeof(name)); - util_strlcat(name, optarg, sizeof(name)); - } else { - util_strlcpy(name, optarg, sizeof(name)); - } + if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0) + util_strscpyl(name, sizeof(name), udev_get_dev_path(udev), "/", optarg, NULL); + else + util_strscpy(name, sizeof(name), optarg); util_remove_trailing_chars(name, '/'); if (stat(name, &statbuf) < 0) { fprintf(stderr, "device node not found\n"); @@ -310,12 +377,10 @@ int udevadm_info(struct udev *udev, int argc, char *argv[]) goto exit; } /* add sys dir if needed */ - if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0) { - util_strlcpy(path, udev_get_sys_path(udev), sizeof(path)); - util_strlcat(path, optarg, sizeof(path)); - } else { - util_strlcpy(path, optarg, sizeof(path)); - } + if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0) + util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), optarg, NULL); + else + util_strscpy(path, sizeof(path), optarg); util_remove_trailing_chars(path, '/'); device = udev_device_new_from_syspath(udev, path); if (device == NULL) { @@ -326,37 +391,33 @@ int udevadm_info(struct udev *udev, int argc, char *argv[]) break; case 'q': action = ACTION_QUERY; - if (strcmp(optarg, "name") == 0) { + if (strcmp(optarg, "property") == 0 || strcmp(optarg, "env") == 0) { + query = QUERY_PROPERTY; + } else if (strcmp(optarg, "name") == 0) { query = QUERY_NAME; - break; - } - if (strcmp(optarg, "symlink") == 0) { + } else if (strcmp(optarg, "symlink") == 0) { query = QUERY_SYMLINK; - break; - } - if (strcmp(optarg, "path") == 0) { + } else if (strcmp(optarg, "path") == 0) { query = QUERY_PATH; - break; - } - if (strcmp(optarg, "env") == 0) { - query = QUERY_ENV; - break; - } - if (strcmp(optarg, "all") == 0) { + } else if (strcmp(optarg, "all") == 0) { query = QUERY_ALL; - break; + } else { + fprintf(stderr, "unknown query type\n"); + rc = 3; + goto exit; } - fprintf(stderr, "unknown query type\n"); - rc = 3; - goto exit; + break; case 'r': if (action == ACTION_NONE) action = ACTION_ROOT; - root = 1; + root = true; break; + case 'R': + printf("%s\n", udev_get_run_path(udev)); + goto exit; case 'd': action = ACTION_DEVICE_ID_FILE; - util_strlcpy(name, optarg, sizeof(name)); + util_strscpy(name, sizeof(name), optarg); break; case 'a': action = ACTION_ATTRIBUTE_WALK; @@ -364,8 +425,11 @@ int udevadm_info(struct udev *udev, int argc, char *argv[]) case 'e': export_devices(udev); goto exit; + case 'c': + cleanup_db(udev); + goto exit; case 'x': - export = 1; + export = true; break; case 'P': export_prefix = optarg; @@ -379,7 +443,7 @@ int udevadm_info(struct udev *udev, int argc, char *argv[]) " name name of device node\n" " symlink pointing to node\n" " path sys device path\n" - " env the device related imported environment\n" + " property the device properties\n" " all all values\n" " --path= sys device path used for query or attribute walk\n" " --name= node or symlink name used for query or attribute walk\n" @@ -387,11 +451,14 @@ int udevadm_info(struct udev *udev, int argc, char *argv[]) " --attribute-walk print all key matches while walking along the chain\n" " of parent devices\n" " --device-id-of-file= print major:minor of device containing this file\n" + " --export export key/value pairs\n" + " --export-prefix export the key name with a prefix\n" " --export-db export the content of the udev database\n" - " --help print this text\n" - "\n"); + " --cleanup-db cleanup the udev database\n" + " --help\n\n"); goto exit; default: + rc = 1; goto exit; } } @@ -405,23 +472,24 @@ int udevadm_info(struct udev *udev, int argc, char *argv[]) } switch(query) { - case QUERY_NAME: + case QUERY_NAME: { + const char *node = udev_device_get_devnode(device); + + if (node == NULL) { + fprintf(stderr, "no device node found\n"); + rc = 5; + goto exit; + } + if (root) { printf("%s\n", udev_device_get_devnode(device)); } else { - size_t len; - const char *node; - - len = strlen(udev_get_dev_path(udev)); - node = udev_device_get_devnode(device); - if (node == NULL) { - fprintf(stderr, "no device node found\n"); - rc = 5; - goto exit; - } - printf("%s\n", &udev_device_get_devnode(device)[len+1]); + size_t len = strlen(udev_get_dev_path(udev)); + + printf("%s\n", &udev_device_get_devnode(device)[len+1]); } break; + } case QUERY_SYMLINK: list_entry = udev_device_get_devlinks_list_entry(device); while (list_entry != NULL) { @@ -442,10 +510,20 @@ int udevadm_info(struct udev *udev, int argc, char *argv[]) case QUERY_PATH: printf("%s\n", udev_device_get_devpath(device)); goto exit; - case QUERY_ENV: + case QUERY_PROPERTY: list_entry = udev_device_get_properties_list_entry(device); while (list_entry != NULL) { - printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry)); + if (export) { + const char *prefix = export_prefix; + + if (prefix == NULL) + prefix = ""; + printf("%s%s='%s'\n", prefix, + udev_list_entry_get_name(list_entry), + udev_list_entry_get_value(list_entry)); + } else { + printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry)); + } list_entry = udev_list_entry_get_next(list_entry); } break; @@ -482,3 +560,9 @@ exit: udev_device_unref(device); return rc; } + +const struct udevadm_cmd udevadm_info = { + .name = "info", + .cmd = uinfo, + .help = "query sysfs or the udev database", +};