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/>.
29 #include "string-util.h"
30 #include "udev-util.h"
32 #include "udevadm-util.h"
34 static bool skip_attribute(const char *name
) {
35 static const char* const skip
[] = {
46 for (i
= 0; i
< ELEMENTSOF(skip
); i
++)
47 if (streq(name
, skip
[i
]))
52 static void print_all_attributes(struct udev_device
*device
, const char *key
) {
53 struct udev_list_entry
*sysattr
;
55 udev_list_entry_foreach(sysattr
, udev_device_get_sysattr_list_entry(device
)) {
60 name
= udev_list_entry_get_name(sysattr
);
61 if (skip_attribute(name
))
64 value
= udev_device_get_sysattr_value(device
, name
);
68 /* skip any values that look like a path */
72 /* skip nonprintable attributes */
74 while (len
> 0 && isprint(value
[len
-1]))
79 printf(" %s{%s}==\"%s\"\n", key
, name
, value
);
84 static int print_device_chain(struct udev_device
*device
) {
85 struct udev_device
*device_parent
;
89 "Udevadm info starts with the device specified by the devpath and then\n"
90 "walks up the chain of parent devices. It prints for every device\n"
91 "found, all possible attributes in the udev rules key format.\n"
92 "A rule to match, can be composed by the attributes of the device\n"
93 "and the attributes from one single parent device.\n"
96 printf(" looking at device '%s':\n", udev_device_get_devpath(device
));
97 printf(" KERNEL==\"%s\"\n", udev_device_get_sysname(device
));
98 str
= udev_device_get_subsystem(device
);
101 printf(" SUBSYSTEM==\"%s\"\n", str
);
102 str
= udev_device_get_driver(device
);
105 printf(" DRIVER==\"%s\"\n", str
);
106 print_all_attributes(device
, "ATTR");
108 device_parent
= device
;
110 device_parent
= udev_device_get_parent(device_parent
);
111 if (device_parent
== NULL
)
113 printf(" looking at parent device '%s':\n", udev_device_get_devpath(device_parent
));
114 printf(" KERNELS==\"%s\"\n", udev_device_get_sysname(device_parent
));
115 str
= udev_device_get_subsystem(device_parent
);
118 printf(" SUBSYSTEMS==\"%s\"\n", str
);
119 str
= udev_device_get_driver(device_parent
);
122 printf(" DRIVERS==\"%s\"\n", str
);
123 print_all_attributes(device_parent
, "ATTRS");
124 } while (device_parent
!= NULL
);
129 static void print_record(struct udev_device
*device
) {
132 struct udev_list_entry
*list_entry
;
134 printf("P: %s\n", udev_device_get_devpath(device
));
136 str
= udev_device_get_devnode(device
);
138 printf("N: %s\n", str
+ strlen("/dev/"));
140 i
= udev_device_get_devlink_priority(device
);
142 printf("L: %i\n", i
);
144 udev_list_entry_foreach(list_entry
, udev_device_get_devlinks_list_entry(device
))
145 printf("S: %s\n", udev_list_entry_get_name(list_entry
) + strlen("/dev/"));
147 udev_list_entry_foreach(list_entry
, udev_device_get_properties_list_entry(device
))
149 udev_list_entry_get_name(list_entry
),
150 udev_list_entry_get_value(list_entry
));
154 static int stat_device(const char *name
, bool export
, const char *prefix
) {
157 if (stat(name
, &statbuf
) != 0)
163 printf("%sMAJOR=%u\n"
165 prefix
, major(statbuf
.st_dev
),
166 prefix
, minor(statbuf
.st_dev
));
168 printf("%u:%u\n", major(statbuf
.st_dev
), minor(statbuf
.st_dev
));
172 static int export_devices(struct udev
*udev
) {
173 struct udev_enumerate
*udev_enumerate
;
174 struct udev_list_entry
*list_entry
;
176 udev_enumerate
= udev_enumerate_new(udev
);
177 if (udev_enumerate
== NULL
)
179 udev_enumerate_scan_devices(udev_enumerate
);
180 udev_list_entry_foreach(list_entry
, udev_enumerate_get_list_entry(udev_enumerate
)) {
181 struct udev_device
*device
;
183 device
= udev_device_new_from_syspath(udev
, udev_list_entry_get_name(list_entry
));
184 if (device
!= NULL
) {
185 print_record(device
);
186 udev_device_unref(device
);
189 udev_enumerate_unref(udev_enumerate
);
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
) {
224 unlink("/run/udev/queue.bin");
226 dir
= opendir("/run/udev/data");
228 cleanup_dir(dir
, S_ISVTX
, 1);
232 dir
= opendir("/run/udev/links");
234 cleanup_dir(dir
, 0, 2);
238 dir
= opendir("/run/udev/tags");
240 cleanup_dir(dir
, 0, 2);
244 dir
= opendir("/run/udev/static_node-tags");
246 cleanup_dir(dir
, 0, 2);
250 dir
= opendir("/run/udev/watch");
252 cleanup_dir(dir
, 0, 1);
257 static void help(void) {
259 printf("%s info [OPTIONS] [DEVPATH|FILE]\n\n"
260 "Query sysfs or the udev database.\n\n"
261 " -h --help Print this message\n"
262 " --version Print version of the program\n"
263 " -q --query=TYPE Query device information:\n"
264 " name Name of device node\n"
265 " symlink Pointing to node\n"
266 " path sysfs device path\n"
267 " property The device properties\n"
269 " -p --path=SYSPATH sysfs device path used for query or attribute walk\n"
270 " -n --name=NAME Node or symlink name used for query or attribute walk\n"
271 " -r --root Prepend dev directory to path names\n"
272 " -a --attribute-walk Print all key matches walking along the chain\n"
273 " of parent devices\n"
274 " -d --device-id-of-file=FILE Print major:minor of device containing this file\n"
275 " -x --export Export key/value pairs\n"
276 " -P --export-prefix Export the key name with a prefix\n"
277 " -e --export-db Export the content of the udev database\n"
278 " -c --cleanup-db Clean up the udev database\n"
279 , program_invocation_short_name
);
282 static int uinfo(struct udev
*udev
, int argc
, char *argv
[]) {
283 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
286 const char *export_prefix
= NULL
;
287 char name
[UTIL_PATH_SIZE
];
288 struct udev_list_entry
*list_entry
;
291 static const struct option options
[] = {
292 { "name", required_argument
, NULL
, 'n' },
293 { "path", required_argument
, NULL
, 'p' },
294 { "query", required_argument
, NULL
, 'q' },
295 { "attribute-walk", no_argument
, NULL
, 'a' },
296 { "cleanup-db", no_argument
, NULL
, 'c' },
297 { "export-db", no_argument
, NULL
, 'e' },
298 { "root", no_argument
, NULL
, 'r' },
299 { "device-id-of-file", required_argument
, NULL
, 'd' },
300 { "export", no_argument
, NULL
, 'x' },
301 { "export-prefix", required_argument
, NULL
, 'P' },
302 { "version", no_argument
, NULL
, 'V' },
303 { "help", no_argument
, NULL
, 'h' },
309 ACTION_ATTRIBUTE_WALK
,
310 ACTION_DEVICE_ID_FILE
,
311 } action
= ACTION_QUERY
;
321 while ((c
= getopt_long(argc
, argv
, "aced:n:p:q:rxP:RVh", options
, NULL
)) >= 0)
324 if (device
!= NULL
) {
325 fprintf(stderr
, "device already specified\n");
329 device
= find_device(udev
, optarg
, "/dev/");
330 if (device
== NULL
) {
331 fprintf(stderr
, "device node not found\n");
337 if (device
!= NULL
) {
338 fprintf(stderr
, "device already specified\n");
342 device
= find_device(udev
, optarg
, "/sys");
343 if (device
== NULL
) {
344 fprintf(stderr
, "syspath not found\n");
349 action
= ACTION_QUERY
;
350 if (streq(optarg
, "property") || streq(optarg
, "env"))
351 query
= QUERY_PROPERTY
;
352 else if (streq(optarg
, "name"))
354 else if (streq(optarg
, "symlink"))
355 query
= QUERY_SYMLINK
;
356 else if (streq(optarg
, "path"))
358 else if (streq(optarg
, "all"))
361 fprintf(stderr
, "unknown query type\n");
369 action
= ACTION_DEVICE_ID_FILE
;
370 strscpy(name
, sizeof(name
), optarg
);
373 action
= ACTION_ATTRIBUTE_WALK
;
376 export_devices(udev
);
385 export_prefix
= optarg
;
388 printf("%s\n", VERSION
);
404 device
= find_device(udev
, argv
[optind
], NULL
);
406 fprintf(stderr
, "Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected.\n");
413 const char *node
= udev_device_get_devnode(device
);
416 fprintf(stderr
, "no device node found\n");
421 printf("%s\n", udev_device_get_devnode(device
));
423 printf("%s\n", udev_device_get_devnode(device
) + strlen("/dev/"));
427 list_entry
= udev_device_get_devlinks_list_entry(device
);
428 while (list_entry
!= NULL
) {
430 printf("%s", udev_list_entry_get_name(list_entry
));
432 printf("%s", udev_list_entry_get_name(list_entry
) + strlen("/dev/"));
433 list_entry
= udev_list_entry_get_next(list_entry
);
434 if (list_entry
!= NULL
)
440 printf("%s\n", udev_device_get_devpath(device
));
443 list_entry
= udev_device_get_properties_list_entry(device
);
444 while (list_entry
!= NULL
) {
446 const char *prefix
= export_prefix
;
450 printf("%s%s='%s'\n", prefix
,
451 udev_list_entry_get_name(list_entry
),
452 udev_list_entry_get_value(list_entry
));
454 printf("%s=%s\n", udev_list_entry_get_name(list_entry
), udev_list_entry_get_value(list_entry
));
456 list_entry
= udev_list_entry_get_next(list_entry
);
460 print_record(device
);
463 assert_not_reached("unknown query type");
466 case ACTION_ATTRIBUTE_WALK
:
467 if (!device
&& argv
[optind
]) {
468 device
= find_device(udev
, argv
[optind
], NULL
);
470 fprintf(stderr
, "Unknown device, absolute path in /dev/ or /sys expected.\n");
475 fprintf(stderr
, "Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected.\n");
478 print_device_chain(device
);
480 case ACTION_DEVICE_ID_FILE
:
481 if (stat_device(name
, export
, export_prefix
) != 0)
489 const struct udevadm_cmd udevadm_info
= {
492 .help
= "Query sysfs or the udev database",