1 /* SPDX-License-Identifier: GPL-2.0+ */
3 * Copyright (C) 2004-2009 Kay Sievers <kay@vrfy.org>
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29 #include "dirent-util.h"
31 #include "string-util.h"
32 #include "udev-util.h"
34 #include "udevadm-util.h"
36 static bool skip_attribute(const char *name
) {
37 static const char* const skip
[] = {
48 for (i
= 0; i
< ELEMENTSOF(skip
); i
++)
49 if (streq(name
, skip
[i
]))
54 static void print_all_attributes(struct udev_device
*device
, const char *key
) {
55 struct udev_list_entry
*sysattr
;
57 udev_list_entry_foreach(sysattr
, udev_device_get_sysattr_list_entry(device
)) {
62 name
= udev_list_entry_get_name(sysattr
);
63 if (skip_attribute(name
))
66 value
= udev_device_get_sysattr_value(device
, name
);
70 /* skip any values that look like a path */
74 /* skip nonprintable attributes */
76 while (len
> 0 && isprint(value
[len
-1]))
81 printf(" %s{%s}==\"%s\"\n", key
, name
, value
);
86 static int print_device_chain(struct udev_device
*device
) {
87 struct udev_device
*device_parent
;
91 "Udevadm info starts with the device specified by the devpath and then\n"
92 "walks up the chain of parent devices. It prints for every device\n"
93 "found, all possible attributes in the udev rules key format.\n"
94 "A rule to match, can be composed by the attributes of the device\n"
95 "and the attributes from one single parent device.\n"
98 printf(" looking at device '%s':\n", udev_device_get_devpath(device
));
99 printf(" KERNEL==\"%s\"\n", udev_device_get_sysname(device
));
100 str
= udev_device_get_subsystem(device
);
103 printf(" SUBSYSTEM==\"%s\"\n", str
);
104 str
= udev_device_get_driver(device
);
107 printf(" DRIVER==\"%s\"\n", str
);
108 print_all_attributes(device
, "ATTR");
110 device_parent
= device
;
112 device_parent
= udev_device_get_parent(device_parent
);
113 if (device_parent
== NULL
)
115 printf(" looking at parent device '%s':\n", udev_device_get_devpath(device_parent
));
116 printf(" KERNELS==\"%s\"\n", udev_device_get_sysname(device_parent
));
117 str
= udev_device_get_subsystem(device_parent
);
120 printf(" SUBSYSTEMS==\"%s\"\n", str
);
121 str
= udev_device_get_driver(device_parent
);
124 printf(" DRIVERS==\"%s\"\n", str
);
125 print_all_attributes(device_parent
, "ATTRS");
126 } while (device_parent
!= NULL
);
131 static void print_record(struct udev_device
*device
) {
134 struct udev_list_entry
*list_entry
;
136 printf("P: %s\n", udev_device_get_devpath(device
));
138 str
= udev_device_get_devnode(device
);
140 printf("N: %s\n", str
+ STRLEN("/dev/"));
142 i
= udev_device_get_devlink_priority(device
);
144 printf("L: %i\n", i
);
146 udev_list_entry_foreach(list_entry
, udev_device_get_devlinks_list_entry(device
))
148 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 _cleanup_udev_enumerate_unref_
struct udev_enumerate
*udev_enumerate
;
177 struct udev_list_entry
*list_entry
;
179 udev_enumerate
= udev_enumerate_new(udev
);
180 if (udev_enumerate
== NULL
)
183 udev_enumerate_scan_devices(udev_enumerate
);
184 udev_list_entry_foreach(list_entry
, udev_enumerate_get_list_entry(udev_enumerate
)) {
185 _cleanup_udev_device_unref_
struct udev_device
*device
;
187 device
= udev_device_new_from_syspath(udev
, udev_list_entry_get_name(list_entry
));
189 print_record(device
);
195 static void cleanup_dir(DIR *dir
, mode_t mask
, int depth
) {
201 FOREACH_DIRENT_ALL(dent
, dir
, break) {
204 if (dent
->d_name
[0] == '.')
206 if (fstatat(dirfd(dir
), dent
->d_name
, &stats
, AT_SYMLINK_NOFOLLOW
) != 0)
208 if ((stats
.st_mode
& mask
) != 0)
210 if (S_ISDIR(stats
.st_mode
)) {
211 _cleanup_closedir_
DIR *dir2
;
213 dir2
= fdopendir(openat(dirfd(dir
), dent
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
));
215 cleanup_dir(dir2
, mask
, depth
-1);
217 (void) unlinkat(dirfd(dir
), dent
->d_name
, AT_REMOVEDIR
);
219 (void) unlinkat(dirfd(dir
), dent
->d_name
, 0);
223 static void cleanup_db(struct udev
*udev
) {
224 _cleanup_closedir_
DIR *dir1
= NULL
, *dir2
= NULL
, *dir3
= NULL
, *dir4
= NULL
, *dir5
= NULL
;
226 (void) unlink("/run/udev/queue.bin");
228 dir1
= opendir("/run/udev/data");
230 cleanup_dir(dir1
, S_ISVTX
, 1);
232 dir2
= opendir("/run/udev/links");
234 cleanup_dir(dir2
, 0, 2);
236 dir3
= opendir("/run/udev/tags");
238 cleanup_dir(dir3
, 0, 2);
240 dir4
= opendir("/run/udev/static_node-tags");
242 cleanup_dir(dir4
, 0, 2);
244 dir5
= opendir("/run/udev/watch");
246 cleanup_dir(dir5
, 0, 1);
249 static void help(void) {
251 printf("%s info [OPTIONS] [DEVPATH|FILE]\n\n"
252 "Query sysfs or the udev database.\n\n"
253 " -h --help Print this message\n"
254 " -V --version Print version of the program\n"
255 " -q --query=TYPE Query device information:\n"
256 " name Name of device node\n"
257 " symlink Pointing to node\n"
258 " path sysfs device path\n"
259 " property The device properties\n"
261 " -p --path=SYSPATH sysfs device path used for query or attribute walk\n"
262 " -n --name=NAME Node or symlink name used for query or attribute walk\n"
263 " -r --root Prepend dev directory to path names\n"
264 " -a --attribute-walk Print all key matches walking along the chain\n"
265 " of parent devices\n"
266 " -d --device-id-of-file=FILE Print major:minor of device containing this file\n"
267 " -x --export Export key/value pairs\n"
268 " -P --export-prefix Export the key name with a prefix\n"
269 " -e --export-db Export the content of the udev database\n"
270 " -c --cleanup-db Clean up the udev database\n"
271 , program_invocation_short_name
);
274 static int uinfo(struct udev
*udev
, int argc
, char *argv
[]) {
275 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
278 const char *export_prefix
= NULL
;
279 char name
[UTIL_PATH_SIZE
];
280 struct udev_list_entry
*list_entry
;
283 static const struct option options
[] = {
284 { "name", required_argument
, NULL
, 'n' },
285 { "path", required_argument
, NULL
, 'p' },
286 { "query", required_argument
, NULL
, 'q' },
287 { "attribute-walk", no_argument
, NULL
, 'a' },
288 { "cleanup-db", no_argument
, NULL
, 'c' },
289 { "export-db", no_argument
, NULL
, 'e' },
290 { "root", no_argument
, NULL
, 'r' },
291 { "device-id-of-file", required_argument
, NULL
, 'd' },
292 { "export", no_argument
, NULL
, 'x' },
293 { "export-prefix", required_argument
, NULL
, 'P' },
294 { "version", no_argument
, NULL
, 'V' },
295 { "help", no_argument
, NULL
, 'h' },
301 ACTION_ATTRIBUTE_WALK
,
302 ACTION_DEVICE_ID_FILE
,
303 } action
= ACTION_QUERY
;
313 while ((c
= getopt_long(argc
, argv
, "aced:n:p:q:rxP:RVh", options
, NULL
)) >= 0)
316 if (device
!= NULL
) {
317 fprintf(stderr
, "device already specified\n");
321 device
= find_device(udev
, optarg
, "/dev/");
322 if (device
== NULL
) {
323 fprintf(stderr
, "device node not found\n");
329 if (device
!= NULL
) {
330 fprintf(stderr
, "device already specified\n");
334 device
= find_device(udev
, optarg
, "/sys");
335 if (device
== NULL
) {
336 fprintf(stderr
, "syspath not found\n");
341 action
= ACTION_QUERY
;
342 if (streq(optarg
, "property") || streq(optarg
, "env"))
343 query
= QUERY_PROPERTY
;
344 else if (streq(optarg
, "name"))
346 else if (streq(optarg
, "symlink"))
347 query
= QUERY_SYMLINK
;
348 else if (streq(optarg
, "path"))
350 else if (streq(optarg
, "all"))
353 fprintf(stderr
, "unknown query type\n");
361 action
= ACTION_DEVICE_ID_FILE
;
362 strscpy(name
, sizeof(name
), optarg
);
365 action
= ACTION_ATTRIBUTE_WALK
;
368 if (export_devices(udev
) < 0)
378 export_prefix
= optarg
;
397 device
= find_device(udev
, argv
[optind
], NULL
);
399 fprintf(stderr
, "Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected.\n");
406 const char *node
= udev_device_get_devnode(device
);
409 fprintf(stderr
, "no device node found\n");
414 printf("%s\n", udev_device_get_devnode(device
));
417 udev_device_get_devnode(device
) + STRLEN("/dev/"));
421 list_entry
= udev_device_get_devlinks_list_entry(device
);
422 while (list_entry
!= NULL
) {
424 printf("%s", udev_list_entry_get_name(list_entry
));
427 udev_list_entry_get_name(list_entry
) + STRLEN("/dev/"));
428 list_entry
= udev_list_entry_get_next(list_entry
);
429 if (list_entry
!= NULL
)
435 printf("%s\n", udev_device_get_devpath(device
));
438 list_entry
= udev_device_get_properties_list_entry(device
);
439 while (list_entry
!= NULL
) {
441 printf("%s%s='%s'\n", strempty(export_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",