2 * Copyright (C) 2004-2009 Kay Sievers <kay@vrfy.org>
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
30 #include "string-util.h"
31 #include "udev-util.h"
33 #include "udevadm-util.h"
35 static bool skip_attribute(const char *name
) {
36 static const char* const skip
[] = {
47 for (i
= 0; i
< ELEMENTSOF(skip
); i
++)
48 if (streq(name
, skip
[i
]))
53 static void print_all_attributes(struct udev_device
*device
, const char *key
) {
54 struct udev_list_entry
*sysattr
;
56 udev_list_entry_foreach(sysattr
, udev_device_get_sysattr_list_entry(device
)) {
61 name
= udev_list_entry_get_name(sysattr
);
62 if (skip_attribute(name
))
65 value
= udev_device_get_sysattr_value(device
, name
);
69 /* skip any values that look like a path */
73 /* skip nonprintable attributes */
75 while (len
> 0 && isprint(value
[len
-1]))
80 printf(" %s{%s}==\"%s\"\n", key
, name
, value
);
85 static int print_device_chain(struct udev_device
*device
) {
86 struct udev_device
*device_parent
;
90 "Udevadm info starts with the device specified by the devpath and then\n"
91 "walks up the chain of parent devices. It prints for every device\n"
92 "found, all possible attributes in the udev rules key format.\n"
93 "A rule to match, can be composed by the attributes of the device\n"
94 "and the attributes from one single parent device.\n"
97 printf(" looking at device '%s':\n", udev_device_get_devpath(device
));
98 printf(" KERNEL==\"%s\"\n", udev_device_get_sysname(device
));
99 str
= udev_device_get_subsystem(device
);
102 printf(" SUBSYSTEM==\"%s\"\n", str
);
103 str
= udev_device_get_driver(device
);
106 printf(" DRIVER==\"%s\"\n", str
);
107 print_all_attributes(device
, "ATTR");
109 device_parent
= device
;
111 device_parent
= udev_device_get_parent(device_parent
);
112 if (device_parent
== NULL
)
114 printf(" looking at parent device '%s':\n", udev_device_get_devpath(device_parent
));
115 printf(" KERNELS==\"%s\"\n", udev_device_get_sysname(device_parent
));
116 str
= udev_device_get_subsystem(device_parent
);
119 printf(" SUBSYSTEMS==\"%s\"\n", str
);
120 str
= udev_device_get_driver(device_parent
);
123 printf(" DRIVERS==\"%s\"\n", str
);
124 print_all_attributes(device_parent
, "ATTRS");
125 } while (device_parent
!= NULL
);
130 static void print_record(struct udev_device
*device
) {
133 struct udev_list_entry
*list_entry
;
135 printf("P: %s\n", udev_device_get_devpath(device
));
137 str
= udev_device_get_devnode(device
);
139 printf("N: %s\n", str
+ strlen("/dev/"));
141 i
= udev_device_get_devlink_priority(device
);
143 printf("L: %i\n", i
);
145 udev_list_entry_foreach(list_entry
, udev_device_get_devlinks_list_entry(device
))
146 printf("S: %s\n", udev_list_entry_get_name(list_entry
) + strlen("/dev/"));
148 udev_list_entry_foreach(list_entry
, udev_device_get_properties_list_entry(device
))
150 udev_list_entry_get_name(list_entry
),
151 udev_list_entry_get_value(list_entry
));
155 static int stat_device(const char *name
, bool export
, const char *prefix
) {
158 if (stat(name
, &statbuf
) != 0)
164 printf("%sMAJOR=%u\n"
166 prefix
, major(statbuf
.st_dev
),
167 prefix
, minor(statbuf
.st_dev
));
169 printf("%u:%u\n", major(statbuf
.st_dev
), minor(statbuf
.st_dev
));
173 static int export_devices(struct udev
*udev
) {
174 _cleanup_udev_enumerate_unref_
struct udev_enumerate
*udev_enumerate
;
175 struct udev_list_entry
*list_entry
;
177 udev_enumerate
= udev_enumerate_new(udev
);
178 if (udev_enumerate
== NULL
)
181 udev_enumerate_scan_devices(udev_enumerate
);
182 udev_list_entry_foreach(list_entry
, udev_enumerate_get_list_entry(udev_enumerate
)) {
183 _cleanup_udev_device_unref_
struct udev_device
*device
;
185 device
= udev_device_new_from_syspath(udev
, udev_list_entry_get_name(list_entry
));
187 print_record(device
);
193 static void cleanup_dir(DIR *dir
, mode_t mask
, int depth
) {
199 for (dent
= readdir(dir
); dent
!= NULL
; dent
= readdir(dir
)) {
202 if (dent
->d_name
[0] == '.')
204 if (fstatat(dirfd(dir
), dent
->d_name
, &stats
, AT_SYMLINK_NOFOLLOW
) != 0)
206 if ((stats
.st_mode
& mask
) != 0)
208 if (S_ISDIR(stats
.st_mode
)) {
209 _cleanup_closedir_
DIR *dir2
;
211 dir2
= fdopendir(openat(dirfd(dir
), dent
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
));
213 cleanup_dir(dir2
, mask
, depth
-1);
215 (void) unlinkat(dirfd(dir
), dent
->d_name
, AT_REMOVEDIR
);
217 (void) unlinkat(dirfd(dir
), dent
->d_name
, 0);
221 static void cleanup_db(struct udev
*udev
) {
222 _cleanup_closedir_
DIR *dir1
= NULL
, *dir2
= NULL
, *dir3
= NULL
, *dir4
= NULL
, *dir5
= NULL
;
224 (void) unlink("/run/udev/queue.bin");
226 dir1
= opendir("/run/udev/data");
228 cleanup_dir(dir1
, S_ISVTX
, 1);
230 dir2
= opendir("/run/udev/links");
232 cleanup_dir(dir2
, 0, 2);
234 dir3
= opendir("/run/udev/tags");
236 cleanup_dir(dir3
, 0, 2);
238 dir4
= opendir("/run/udev/static_node-tags");
240 cleanup_dir(dir4
, 0, 2);
242 dir5
= opendir("/run/udev/watch");
244 cleanup_dir(dir5
, 0, 1);
247 static void help(void) {
249 printf("%s info [OPTIONS] [DEVPATH|FILE]\n\n"
250 "Query sysfs or the udev database.\n\n"
251 " -h --help Print this message\n"
252 " --version Print version of the program\n"
253 " -q --query=TYPE Query device information:\n"
254 " name Name of device node\n"
255 " symlink Pointing to node\n"
256 " path sysfs device path\n"
257 " property The device properties\n"
259 " -p --path=SYSPATH sysfs device path used for query or attribute walk\n"
260 " -n --name=NAME Node or symlink name used for query or attribute walk\n"
261 " -r --root Prepend dev directory to path names\n"
262 " -a --attribute-walk Print all key matches walking along the chain\n"
263 " of parent devices\n"
264 " -d --device-id-of-file=FILE Print major:minor of device containing this file\n"
265 " -x --export Export key/value pairs\n"
266 " -P --export-prefix Export the key name with a prefix\n"
267 " -e --export-db Export the content of the udev database\n"
268 " -c --cleanup-db Clean up the udev database\n"
269 , program_invocation_short_name
);
272 static int uinfo(struct udev
*udev
, int argc
, char *argv
[]) {
273 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
276 const char *export_prefix
= NULL
;
277 char name
[UTIL_PATH_SIZE
];
278 struct udev_list_entry
*list_entry
;
281 static const struct option options
[] = {
282 { "name", required_argument
, NULL
, 'n' },
283 { "path", required_argument
, NULL
, 'p' },
284 { "query", required_argument
, NULL
, 'q' },
285 { "attribute-walk", no_argument
, NULL
, 'a' },
286 { "cleanup-db", no_argument
, NULL
, 'c' },
287 { "export-db", no_argument
, NULL
, 'e' },
288 { "root", no_argument
, NULL
, 'r' },
289 { "device-id-of-file", required_argument
, NULL
, 'd' },
290 { "export", no_argument
, NULL
, 'x' },
291 { "export-prefix", required_argument
, NULL
, 'P' },
292 { "version", no_argument
, NULL
, 'V' },
293 { "help", no_argument
, NULL
, 'h' },
299 ACTION_ATTRIBUTE_WALK
,
300 ACTION_DEVICE_ID_FILE
,
301 } action
= ACTION_QUERY
;
311 while ((c
= getopt_long(argc
, argv
, "aced:n:p:q:rxP:RVh", options
, NULL
)) >= 0)
314 if (device
!= NULL
) {
315 fprintf(stderr
, "device already specified\n");
319 device
= find_device(udev
, optarg
, "/dev/");
320 if (device
== NULL
) {
321 fprintf(stderr
, "device node not found\n");
327 if (device
!= NULL
) {
328 fprintf(stderr
, "device already specified\n");
332 device
= find_device(udev
, optarg
, "/sys");
333 if (device
== NULL
) {
334 fprintf(stderr
, "syspath not found\n");
339 action
= ACTION_QUERY
;
340 if (streq(optarg
, "property") || streq(optarg
, "env"))
341 query
= QUERY_PROPERTY
;
342 else if (streq(optarg
, "name"))
344 else if (streq(optarg
, "symlink"))
345 query
= QUERY_SYMLINK
;
346 else if (streq(optarg
, "path"))
348 else if (streq(optarg
, "all"))
351 fprintf(stderr
, "unknown query type\n");
359 action
= ACTION_DEVICE_ID_FILE
;
360 strscpy(name
, sizeof(name
), optarg
);
363 action
= ACTION_ATTRIBUTE_WALK
;
366 if (export_devices(udev
) < 0)
376 export_prefix
= optarg
;
379 printf("%s\n", VERSION
);
395 device
= find_device(udev
, argv
[optind
], NULL
);
397 fprintf(stderr
, "Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected.\n");
404 const char *node
= udev_device_get_devnode(device
);
407 fprintf(stderr
, "no device node found\n");
412 printf("%s\n", udev_device_get_devnode(device
));
414 printf("%s\n", udev_device_get_devnode(device
) + strlen("/dev/"));
418 list_entry
= udev_device_get_devlinks_list_entry(device
);
419 while (list_entry
!= NULL
) {
421 printf("%s", udev_list_entry_get_name(list_entry
));
423 printf("%s", udev_list_entry_get_name(list_entry
) + strlen("/dev/"));
424 list_entry
= udev_list_entry_get_next(list_entry
);
425 if (list_entry
!= NULL
)
431 printf("%s\n", udev_device_get_devpath(device
));
434 list_entry
= udev_device_get_properties_list_entry(device
);
435 while (list_entry
!= NULL
) {
437 const char *prefix
= export_prefix
;
441 printf("%s%s='%s'\n", prefix
,
442 udev_list_entry_get_name(list_entry
),
443 udev_list_entry_get_value(list_entry
));
445 printf("%s=%s\n", udev_list_entry_get_name(list_entry
), udev_list_entry_get_value(list_entry
));
447 list_entry
= udev_list_entry_get_next(list_entry
);
451 print_record(device
);
454 assert_not_reached("unknown query type");
457 case ACTION_ATTRIBUTE_WALK
:
458 if (!device
&& argv
[optind
]) {
459 device
= find_device(udev
, argv
[optind
], NULL
);
461 fprintf(stderr
, "Unknown device, absolute path in /dev/ or /sys expected.\n");
466 fprintf(stderr
, "Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected.\n");
469 print_device_chain(device
);
471 case ACTION_DEVICE_ID_FILE
:
472 if (stat_device(name
, export
, export_prefix
) != 0)
480 const struct udevadm_cmd udevadm_info
= {
483 .help
= "Query sysfs or the udev database",