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 "udev-util.h"
31 #include "udevadm-util.h"
33 static bool skip_attribute(const char *name
) {
34 static const char* const skip
[] = {
45 for (i
= 0; i
< ELEMENTSOF(skip
); i
++)
46 if (streq(name
, skip
[i
]))
51 static void print_all_attributes(struct udev_device
*device
, const char *key
) {
52 struct udev_list_entry
*sysattr
;
54 udev_list_entry_foreach(sysattr
, udev_device_get_sysattr_list_entry(device
)) {
59 name
= udev_list_entry_get_name(sysattr
);
60 if (skip_attribute(name
))
63 value
= udev_device_get_sysattr_value(device
, name
);
67 /* skip any values that look like a path */
71 /* skip nonprintable attributes */
73 while (len
> 0 && isprint(value
[len
-1]))
78 printf(" %s{%s}==\"%s\"\n", key
, name
, value
);
83 static int print_device_chain(struct udev_device
*device
) {
84 struct udev_device
*device_parent
;
88 "Udevadm info starts with the device specified by the devpath and then\n"
89 "walks up the chain of parent devices. It prints for every device\n"
90 "found, all possible attributes in the udev rules key format.\n"
91 "A rule to match, can be composed by the attributes of the device\n"
92 "and the attributes from one single parent device.\n"
95 printf(" looking at device '%s':\n", udev_device_get_devpath(device
));
96 printf(" KERNEL==\"%s\"\n", udev_device_get_sysname(device
));
97 str
= udev_device_get_subsystem(device
);
100 printf(" SUBSYSTEM==\"%s\"\n", str
);
101 str
= udev_device_get_driver(device
);
104 printf(" DRIVER==\"%s\"\n", str
);
105 print_all_attributes(device
, "ATTR");
107 device_parent
= device
;
109 device_parent
= udev_device_get_parent(device_parent
);
110 if (device_parent
== NULL
)
112 printf(" looking at parent device '%s':\n", udev_device_get_devpath(device_parent
));
113 printf(" KERNELS==\"%s\"\n", udev_device_get_sysname(device_parent
));
114 str
= udev_device_get_subsystem(device_parent
);
117 printf(" SUBSYSTEMS==\"%s\"\n", str
);
118 str
= udev_device_get_driver(device_parent
);
121 printf(" DRIVERS==\"%s\"\n", str
);
122 print_all_attributes(device_parent
, "ATTRS");
123 } while (device_parent
!= NULL
);
128 static void print_record(struct udev_device
*device
) {
131 struct udev_list_entry
*list_entry
;
133 printf("P: %s\n", udev_device_get_devpath(device
));
135 str
= udev_device_get_devnode(device
);
137 printf("N: %s\n", str
+ strlen("/dev/"));
139 i
= udev_device_get_devlink_priority(device
);
141 printf("L: %i\n", i
);
143 udev_list_entry_foreach(list_entry
, udev_device_get_devlinks_list_entry(device
))
144 printf("S: %s\n", udev_list_entry_get_name(list_entry
) + strlen("/dev/"));
146 udev_list_entry_foreach(list_entry
, udev_device_get_properties_list_entry(device
))
148 udev_list_entry_get_name(list_entry
),
149 udev_list_entry_get_value(list_entry
));
153 static int stat_device(const char *name
, bool export
, const char *prefix
) {
156 if (stat(name
, &statbuf
) != 0)
162 printf("%sMAJOR=%u\n"
164 prefix
, major(statbuf
.st_dev
),
165 prefix
, minor(statbuf
.st_dev
));
167 printf("%u:%u\n", major(statbuf
.st_dev
), minor(statbuf
.st_dev
));
171 static int export_devices(struct udev
*udev
) {
172 struct udev_enumerate
*udev_enumerate
;
173 struct udev_list_entry
*list_entry
;
175 udev_enumerate
= udev_enumerate_new(udev
);
176 if (udev_enumerate
== NULL
)
178 udev_enumerate_scan_devices(udev_enumerate
);
179 udev_list_entry_foreach(list_entry
, udev_enumerate_get_list_entry(udev_enumerate
)) {
180 struct udev_device
*device
;
182 device
= udev_device_new_from_syspath(udev
, udev_list_entry_get_name(list_entry
));
183 if (device
!= NULL
) {
184 print_record(device
);
185 udev_device_unref(device
);
188 udev_enumerate_unref(udev_enumerate
);
192 static void cleanup_dir(DIR *dir
, mode_t mask
, int depth
) {
198 for (dent
= readdir(dir
); dent
!= NULL
; dent
= readdir(dir
)) {
201 if (dent
->d_name
[0] == '.')
203 if (fstatat(dirfd(dir
), dent
->d_name
, &stats
, AT_SYMLINK_NOFOLLOW
) != 0)
205 if ((stats
.st_mode
& mask
) != 0)
207 if (S_ISDIR(stats
.st_mode
)) {
208 _cleanup_closedir_
DIR *dir2
;
210 dir2
= fdopendir(openat(dirfd(dir
), dent
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
));
212 cleanup_dir(dir2
, mask
, depth
-1);
214 (void) unlinkat(dirfd(dir
), dent
->d_name
, AT_REMOVEDIR
);
216 (void) unlinkat(dirfd(dir
), dent
->d_name
, 0);
220 static void cleanup_db(struct udev
*udev
) {
223 unlink("/run/udev/queue.bin");
225 dir
= opendir("/run/udev/data");
227 cleanup_dir(dir
, S_ISVTX
, 1);
231 dir
= opendir("/run/udev/links");
233 cleanup_dir(dir
, 0, 2);
237 dir
= opendir("/run/udev/tags");
239 cleanup_dir(dir
, 0, 2);
243 dir
= opendir("/run/udev/static_node-tags");
245 cleanup_dir(dir
, 0, 2);
249 dir
= opendir("/run/udev/watch");
251 cleanup_dir(dir
, 0, 1);
256 static void help(void) {
258 printf("%s info [OPTIONS] [DEVPATH|FILE]\n\n"
259 "Query sysfs or the udev database.\n\n"
260 " -h --help Print this message\n"
261 " --version Print version of the program\n"
262 " -q --query=TYPE Query device information:\n"
263 " name Name of device node\n"
264 " symlink Pointing to node\n"
265 " path sysfs device path\n"
266 " property The device properties\n"
268 " -p --path=SYSPATH sysfs device path used for query or attribute walk\n"
269 " -n --name=NAME Node or symlink name used for query or attribute walk\n"
270 " -r --root Prepend dev directory to path names\n"
271 " -a --attribute-walk Print all key matches walking along the chain\n"
272 " of parent devices\n"
273 " -d --device-id-of-file=FILE Print major:minor of device containing this file\n"
274 " -x --export Export key/value pairs\n"
275 " -P --export-prefix Export the key name with a prefix\n"
276 " -e --export-db Export the content of the udev database\n"
277 " -c --cleanup-db Clean up the udev database\n"
278 , program_invocation_short_name
);
281 static int uinfo(struct udev
*udev
, int argc
, char *argv
[]) {
282 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
285 const char *export_prefix
= NULL
;
286 char name
[UTIL_PATH_SIZE
];
287 struct udev_list_entry
*list_entry
;
290 static const struct option options
[] = {
291 { "name", required_argument
, NULL
, 'n' },
292 { "path", required_argument
, NULL
, 'p' },
293 { "query", required_argument
, NULL
, 'q' },
294 { "attribute-walk", no_argument
, NULL
, 'a' },
295 { "cleanup-db", no_argument
, NULL
, 'c' },
296 { "export-db", no_argument
, NULL
, 'e' },
297 { "root", no_argument
, NULL
, 'r' },
298 { "device-id-of-file", required_argument
, NULL
, 'd' },
299 { "export", no_argument
, NULL
, 'x' },
300 { "export-prefix", required_argument
, NULL
, 'P' },
301 { "version", no_argument
, NULL
, 'V' },
302 { "help", no_argument
, NULL
, 'h' },
308 ACTION_ATTRIBUTE_WALK
,
309 ACTION_DEVICE_ID_FILE
,
310 } action
= ACTION_QUERY
;
320 while ((c
= getopt_long(argc
, argv
, "aced:n:p:q:rxP:RVh", options
, NULL
)) >= 0)
323 if (device
!= NULL
) {
324 fprintf(stderr
, "device already specified\n");
328 device
= find_device(udev
, optarg
, "/dev/");
329 if (device
== NULL
) {
330 fprintf(stderr
, "device node not found\n");
336 if (device
!= NULL
) {
337 fprintf(stderr
, "device already specified\n");
341 device
= find_device(udev
, optarg
, "/sys");
342 if (device
== NULL
) {
343 fprintf(stderr
, "syspath not found\n");
348 action
= ACTION_QUERY
;
349 if (streq(optarg
, "property") || streq(optarg
, "env"))
350 query
= QUERY_PROPERTY
;
351 else if (streq(optarg
, "name"))
353 else if (streq(optarg
, "symlink"))
354 query
= QUERY_SYMLINK
;
355 else if (streq(optarg
, "path"))
357 else if (streq(optarg
, "all"))
360 fprintf(stderr
, "unknown query type\n");
368 action
= ACTION_DEVICE_ID_FILE
;
369 strscpy(name
, sizeof(name
), optarg
);
372 action
= ACTION_ATTRIBUTE_WALK
;
375 export_devices(udev
);
384 export_prefix
= optarg
;
387 printf("%s\n", VERSION
);
403 device
= find_device(udev
, argv
[optind
], NULL
);
405 fprintf(stderr
, "Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected.\n");
412 const char *node
= udev_device_get_devnode(device
);
415 fprintf(stderr
, "no device node found\n");
420 printf("%s\n", udev_device_get_devnode(device
));
422 printf("%s\n", udev_device_get_devnode(device
) + strlen("/dev/"));
426 list_entry
= udev_device_get_devlinks_list_entry(device
);
427 while (list_entry
!= NULL
) {
429 printf("%s", udev_list_entry_get_name(list_entry
));
431 printf("%s", udev_list_entry_get_name(list_entry
) + strlen("/dev/"));
432 list_entry
= udev_list_entry_get_next(list_entry
);
433 if (list_entry
!= NULL
)
439 printf("%s\n", udev_device_get_devpath(device
));
442 list_entry
= udev_device_get_properties_list_entry(device
);
443 while (list_entry
!= NULL
) {
445 const char *prefix
= export_prefix
;
449 printf("%s%s='%s'\n", prefix
,
450 udev_list_entry_get_name(list_entry
),
451 udev_list_entry_get_value(list_entry
));
453 printf("%s=%s\n", udev_list_entry_get_name(list_entry
), udev_list_entry_get_value(list_entry
));
455 list_entry
= udev_list_entry_get_next(list_entry
);
459 print_record(device
);
462 assert_not_reached("unknown query type");
465 case ACTION_ATTRIBUTE_WALK
:
466 if (!device
&& argv
[optind
]) {
467 device
= find_device(udev
, argv
[optind
], NULL
);
469 fprintf(stderr
, "Unknown device, absolute path in /dev/ or /sys expected.\n");
474 fprintf(stderr
, "Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected.\n");
477 print_device_chain(device
);
479 case ACTION_DEVICE_ID_FILE
:
480 if (stat_device(name
, export
, export_prefix
) != 0)
488 const struct udevadm_cmd udevadm_info
= {
491 .help
= "Query sysfs or the udev database",