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