1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 * Copyright (C) 2004-2009 Kay Sievers <kay@vrfy.org>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
32 #include "string-util.h"
33 #include "udev-util.h"
35 #include "udevadm-util.h"
37 static bool skip_attribute(const char *name
) {
38 static const char* const skip
[] = {
49 for (i
= 0; i
< ELEMENTSOF(skip
); i
++)
50 if (streq(name
, skip
[i
]))
55 static void print_all_attributes(struct udev_device
*device
, const char *key
) {
56 struct udev_list_entry
*sysattr
;
58 udev_list_entry_foreach(sysattr
, udev_device_get_sysattr_list_entry(device
)) {
63 name
= udev_list_entry_get_name(sysattr
);
64 if (skip_attribute(name
))
67 value
= udev_device_get_sysattr_value(device
, name
);
71 /* skip any values that look like a path */
75 /* skip nonprintable attributes */
77 while (len
> 0 && isprint(value
[len
-1]))
82 printf(" %s{%s}==\"%s\"\n", key
, name
, value
);
87 static int print_device_chain(struct udev_device
*device
) {
88 struct udev_device
*device_parent
;
92 "Udevadm info starts with the device specified by the devpath and then\n"
93 "walks up the chain of parent devices. It prints for every device\n"
94 "found, all possible attributes in the udev rules key format.\n"
95 "A rule to match, can be composed by the attributes of the device\n"
96 "and the attributes from one single parent device.\n"
99 printf(" looking at device '%s':\n", udev_device_get_devpath(device
));
100 printf(" KERNEL==\"%s\"\n", udev_device_get_sysname(device
));
101 str
= udev_device_get_subsystem(device
);
104 printf(" SUBSYSTEM==\"%s\"\n", str
);
105 str
= udev_device_get_driver(device
);
108 printf(" DRIVER==\"%s\"\n", str
);
109 print_all_attributes(device
, "ATTR");
111 device_parent
= device
;
113 device_parent
= udev_device_get_parent(device_parent
);
114 if (device_parent
== NULL
)
116 printf(" looking at parent device '%s':\n", udev_device_get_devpath(device_parent
));
117 printf(" KERNELS==\"%s\"\n", udev_device_get_sysname(device_parent
));
118 str
= udev_device_get_subsystem(device_parent
);
121 printf(" SUBSYSTEMS==\"%s\"\n", str
);
122 str
= udev_device_get_driver(device_parent
);
125 printf(" DRIVERS==\"%s\"\n", str
);
126 print_all_attributes(device_parent
, "ATTRS");
127 } while (device_parent
!= NULL
);
132 static void print_record(struct udev_device
*device
) {
135 struct udev_list_entry
*list_entry
;
137 printf("P: %s\n", udev_device_get_devpath(device
));
139 str
= udev_device_get_devnode(device
);
141 printf("N: %s\n", str
+ strlen("/dev/"));
143 i
= udev_device_get_devlink_priority(device
);
145 printf("L: %i\n", i
);
147 udev_list_entry_foreach(list_entry
, udev_device_get_devlinks_list_entry(device
))
148 printf("S: %s\n", udev_list_entry_get_name(list_entry
) + strlen("/dev/"));
150 udev_list_entry_foreach(list_entry
, udev_device_get_properties_list_entry(device
))
152 udev_list_entry_get_name(list_entry
),
153 udev_list_entry_get_value(list_entry
));
157 static int stat_device(const char *name
, bool export
, const char *prefix
) {
160 if (stat(name
, &statbuf
) != 0)
166 printf("%sMAJOR=%u\n"
168 prefix
, major(statbuf
.st_dev
),
169 prefix
, minor(statbuf
.st_dev
));
171 printf("%u:%u\n", major(statbuf
.st_dev
), minor(statbuf
.st_dev
));
175 static int export_devices(struct udev
*udev
) {
176 struct udev_enumerate
*udev_enumerate
;
177 struct udev_list_entry
*list_entry
;
179 udev_enumerate
= udev_enumerate_new(udev
);
180 if (udev_enumerate
== NULL
)
182 udev_enumerate_scan_devices(udev_enumerate
);
183 udev_list_entry_foreach(list_entry
, udev_enumerate_get_list_entry(udev_enumerate
)) {
184 struct udev_device
*device
;
186 device
= udev_device_new_from_syspath(udev
, udev_list_entry_get_name(list_entry
));
187 if (device
!= NULL
) {
188 print_record(device
);
189 udev_device_unref(device
);
192 udev_enumerate_unref(udev_enumerate
);
196 static void cleanup_dir(DIR *dir
, mode_t mask
, int depth
) {
202 for (dent
= readdir(dir
); dent
!= NULL
; dent
= readdir(dir
)) {
205 if (dent
->d_name
[0] == '.')
207 if (fstatat(dirfd(dir
), dent
->d_name
, &stats
, AT_SYMLINK_NOFOLLOW
) != 0)
209 if ((stats
.st_mode
& mask
) != 0)
211 if (S_ISDIR(stats
.st_mode
)) {
212 _cleanup_closedir_
DIR *dir2
;
214 dir2
= fdopendir(openat(dirfd(dir
), dent
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
));
216 cleanup_dir(dir2
, mask
, depth
-1);
218 (void) unlinkat(dirfd(dir
), dent
->d_name
, AT_REMOVEDIR
);
220 (void) unlinkat(dirfd(dir
), dent
->d_name
, 0);
224 static void cleanup_db(struct udev
*udev
) {
227 unlink("/run/udev/queue.bin");
229 dir
= opendir("/run/udev/data");
231 cleanup_dir(dir
, S_ISVTX
, 1);
235 dir
= opendir("/run/udev/links");
237 cleanup_dir(dir
, 0, 2);
241 dir
= opendir("/run/udev/tags");
243 cleanup_dir(dir
, 0, 2);
247 dir
= opendir("/run/udev/static_node-tags");
249 cleanup_dir(dir
, 0, 2);
253 dir
= opendir("/run/udev/watch");
255 cleanup_dir(dir
, 0, 1);
260 static void help(void) {
262 printf("%s info [OPTIONS] [DEVPATH|FILE]\n\n"
263 "Query sysfs or the udev database.\n\n"
264 " -h --help Print this message\n"
265 " --version Print version of the program\n"
266 " -q --query=TYPE Query device information:\n"
267 " name Name of device node\n"
268 " symlink Pointing to node\n"
269 " path sysfs device path\n"
270 " property The device properties\n"
272 " -p --path=SYSPATH sysfs device path used for query or attribute walk\n"
273 " -n --name=NAME Node or symlink name used for query or attribute walk\n"
274 " -r --root Prepend dev directory to path names\n"
275 " -a --attribute-walk Print all key matches walking along the chain\n"
276 " of parent devices\n"
277 " -d --device-id-of-file=FILE Print major:minor of device containing this file\n"
278 " -x --export Export key/value pairs\n"
279 " -P --export-prefix Export the key name with a prefix\n"
280 " -e --export-db Export the content of the udev database\n"
281 " -c --cleanup-db Clean up the udev database\n"
282 , program_invocation_short_name
);
285 static int uinfo(struct udev
*udev
, int argc
, char *argv
[]) {
286 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
289 const char *export_prefix
= NULL
;
290 char name
[UTIL_PATH_SIZE
];
291 struct udev_list_entry
*list_entry
;
294 static const struct option options
[] = {
295 { "name", required_argument
, NULL
, 'n' },
296 { "path", required_argument
, NULL
, 'p' },
297 { "query", required_argument
, NULL
, 'q' },
298 { "attribute-walk", no_argument
, NULL
, 'a' },
299 { "cleanup-db", no_argument
, NULL
, 'c' },
300 { "export-db", no_argument
, NULL
, 'e' },
301 { "root", no_argument
, NULL
, 'r' },
302 { "device-id-of-file", required_argument
, NULL
, 'd' },
303 { "export", no_argument
, NULL
, 'x' },
304 { "export-prefix", required_argument
, NULL
, 'P' },
305 { "version", no_argument
, NULL
, 'V' },
306 { "help", no_argument
, NULL
, 'h' },
312 ACTION_ATTRIBUTE_WALK
,
313 ACTION_DEVICE_ID_FILE
,
314 } action
= ACTION_QUERY
;
324 while ((c
= getopt_long(argc
, argv
, "aced:n:p:q:rxP:RVh", options
, NULL
)) >= 0)
327 if (device
!= NULL
) {
328 fprintf(stderr
, "device already specified\n");
332 device
= find_device(udev
, optarg
, "/dev/");
333 if (device
== NULL
) {
334 fprintf(stderr
, "device node not found\n");
340 if (device
!= NULL
) {
341 fprintf(stderr
, "device already specified\n");
345 device
= find_device(udev
, optarg
, "/sys");
346 if (device
== NULL
) {
347 fprintf(stderr
, "syspath not found\n");
352 action
= ACTION_QUERY
;
353 if (streq(optarg
, "property") || streq(optarg
, "env"))
354 query
= QUERY_PROPERTY
;
355 else if (streq(optarg
, "name"))
357 else if (streq(optarg
, "symlink"))
358 query
= QUERY_SYMLINK
;
359 else if (streq(optarg
, "path"))
361 else if (streq(optarg
, "all"))
364 fprintf(stderr
, "unknown query type\n");
372 action
= ACTION_DEVICE_ID_FILE
;
373 strscpy(name
, sizeof(name
), optarg
);
376 action
= ACTION_ATTRIBUTE_WALK
;
379 export_devices(udev
);
388 export_prefix
= optarg
;
391 printf("%s\n", VERSION
);
407 device
= find_device(udev
, argv
[optind
], NULL
);
409 fprintf(stderr
, "Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected.\n");
416 const char *node
= udev_device_get_devnode(device
);
419 fprintf(stderr
, "no device node found\n");
424 printf("%s\n", udev_device_get_devnode(device
));
426 printf("%s\n", udev_device_get_devnode(device
) + strlen("/dev/"));
430 list_entry
= udev_device_get_devlinks_list_entry(device
);
431 while (list_entry
!= NULL
) {
433 printf("%s", udev_list_entry_get_name(list_entry
));
435 printf("%s", udev_list_entry_get_name(list_entry
) + strlen("/dev/"));
436 list_entry
= udev_list_entry_get_next(list_entry
);
437 if (list_entry
!= NULL
)
443 printf("%s\n", udev_device_get_devpath(device
));
446 list_entry
= udev_device_get_properties_list_entry(device
);
447 while (list_entry
!= NULL
) {
449 const char *prefix
= export_prefix
;
453 printf("%s%s='%s'\n", prefix
,
454 udev_list_entry_get_name(list_entry
),
455 udev_list_entry_get_value(list_entry
));
457 printf("%s=%s\n", udev_list_entry_get_name(list_entry
), udev_list_entry_get_value(list_entry
));
459 list_entry
= udev_list_entry_get_next(list_entry
);
463 print_record(device
);
466 assert_not_reached("unknown query type");
469 case ACTION_ATTRIBUTE_WALK
:
470 if (!device
&& argv
[optind
]) {
471 device
= find_device(udev
, argv
[optind
], NULL
);
473 fprintf(stderr
, "Unknown device, absolute path in /dev/ or /sys expected.\n");
478 fprintf(stderr
, "Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected.\n");
481 print_device_chain(device
);
483 case ACTION_DEVICE_ID_FILE
:
484 if (stat_device(name
, export
, export_prefix
) != 0)
492 const struct udevadm_cmd udevadm_info
= {
495 .help
= "Query sysfs or the udev database",