]> git.ipfire.org Git - thirdparty/systemd.git/blame - udev/udevadm-info.c
udevadm: trigger - add --property-match=<key>:<value>
[thirdparty/systemd.git] / udev / udevadm-info.c
CommitLineData
be9b51f6 1/*
55e9959b 2 * Copyright (C) 2004-2008 Kay Sievers <kay.sievers@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
18#include <stdlib.h>
19#include <string.h>
20#include <stdio.h>
1aa1e248 21#include <stddef.h>
034f35d7 22#include <ctype.h>
87171e46
KS
23#include <stdarg.h>
24#include <unistd.h>
1aa1e248 25#include <dirent.h>
87171e46 26#include <errno.h>
11f1bb5a 27#include <getopt.h>
e6c1a2bd 28#include <fcntl.h>
492e76c9
KS
29#include <sys/stat.h>
30#include <sys/types.h>
be9b51f6 31
869fc2f1 32#include "udev.h"
be9b51f6 33
93b0f384 34static void print_all_attributes(struct udev_device *device, const char *key)
be9b51f6 35{
4aa0b15e 36 struct udev *udev = udev_device_get_udev(device);
1aa1e248
KS
37 DIR *dir;
38 struct dirent *dent;
39
93b0f384 40 dir = opendir(udev_device_get_syspath(device));
1aa1e248
KS
41 if (dir != NULL) {
42 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
492e76c9 43 struct stat statbuf;
93b0f384 44 const char *value;
1aa1e248
KS
45 size_t len;
46
492e76c9
KS
47 if (dent->d_name[0] == '.')
48 continue;
49
e9b64770
KS
50 if (strcmp(dent->d_name, "uevent") == 0)
51 continue;
4c46d72a
KS
52 if (strcmp(dent->d_name, "dev") == 0)
53 continue;
e9b64770 54
e6c1a2bd 55 if (fstatat(dirfd(dir), dent->d_name, &statbuf, AT_SYMLINK_NOFOLLOW) != 0)
492e76c9
KS
56 continue;
57 if (S_ISLNK(statbuf.st_mode))
58 continue;
59
69239210 60 value = udev_device_get_sysattr_value(device, dent->d_name);
93b0f384 61 if (value == NULL)
1aa1e248 62 continue;
7d563a17 63 dbg(udev, "attr '%s'='%s'(%zi)\n", dent->d_name, value, len);
1aa1e248 64
1aa1e248 65 /* skip nonprintable attributes */
93b0f384
KS
66 len = strlen(value);
67 while (len > 0 && isprint(value[len-1]))
1aa1e248 68 len--;
93b0f384 69 if (len > 0) {
4aa0b15e 70 dbg(udev, "attribute value of '%s' non-printable, skip\n", dent->d_name);
1aa1e248
KS
71 continue;
72 }
6276fdd2 73
95776dc6 74 printf(" %s{%s}==\"%s\"\n", key, dent->d_name, value);
6276fdd2 75 }
4ad3a37f 76 closedir(dir);
be9b51f6
KS
77 }
78 printf("\n");
be9b51f6
KS
79}
80
93b0f384 81static int print_device_chain(struct udev_device *device)
87171e46 82{
b2d9e4f2 83 struct udev_device *device_parent;
4ad3a37f 84 const char *str;
e48fc108 85
1aa1e248 86 printf("\n"
b620292b 87 "Udevadm info starts with the device specified by the devpath and then\n"
6cf19e52
KS
88 "walks up the chain of parent devices. It prints for every device\n"
89 "found, all possible attributes in the udev rules key format.\n"
90 "A rule to match, can be composed by the attributes of the device\n"
91 "and the attributes from one single parent device.\n"
dba8c18b 92 "\n");
f61d732a 93
4ad3a37f
KS
94 printf(" looking at device '%s':\n", udev_device_get_devpath(device));
95 printf(" KERNEL==\"%s\"\n", udev_device_get_sysname(device));
96 str = udev_device_get_subsystem(device);
97 if (str == NULL)
98 str = "";
99 printf(" SUBSYSTEM==\"%s\"\n", str);
100 str = udev_device_get_driver(device);
101 if (str == NULL)
102 str = "";
103 printf(" DRIVER==\"%s\"\n", str);
93b0f384 104 print_all_attributes(device, "ATTR");
4ad3a37f 105
b2d9e4f2
KS
106 device_parent = device;
107 do {
108 device_parent = udev_device_get_parent(device_parent);
4ad3a37f 109 if (device_parent == NULL)
034f35d7 110 break;
b2d9e4f2
KS
111 printf(" looking at parent device '%s':\n", udev_device_get_devpath(device_parent));
112 printf(" KERNELS==\"%s\"\n", udev_device_get_sysname(device_parent));
113 str = udev_device_get_subsystem(device_parent);
4ad3a37f
KS
114 if (str == NULL)
115 str = "";
116 printf(" SUBSYSTEMS==\"%s\"\n", str);
b2d9e4f2 117 str = udev_device_get_driver(device_parent);
4ad3a37f
KS
118 if (str == NULL)
119 str = "";
120 printf(" DRIVERS==\"%s\"\n", str);
93b0f384 121 print_all_attributes(device_parent, "ATTRS");
b2d9e4f2 122 } while (device_parent != NULL);
be9b51f6 123
1aa1e248
KS
124 return 0;
125}
126
93b0f384 127static void print_record(struct udev_device *device)
31de3a2b 128{
93b0f384 129 size_t len;
ee137da3 130 const char *str;
93b0f384 131 int i;
0de33a61 132 struct udev_list_entry *list_entry;
93b0f384
KS
133
134 printf("P: %s\n", udev_device_get_devpath(device));
bf7ad0ea 135
93b0f384 136 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
ee137da3
KS
137 str = udev_device_get_devnode(device);
138 if (str != NULL)
139 printf("N: %s\n", &str[len+1]);
bf7ad0ea 140
aa8734ff 141 i = udev_device_get_devlink_priority(device);
93b0f384
KS
142 if (i != 0)
143 printf("L: %i\n", i);
bf7ad0ea 144
aa8734ff 145 i = udev_device_get_num_fake_partitions(device);
93b0f384
KS
146 if (i != 0)
147 printf("A:%u\n", i);
bf7ad0ea 148
aa8734ff 149 i = udev_device_get_ignore_remove(device);
93b0f384
KS
150 if (i != 0)
151 printf("R:%u\n", i);
93b0f384 152
c08337da
SJR
153 i = udev_device_get_watch_handle(device);
154 if (i >= 0)
155 printf("W:%u\n", i);
156
0de33a61 157 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
bf7ad0ea 158 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
0de33a61 159 printf("S: %s\n", &udev_list_entry_get_name(list_entry)[len+1]);
31de3a2b 160 }
93b0f384 161
0de33a61
KS
162 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))
163 printf("E: %s=%s\n",
164 udev_list_entry_get_name(list_entry),
165 udev_list_entry_get_value(list_entry));
bf7ad0ea 166 printf("\n");
31de3a2b
KS
167}
168
d1acfc3e 169static int stat_device(const char *name, int export, const char *prefix)
f338bac8
KS
170{
171 struct stat statbuf;
172
173 if (stat(name, &statbuf) != 0)
174 return -1;
175
d1acfc3e
KS
176 if (export) {
177 if (prefix == NULL)
178 prefix = "INFO_";
179 printf("%sMAJOR=%d\n"
180 "%sMINOR=%d\n",
181 prefix, major(statbuf.st_dev),
182 prefix, minor(statbuf.st_dev));
183 } else
cce9d773 184 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
f338bac8
KS
185 return 0;
186}
187
bf7ad0ea
KS
188static int export_devices(struct udev *udev)
189{
438d4c3c 190 struct udev_enumerate *udev_enumerate;
0de33a61 191 struct udev_list_entry *list_entry;
bf7ad0ea 192
438d4c3c
KS
193 udev_enumerate = udev_enumerate_new(udev);
194 if (udev_enumerate == NULL)
bf7ad0ea 195 return -1;
c97f839e 196 udev_enumerate_scan_devices(udev_enumerate);
438d4c3c 197 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
bf7ad0ea
KS
198 struct udev_device *device;
199
0de33a61 200 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
bf7ad0ea 201 if (device != NULL) {
b38a5801 202 print_record(device);
bf7ad0ea
KS
203 udev_device_unref(device);
204 }
bf7ad0ea 205 }
438d4c3c 206 udev_enumerate_unref(udev_enumerate);
bf7ad0ea
KS
207 return 0;
208}
209
7d563a17 210int udevadm_info(struct udev *udev, int argc, char *argv[])
87171e46 211{
93b0f384 212 struct udev_device *device = NULL;
87171e46 213 int root = 0;
d1acfc3e
KS
214 int export = 0;
215 const char *export_prefix = NULL;
93b0f384
KS
216 char path[UTIL_PATH_SIZE];
217 char name[UTIL_PATH_SIZE];
0de33a61 218 struct udev_list_entry *list_entry;
93b0f384 219 int rc = 0;
24ca5c33 220
e97717ba 221 static const struct option options[] = {
033e9f8c
KS
222 { "name", required_argument, NULL, 'n' },
223 { "path", required_argument, NULL, 'p' },
224 { "query", required_argument, NULL, 'q' },
225 { "attribute-walk", no_argument, NULL, 'a' },
226 { "export-db", no_argument, NULL, 'e' },
227 { "root", no_argument, NULL, 'r' },
228 { "device-id-of-file", required_argument, NULL, 'd' },
229 { "export", no_argument, NULL, 'x' },
230 { "export-prefix", required_argument, NULL, 'P' },
50025605 231 { "version", no_argument, NULL, 'V' },
033e9f8c 232 { "help", no_argument, NULL, 'h' },
11f1bb5a
KS
233 {}
234 };
235
24ca5c33
KS
236 enum action_type {
237 ACTION_NONE,
238 ACTION_QUERY,
239 ACTION_ATTRIBUTE_WALK,
240 ACTION_ROOT,
f338bac8 241 ACTION_DEVICE_ID_FILE,
24ca5c33
KS
242 } action = ACTION_NONE;
243
b8476286
KS
244 enum query_type {
245 QUERY_NONE,
246 QUERY_NAME,
247 QUERY_PATH,
248 QUERY_SYMLINK,
249 QUERY_ENV,
250 QUERY_ALL,
251 } query = QUERY_NONE;
24ca5c33 252
87171e46 253 while (1) {
7d563a17 254 int option;
bf7ad0ea 255 struct stat statbuf;
7d563a17 256
d1acfc3e 257 option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL);
87171e46
KS
258 if (option == -1)
259 break;
260
7d563a17 261 dbg(udev, "option '%c'\n", option);
87171e46
KS
262 switch (option) {
263 case 'n':
93b0f384
KS
264 if (device != NULL) {
265 fprintf(stderr, "device already specified\n");
266 rc = 2;
267 goto exit;
268 }
2362eea6 269 /* remove /dev if given */
065db052
KS
270 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0)
271 util_strscpyl(name, sizeof(name), udev_get_dev_path(udev), "/", optarg, NULL);
272 else
273 util_strscpy(name, sizeof(name), optarg);
ecc9ec57 274 util_remove_trailing_chars(name, '/');
bf7ad0ea
KS
275 if (stat(name, &statbuf) < 0) {
276 fprintf(stderr, "device node not found\n");
277 rc = 2;
278 goto exit;
279 } else {
280 char type;
281
282 if (S_ISBLK(statbuf.st_mode)) {
283 type = 'b';
284 } else if (S_ISCHR(statbuf.st_mode)) {
285 type = 'c';
286 } else {
287 fprintf(stderr, "device node has wrong file type\n");
288 rc = 2;
289 goto exit;
290 }
291 device = udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
292 if (device == NULL) {
293 fprintf(stderr, "device node not found\n");
294 rc = 2;
295 goto exit;
296 }
297 }
87171e46 298 break;
87171e46 299 case 'p':
93b0f384
KS
300 if (device != NULL) {
301 fprintf(stderr, "device already specified\n");
302 rc = 2;
303 goto exit;
304 }
bc8184ed 305 /* add sys dir if needed */
065db052
KS
306 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0)
307 util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), optarg, NULL);
308 else
309 util_strscpy(path, sizeof(path), optarg);
ecc9ec57 310 util_remove_trailing_chars(path, '/');
8753fadf 311 device = udev_device_new_from_syspath(udev, path);
bf7ad0ea
KS
312 if (device == NULL) {
313 fprintf(stderr, "device path not found\n");
314 rc = 2;
315 goto exit;
316 }
87171e46 317 break;
87171e46 318 case 'q':
24ca5c33 319 action = ACTION_QUERY;
87171e46 320 if (strcmp(optarg, "name") == 0) {
b8476286 321 query = QUERY_NAME;
87171e46
KS
322 break;
323 }
87171e46 324 if (strcmp(optarg, "symlink") == 0) {
b8476286 325 query = QUERY_SYMLINK;
87171e46
KS
326 break;
327 }
87171e46 328 if (strcmp(optarg, "path") == 0) {
b8476286
KS
329 query = QUERY_PATH;
330 break;
331 }
b8476286
KS
332 if (strcmp(optarg, "env") == 0) {
333 query = QUERY_ENV;
87171e46
KS
334 break;
335 }
8ea84a8a 336 if (strcmp(optarg, "all") == 0) {
b8476286 337 query = QUERY_ALL;
8ea84a8a
KS
338 break;
339 }
61b1b706 340 fprintf(stderr, "unknown query type\n");
62b9dfb6 341 rc = 3;
e48fc108 342 goto exit;
87171e46 343 case 'r':
24ca5c33
KS
344 if (action == ACTION_NONE)
345 action = ACTION_ROOT;
87171e46
KS
346 root = 1;
347 break;
f338bac8
KS
348 case 'd':
349 action = ACTION_DEVICE_ID_FILE;
065db052 350 util_strscpy(name, sizeof(name), optarg);
f338bac8 351 break;
87171e46 352 case 'a':
24ca5c33 353 action = ACTION_ATTRIBUTE_WALK;
87171e46 354 break;
24ca5c33 355 case 'e':
bf7ad0ea 356 export_devices(udev);
e48fc108 357 goto exit;
d1acfc3e
KS
358 case 'x':
359 export = 1;
360 break;
361 case 'P':
362 export_prefix = optarg;
363 break;
87171e46 364 case 'V':
50025605 365 printf("%s\n", VERSION);
e48fc108 366 goto exit;
87171e46 367 case 'h':
225cb03b 368 printf("Usage: udevadm info OPTIONS\n"
cd42b50d 369 " --query=<type> query device information:\n"
f338bac8
KS
370 " name name of device node\n"
371 " symlink pointing to node\n"
cd42b50d 372 " path sys device path\n"
f338bac8
KS
373 " env the device related imported environment\n"
374 " all all values\n"
cd42b50d
KS
375 " --path=<syspath> sys device path used for query or attribute walk\n"
376 " --name=<name> node or symlink name used for query or attribute walk\n"
377 " --root prepend dev directory to path names\n"
378 " --attribute-walk print all key matches while walking along the chain\n"
f338bac8 379 " of parent devices\n"
cd42b50d 380 " --device-id-of-file=<file> print major:minor of device containing this file\n"
f338bac8 381 " --export-db export the content of the udev database\n"
f1e7e360 382 " --help\n\n");
e3396a2d 383 goto exit;
87171e46 384 default:
24ca5c33 385 goto exit;
87171e46
KS
386 }
387 }
388
24ca5c33
KS
389 switch (action) {
390 case ACTION_QUERY:
93b0f384 391 if (device == NULL) {
9a8047fa 392 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
1aa1e248 393 rc = 4;
24ca5c33 394 goto exit;
87171e46
KS
395 }
396
87171e46 397 switch(query) {
b8476286 398 case QUERY_NAME:
93b0f384 399 if (root) {
fb762bb9 400 printf("%s\n", udev_device_get_devnode(device));
93b0f384
KS
401 } else {
402 size_t len;
62b9dfb6 403 const char *node;
18770246 404
93b0f384 405 len = strlen(udev_get_dev_path(udev));
62b9dfb6
KS
406 node = udev_device_get_devnode(device);
407 if (node == NULL) {
408 fprintf(stderr, "no device node found\n");
409 rc = 5;
410 goto exit;
411 }
412 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
18770246 413 }
24ca5c33 414 break;
93b0f384 415 case QUERY_SYMLINK:
0de33a61
KS
416 list_entry = udev_device_get_devlinks_list_entry(device);
417 while (list_entry != NULL) {
bf7ad0ea 418 if (root) {
0de33a61 419 printf("%s", udev_list_entry_get_name(list_entry));
bf7ad0ea
KS
420 } else {
421 size_t len;
422
423 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
0de33a61 424 printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
bf7ad0ea 425 }
0de33a61
KS
426 list_entry = udev_list_entry_get_next(list_entry);
427 if (list_entry != NULL)
bf7ad0ea
KS
428 printf(" ");
429 }
430 printf("\n");
93b0f384 431 break;
b8476286 432 case QUERY_PATH:
93b0f384 433 printf("%s\n", udev_device_get_devpath(device));
e48fc108 434 goto exit;
b8476286 435 case QUERY_ENV:
0de33a61
KS
436 list_entry = udev_device_get_properties_list_entry(device);
437 while (list_entry != NULL) {
438 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
439 list_entry = udev_list_entry_get_next(list_entry);
bf7ad0ea 440 }
24ca5c33 441 break;
b8476286 442 case QUERY_ALL:
93b0f384 443 print_record(device);
24ca5c33 444 break;
87171e46 445 default:
e3396a2d 446 fprintf(stderr, "unknown query type\n");
24ca5c33 447 break;
87171e46 448 }
24ca5c33
KS
449 break;
450 case ACTION_ATTRIBUTE_WALK:
93b0f384 451 if (device == NULL) {
9a8047fa 452 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
62b9dfb6 453 rc = 4;
1aa0c52b
KS
454 goto exit;
455 }
93b0f384 456 print_device_chain(device);
24ca5c33 457 break;
f338bac8 458 case ACTION_DEVICE_ID_FILE:
d1acfc3e 459 if (stat_device(name, export, export_prefix) != 0)
62b9dfb6 460 rc = 1;
f338bac8 461 break;
24ca5c33 462 case ACTION_ROOT:
7d563a17 463 printf("%s\n", udev_get_dev_path(udev));
24ca5c33
KS
464 break;
465 default:
e3396a2d 466 fprintf(stderr, "missing option\n");
1aa1e248 467 rc = 1;
24ca5c33 468 break;
87171e46
KS
469 }
470
e48fc108 471exit:
93b0f384 472 udev_device_unref(device);
1aa1e248 473 return rc;
87171e46 474}