]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/udev/udevadm-info.c
udevadm-monitor: initialize variable
[thirdparty/systemd.git] / src / udev / udevadm-info.c
CommitLineData
e7145211 1/* SPDX-License-Identifier: GPL-2.0+ */
be9b51f6 2
034f35d7 3#include <ctype.h>
87171e46 4#include <errno.h>
e6c1a2bd 5#include <fcntl.h>
07630cea
LP
6#include <getopt.h>
7#include <stddef.h>
8#include <stdio.h>
9#include <string.h>
492e76c9 10#include <sys/stat.h>
07630cea 11#include <unistd.h>
be9b51f6 12
13aca847
YW
13#include "sd-device.h"
14
c4abe719 15#include "alloc-util.h"
13aca847
YW
16#include "device-enumerator-private.h"
17#include "device-private.h"
18#include "device-util.h"
8fb3f009 19#include "dirent-util.h"
3ffd4af2 20#include "fd-util.h"
07630cea 21#include "string-util.h"
3d05193e 22#include "udevadm.h"
d6170d27 23#include "udevadm-util.h"
be9b51f6 24
9ec6e95b 25static bool skip_attribute(const char *name) {
46512cd9 26 static const char* const skip[] = {
912541b0
KS
27 "uevent",
28 "dev",
29 "modalias",
30 "resource",
31 "driver",
32 "subsystem",
33 "module",
34 };
14cb109d 35 unsigned i;
912541b0 36
8fef0ff2 37 for (i = 0; i < ELEMENTSOF(skip); i++)
090be865 38 if (streq(name, skip[i]))
912541b0
KS
39 return true;
40 return false;
20bee04c
KS
41}
42
13aca847
YW
43static void print_all_attributes(sd_device *device, const char *key) {
44 const char *name, *value;
912541b0 45
13aca847 46 FOREACH_DEVICE_PROPERTY(device, name, value) {
912541b0
KS
47 size_t len;
48
912541b0
KS
49 if (skip_attribute(name))
50 continue;
51
912541b0
KS
52 /* skip any values that look like a path */
53 if (value[0] == '/')
54 continue;
55
56 /* skip nonprintable attributes */
57 len = strlen(value);
58 while (len > 0 && isprint(value[len-1]))
59 len--;
baa30fbc 60 if (len > 0)
912541b0 61 continue;
912541b0
KS
62
63 printf(" %s{%s}==\"%s\"\n", key, name, value);
64 }
65 printf("\n");
be9b51f6
KS
66}
67
13aca847
YW
68static int print_device_chain(sd_device *device) {
69 sd_device *child, *parent;
912541b0
KS
70 const char *str;
71
72 printf("\n"
73 "Udevadm info starts with the device specified by the devpath and then\n"
74 "walks up the chain of parent devices. It prints for every device\n"
75 "found, all possible attributes in the udev rules key format.\n"
76 "A rule to match, can be composed by the attributes of the device\n"
77 "and the attributes from one single parent device.\n"
78 "\n");
79
13aca847
YW
80 (void) sd_device_get_devpath(device, &str);
81 printf(" looking at device '%s':\n", str);
82 (void) sd_device_get_sysname(device, &str);
83 printf(" KERNEL==\"%s\"\n", str);
84 if (sd_device_get_subsystem(device, &str) < 0)
912541b0
KS
85 str = "";
86 printf(" SUBSYSTEM==\"%s\"\n", str);
13aca847 87 if (sd_device_get_driver(device, &str) < 0)
912541b0
KS
88 str = "";
89 printf(" DRIVER==\"%s\"\n", str);
90 print_all_attributes(device, "ATTR");
91
13aca847
YW
92 for (child = device; sd_device_get_parent(child, &parent) >= 0; child = parent) {
93 (void) sd_device_get_devpath(parent, &str);
94 printf(" looking at parent device '%s':\n", str);
95 (void) sd_device_get_sysname(parent, &str);
96 printf(" KERNELS==\"%s\"\n", str);
97 if (sd_device_get_subsystem(parent, &str) < 0)
912541b0
KS
98 str = "";
99 printf(" SUBSYSTEMS==\"%s\"\n", str);
13aca847 100 if (sd_device_get_driver(parent, &str) < 0)
912541b0
KS
101 str = "";
102 printf(" DRIVERS==\"%s\"\n", str);
13aca847
YW
103 print_all_attributes(parent, "ATTRS");
104 }
912541b0
KS
105
106 return 0;
1aa1e248
KS
107}
108
13aca847
YW
109static void print_record(sd_device *device) {
110 const char *str, *val;
912541b0 111 int i;
912541b0 112
13aca847
YW
113 (void) sd_device_get_devpath(device, &str);
114 printf("P: %s\n", str);
912541b0 115
13aca847 116 if (sd_device_get_devname(device, &str) >= 0)
fbd0b64f 117 printf("N: %s\n", str + STRLEN("/dev/"));
912541b0 118
13aca847 119 if (device_get_devlink_priority(device, &i) >= 0)
912541b0
KS
120 printf("L: %i\n", i);
121
13aca847
YW
122 FOREACH_DEVICE_DEVLINK(device, str)
123 printf("S: %s\n", str + STRLEN("/dev/"));
124
125 FOREACH_DEVICE_PROPERTY(device, str, val)
126 printf("E: %s=%s\n", str, val);
912541b0 127
912541b0 128 printf("\n");
31de3a2b
KS
129}
130
9ec6e95b 131static int stat_device(const char *name, bool export, const char *prefix) {
912541b0
KS
132 struct stat statbuf;
133
134 if (stat(name, &statbuf) != 0)
755700bb 135 return -errno;
912541b0
KS
136
137 if (export) {
13aca847 138 if (!prefix)
912541b0 139 prefix = "INFO_";
1fa2f38f
ZJS
140 printf("%sMAJOR=%u\n"
141 "%sMINOR=%u\n",
912541b0
KS
142 prefix, major(statbuf.st_dev),
143 prefix, minor(statbuf.st_dev));
144 } else
1fa2f38f 145 printf("%u:%u\n", major(statbuf.st_dev), minor(statbuf.st_dev));
912541b0 146 return 0;
f338bac8
KS
147}
148
2024ed61 149static int export_devices(void) {
13aca847
YW
150 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
151 sd_device *d;
152 int r;
912541b0 153
13aca847
YW
154 r = sd_device_enumerator_new(&e);
155 if (r < 0)
156 return r;
755700bb 157
13aca847
YW
158 r = sd_device_enumerator_allow_uninitialized(e);
159 if (r < 0)
160 return r;
912541b0 161
13aca847
YW
162 r = device_enumerator_scan_devices(e);
163 if (r < 0)
164 return r;
165
166 FOREACH_DEVICE_AND_SUBSYSTEM(e, d)
167 print_record(d);
755700bb 168
912541b0 169 return 0;
bf7ad0ea
KS
170}
171
9ec6e95b 172static void cleanup_dir(DIR *dir, mode_t mask, int depth) {
912541b0
KS
173 struct dirent *dent;
174
175 if (depth <= 0)
176 return;
177
8fb3f009 178 FOREACH_DIRENT_ALL(dent, dir, break) {
912541b0
KS
179 struct stat stats;
180
181 if (dent->d_name[0] == '.')
182 continue;
183 if (fstatat(dirfd(dir), dent->d_name, &stats, AT_SYMLINK_NOFOLLOW) != 0)
184 continue;
185 if ((stats.st_mode & mask) != 0)
186 continue;
187 if (S_ISDIR(stats.st_mode)) {
13aca847 188 _cleanup_closedir_ DIR *dir2 = NULL;
912541b0
KS
189
190 dir2 = fdopendir(openat(dirfd(dir), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC));
13aca847 191 if (dir2)
912541b0 192 cleanup_dir(dir2, mask, depth-1);
200c7fa6
LP
193
194 (void) unlinkat(dirfd(dir), dent->d_name, AT_REMOVEDIR);
195 } else
196 (void) unlinkat(dirfd(dir), dent->d_name, 0);
912541b0 197 }
9ead6627
KS
198}
199
2024ed61 200static void cleanup_db(void) {
755700bb 201 _cleanup_closedir_ DIR *dir1 = NULL, *dir2 = NULL, *dir3 = NULL, *dir4 = NULL, *dir5 = NULL;
912541b0 202
755700bb 203 (void) unlink("/run/udev/queue.bin");
912541b0 204
755700bb 205 dir1 = opendir("/run/udev/data");
13aca847 206 if (dir1)
755700bb 207 cleanup_dir(dir1, S_ISVTX, 1);
912541b0 208
755700bb 209 dir2 = opendir("/run/udev/links");
13aca847 210 if (dir2)
755700bb 211 cleanup_dir(dir2, 0, 2);
912541b0 212
755700bb 213 dir3 = opendir("/run/udev/tags");
13aca847 214 if (dir3)
755700bb 215 cleanup_dir(dir3, 0, 2);
912541b0 216
755700bb 217 dir4 = opendir("/run/udev/static_node-tags");
13aca847 218 if (dir4)
755700bb 219 cleanup_dir(dir4, 0, 2);
84b6ad70 220
755700bb 221 dir5 = opendir("/run/udev/watch");
13aca847 222 if (dir5)
755700bb 223 cleanup_dir(dir5, 0, 1);
9ead6627
KS
224}
225
ee4a776d 226static int help(void) {
5ac0162c
LP
227
228 printf("%s info [OPTIONS] [DEVPATH|FILE]\n\n"
229 "Query sysfs or the udev database.\n\n"
230 " -h --help Print this message\n"
73527992 231 " -V --version Print version of the program\n"
5ac0162c
LP
232 " -q --query=TYPE Query device information:\n"
233 " name Name of device node\n"
234 " symlink Pointing to node\n"
235 " path sysfs device path\n"
236 " property The device properties\n"
237 " all All values\n"
238 " -p --path=SYSPATH sysfs device path used for query or attribute walk\n"
239 " -n --name=NAME Node or symlink name used for query or attribute walk\n"
240 " -r --root Prepend dev directory to path names\n"
241 " -a --attribute-walk Print all key matches walking along the chain\n"
242 " of parent devices\n"
243 " -d --device-id-of-file=FILE Print major:minor of device containing this file\n"
244 " -x --export Export key/value pairs\n"
245 " -P --export-prefix Export the key name with a prefix\n"
246 " -e --export-db Export the content of the udev database\n"
247 " -c --cleanup-db Clean up the udev database\n"
248 , program_invocation_short_name);
ee4a776d
YW
249
250 return 0;
5ac0162c
LP
251}
252
3d05193e 253int info_main(int argc, char *argv[], void *userdata) {
13aca847 254 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
c4abe719
YW
255 bool root = false, export = false;
256 _cleanup_free_ char *name = NULL;
912541b0 257 const char *export_prefix = NULL;
ee4a776d 258 int c, r;
912541b0
KS
259
260 static const struct option options[] = {
7643ac9a
ZJS
261 { "name", required_argument, NULL, 'n' },
262 { "path", required_argument, NULL, 'p' },
263 { "query", required_argument, NULL, 'q' },
264 { "attribute-walk", no_argument, NULL, 'a' },
265 { "cleanup-db", no_argument, NULL, 'c' },
266 { "export-db", no_argument, NULL, 'e' },
267 { "root", no_argument, NULL, 'r' },
912541b0 268 { "device-id-of-file", required_argument, NULL, 'd' },
7643ac9a
ZJS
269 { "export", no_argument, NULL, 'x' },
270 { "export-prefix", required_argument, NULL, 'P' },
271 { "version", no_argument, NULL, 'V' },
272 { "help", no_argument, NULL, 'h' },
912541b0
KS
273 {}
274 };
275
276 enum action_type {
912541b0
KS
277 ACTION_QUERY,
278 ACTION_ATTRIBUTE_WALK,
912541b0 279 ACTION_DEVICE_ID_FILE,
4f5d327a 280 } action = ACTION_QUERY;
912541b0
KS
281
282 enum query_type {
912541b0
KS
283 QUERY_NAME,
284 QUERY_PATH,
285 QUERY_SYMLINK,
286 QUERY_PROPERTY,
287 QUERY_ALL,
4f5d327a 288 } query = QUERY_ALL;
912541b0 289
7643ac9a
ZJS
290 while ((c = getopt_long(argc, argv, "aced:n:p:q:rxP:RVh", options, NULL)) >= 0)
291 switch (c) {
ee4a776d
YW
292 case 'n':
293 if (device) {
294 log_error("device already specified");
295 return -EINVAL;
912541b0 296 }
4f5d327a 297
13aca847
YW
298 r = find_device(optarg, "/dev/", &device);
299 if (r < 0)
300 return log_error_errno(r, "device node not found: %m");
912541b0
KS
301 break;
302 case 'p':
ee4a776d
YW
303 if (device) {
304 log_error("device already specified");
305 return -EINVAL;
912541b0 306 }
4f5d327a 307
13aca847
YW
308 r = find_device(optarg, "/sys", &device);
309 if (r < 0)
310 return log_error_errno(r, "syspath not found: %m");
912541b0
KS
311 break;
312 case 'q':
313 action = ACTION_QUERY;
44433ebd 314 if (streq(optarg, "property") || streq(optarg, "env"))
912541b0 315 query = QUERY_PROPERTY;
44433ebd 316 else if (streq(optarg, "name"))
912541b0 317 query = QUERY_NAME;
44433ebd 318 else if (streq(optarg, "symlink"))
912541b0 319 query = QUERY_SYMLINK;
44433ebd 320 else if (streq(optarg, "path"))
912541b0 321 query = QUERY_PATH;
44433ebd 322 else if (streq(optarg, "all"))
912541b0 323 query = QUERY_ALL;
44433ebd 324 else {
ee4a776d
YW
325 log_error("unknown query type");
326 return -EINVAL;
912541b0
KS
327 }
328 break;
329 case 'r':
912541b0
KS
330 root = true;
331 break;
912541b0
KS
332 case 'd':
333 action = ACTION_DEVICE_ID_FILE;
c4abe719
YW
334 name = strdup(optarg);
335 if (!name)
336 return log_oom();
912541b0
KS
337 break;
338 case 'a':
339 action = ACTION_ATTRIBUTE_WALK;
340 break;
341 case 'e':
ee4a776d 342 return export_devices();
912541b0 343 case 'c':
2024ed61 344 cleanup_db();
44433ebd 345 return 0;
912541b0
KS
346 case 'x':
347 export = true;
348 break;
349 case 'P':
350 export_prefix = optarg;
351 break;
352 case 'V':
51b006e1 353 return print_version();
912541b0 354 case 'h':
ee4a776d
YW
355 return help();
356 case '?':
357 return -EINVAL;
912541b0 358 default:
ee4a776d 359 assert_not_reached("Unknown option");
912541b0 360 }
912541b0
KS
361
362 switch (action) {
363 case ACTION_QUERY:
4f5d327a
KS
364 if (!device) {
365 if (!argv[optind]) {
5ac0162c 366 help();
ee4a776d 367 return -EINVAL;
4f5d327a 368 }
13aca847
YW
369 r = find_device(argv[optind], NULL, &device);
370 if (r < 0)
371 return log_error_errno(r, "Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected: %m");
912541b0
KS
372 }
373
374 switch(query) {
375 case QUERY_NAME: {
13aca847 376 const char *node;
912541b0 377
13aca847
YW
378 r = sd_device_get_devname(device, &node);
379 if (r < 0)
380 return log_error_errno(r, "no device node found: %m");
912541b0 381
6ada823a 382 if (root)
13aca847 383 printf("%s\n", node);
6ada823a 384 else
13aca847 385 printf("%s\n", node + STRLEN("/dev/"));
912541b0
KS
386 break;
387 }
13aca847
YW
388 case QUERY_SYMLINK: {
389 const char *devlink;
390 bool first = true;
391
392 FOREACH_DEVICE_DEVLINK(device, devlink) {
393 if (!first)
394 printf(" ");
6ada823a 395 if (root)
13aca847 396 printf("%s", devlink);
6ada823a 397 else
13aca847
YW
398 printf("%s", devlink + STRLEN("/dev/"));
399
400 first = false;
912541b0
KS
401 }
402 printf("\n");
403 break;
13aca847
YW
404 }
405 case QUERY_PATH: {
406 const char *devpath;
407
408 r = sd_device_get_devpath(device, &devpath);
409 if (r < 0)
410 return log_error_errno(r, "Failed to get device path: %m");
411
412 printf("%s\n", devpath);
44433ebd 413 return 0;
13aca847
YW
414 }
415 case QUERY_PROPERTY: {
416 const char *key, *value;
417
418 FOREACH_DEVICE_PROPERTY(device, key, value)
19a29798 419 if (export)
13aca847 420 printf("%s%s='%s'\n", strempty(export_prefix), key, value);
19a29798 421 else
13aca847 422 printf("%s=%s\n", key, value);
19a29798 423
912541b0 424 break;
13aca847 425 }
912541b0
KS
426 case QUERY_ALL:
427 print_record(device);
428 break;
429 default:
bdd13f6b 430 assert_not_reached("unknown query type");
912541b0
KS
431 }
432 break;
433 case ACTION_ATTRIBUTE_WALK:
4f5d327a 434 if (!device && argv[optind]) {
13aca847
YW
435 r = find_device(argv[optind], NULL, &device);
436 if (r < 0)
437 return log_error_errno(r, "Unknown device, absolute path in /dev/ or /sys expected: %m");
4f5d327a
KS
438 }
439 if (!device) {
ee4a776d
YW
440 log_error("Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected.");
441 return -EINVAL;
912541b0
KS
442 }
443 print_device_chain(device);
444 break;
445 case ACTION_DEVICE_ID_FILE:
ee4a776d
YW
446 r = stat_device(name, export, export_prefix);
447 if (r < 0)
448 return r;
912541b0 449 break;
912541b0 450 }
87171e46 451
44433ebd 452 return 0;
87171e46 453}