]> git.ipfire.org Git - thirdparty/systemd.git/blob - udev/udevadm-info.c
vol_id: add missing id->type to swap0
[thirdparty/systemd.git] / udev / udevadm-info.c
1 /*
2 * Copyright (C) 2004-2008 Kay Sievers <kay.sievers@vrfy.org>
3 *
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.
8 *
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/>.
16 */
17
18 #include <stdlib.h>
19 #include <string.h>
20 #include <stdio.h>
21 #include <stddef.h>
22 #include <ctype.h>
23 #include <stdarg.h>
24 #include <unistd.h>
25 #include <dirent.h>
26 #include <errno.h>
27 #include <getopt.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30
31 #include "udev.h"
32
33 static void print_all_attributes(struct udev_device *device, const char *key)
34 {
35 struct udev *udev = udev_device_get_udev(device);
36 DIR *dir;
37 struct dirent *dent;
38
39 dir = opendir(udev_device_get_syspath(device));
40 if (dir != NULL) {
41 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
42 struct stat statbuf;
43 char filename[UTIL_PATH_SIZE];
44 const char *value;
45 size_t len;
46
47 if (dent->d_name[0] == '.')
48 continue;
49
50 if (strcmp(dent->d_name, "uevent") == 0)
51 continue;
52 if (strcmp(dent->d_name, "dev") == 0)
53 continue;
54
55 util_strlcpy(filename, udev_device_get_syspath(device), sizeof(filename));
56 util_strlcat(filename, "/", sizeof(filename));
57 util_strlcat(filename, dent->d_name, sizeof(filename));
58 if (lstat(filename, &statbuf) != 0)
59 continue;
60 if (S_ISLNK(statbuf.st_mode))
61 continue;
62
63 value = udev_device_get_sysattr_value(device, dent->d_name);
64 if (value == NULL)
65 continue;
66 dbg(udev, "attr '%s'='%s'(%zi)\n", dent->d_name, value, len);
67
68 /* skip nonprintable attributes */
69 len = strlen(value);
70 while (len > 0 && isprint(value[len-1]))
71 len--;
72 if (len > 0) {
73 dbg(udev, "attribute value of '%s' non-printable, skip\n", dent->d_name);
74 continue;
75 }
76
77 printf(" %s{%s}==\"%s\"\n", key, dent->d_name, value);
78 }
79 closedir(dir);
80 }
81 printf("\n");
82 }
83
84 static int print_device_chain(struct udev_device *device)
85 {
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;
128 }
129
130 static void print_record(struct udev_device *device)
131 {
132 size_t len;
133 const char *str;
134 int i;
135 struct udev_list_entry *list_entry;
136
137 printf("P: %s\n", udev_device_get_devpath(device));
138
139 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
140 str = udev_device_get_devnode(device);
141 if (str != NULL)
142 printf("N: %s\n", &str[len+1]);
143
144 i = udev_device_get_devlink_priority(device);
145 if (i != 0)
146 printf("L: %i\n", i);
147
148 i = udev_device_get_num_fake_partitions(device);
149 if (i != 0)
150 printf("A:%u\n", i);
151
152 i = udev_device_get_ignore_remove(device);
153 if (i != 0)
154 printf("R:%u\n", i);
155
156 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
157 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
158 printf("S: %s\n", &udev_list_entry_get_name(list_entry)[len+1]);
159 }
160
161 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))
162 printf("E: %s=%s\n",
163 udev_list_entry_get_name(list_entry),
164 udev_list_entry_get_value(list_entry));
165 printf("\n");
166 }
167
168 static int stat_device(const char *name, int export, const char *prefix)
169 {
170 struct stat statbuf;
171
172 if (stat(name, &statbuf) != 0)
173 return -1;
174
175 if (export) {
176 if (prefix == NULL)
177 prefix = "INFO_";
178 printf("%sMAJOR=%d\n"
179 "%sMINOR=%d\n",
180 prefix, major(statbuf.st_dev),
181 prefix, minor(statbuf.st_dev));
182 } else
183 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
184 return 0;
185 }
186
187 static int export_devices(struct udev *udev)
188 {
189 struct udev_enumerate *udev_enumerate;
190 struct udev_list_entry *list_entry;
191
192 udev_enumerate = udev_enumerate_new(udev);
193 if (udev_enumerate == NULL)
194 return -1;
195 udev_enumerate_scan_devices(udev_enumerate);
196 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
197 struct udev_device *device;
198
199 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
200 if (device != NULL) {
201 if (udev_device_get_devnode(device) != NULL)
202 print_record(device);
203 udev_device_unref(device);
204 }
205 }
206 udev_enumerate_unref(udev_enumerate);
207 return 0;
208 }
209
210 int udevadm_info(struct udev *udev, int argc, char *argv[])
211 {
212 struct udev_device *device = NULL;
213 int root = 0;
214 int export = 0;
215 const char *export_prefix = NULL;
216 char path[UTIL_PATH_SIZE];
217 char name[UTIL_PATH_SIZE];
218 struct udev_list_entry *list_entry;
219 int rc = 0;
220
221 static const struct option options[] = {
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' },
231 { "version", no_argument, NULL, 'V' },
232 { "help", no_argument, NULL, 'h' },
233 {}
234 };
235
236 enum action_type {
237 ACTION_NONE,
238 ACTION_QUERY,
239 ACTION_ATTRIBUTE_WALK,
240 ACTION_ROOT,
241 ACTION_DEVICE_ID_FILE,
242 } action = ACTION_NONE;
243
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;
252
253 while (1) {
254 int option;
255 struct stat statbuf;
256
257 option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL);
258 if (option == -1)
259 break;
260
261 dbg(udev, "option '%c'\n", option);
262 switch (option) {
263 case 'n':
264 if (device != NULL) {
265 fprintf(stderr, "device already specified\n");
266 rc = 2;
267 goto exit;
268 }
269 /* remove /dev if given */
270 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0) {
271 util_strlcpy(name, udev_get_dev_path(udev), sizeof(name));
272 util_strlcat(name, "/", sizeof(name));
273 util_strlcat(name, optarg, sizeof(name));
274 } else {
275 util_strlcpy(name, optarg, sizeof(name));
276 }
277 util_remove_trailing_chars(name, '/');
278 if (stat(name, &statbuf) < 0) {
279 fprintf(stderr, "device node not found\n");
280 rc = 2;
281 goto exit;
282 } else {
283 char type;
284
285 if (S_ISBLK(statbuf.st_mode)) {
286 type = 'b';
287 } else if (S_ISCHR(statbuf.st_mode)) {
288 type = 'c';
289 } else {
290 fprintf(stderr, "device node has wrong file type\n");
291 rc = 2;
292 goto exit;
293 }
294 device = udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
295 if (device == NULL) {
296 fprintf(stderr, "device node not found\n");
297 rc = 2;
298 goto exit;
299 }
300 }
301 break;
302 case 'p':
303 if (device != NULL) {
304 fprintf(stderr, "device already specified\n");
305 rc = 2;
306 goto exit;
307 }
308 /* add sys dir if needed */
309 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0) {
310 util_strlcpy(path, udev_get_sys_path(udev), sizeof(path));
311 util_strlcat(path, optarg, sizeof(path));
312 } else {
313 util_strlcpy(path, optarg, sizeof(path));
314 }
315 util_remove_trailing_chars(path, '/');
316 device = udev_device_new_from_syspath(udev, path);
317 if (device == NULL) {
318 fprintf(stderr, "device path not found\n");
319 rc = 2;
320 goto exit;
321 }
322 break;
323 case 'q':
324 action = ACTION_QUERY;
325 if (strcmp(optarg, "name") == 0) {
326 query = QUERY_NAME;
327 break;
328 }
329 if (strcmp(optarg, "symlink") == 0) {
330 query = QUERY_SYMLINK;
331 break;
332 }
333 if (strcmp(optarg, "path") == 0) {
334 query = QUERY_PATH;
335 break;
336 }
337 if (strcmp(optarg, "env") == 0) {
338 query = QUERY_ENV;
339 break;
340 }
341 if (strcmp(optarg, "all") == 0) {
342 query = QUERY_ALL;
343 break;
344 }
345 fprintf(stderr, "unknown query type\n");
346 rc = 3;
347 goto exit;
348 case 'r':
349 if (action == ACTION_NONE)
350 action = ACTION_ROOT;
351 root = 1;
352 break;
353 case 'd':
354 action = ACTION_DEVICE_ID_FILE;
355 util_strlcpy(name, optarg, sizeof(name));
356 break;
357 case 'a':
358 action = ACTION_ATTRIBUTE_WALK;
359 break;
360 case 'e':
361 export_devices(udev);
362 goto exit;
363 case 'x':
364 export = 1;
365 break;
366 case 'P':
367 export_prefix = optarg;
368 break;
369 case 'V':
370 printf("%s\n", VERSION);
371 goto exit;
372 case 'h':
373 printf("Usage: udevadm info OPTIONS\n"
374 " --query=<type> query device information:\n"
375 " name name of device node\n"
376 " symlink pointing to node\n"
377 " path sys device path\n"
378 " env the device related imported environment\n"
379 " all all values\n"
380 " --path=<syspath> sys device path used for query or attribute walk\n"
381 " --name=<name> node or symlink name used for query or attribute walk\n"
382 " --root prepend dev directory to path names\n"
383 " --attribute-walk print all key matches while walking along the chain\n"
384 " of parent devices\n"
385 " --device-id-of-file=<file> print major:minor of device containing this file\n"
386 " --export-db export the content of the udev database\n"
387 " --help print this text\n"
388 "\n");
389 goto exit;
390 default:
391 goto exit;
392 }
393 }
394
395 switch (action) {
396 case ACTION_QUERY:
397 if (device == NULL) {
398 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
399 rc = 4;
400 goto exit;
401 }
402
403 switch(query) {
404 case QUERY_NAME:
405 if (root) {
406 printf("%s\n", udev_device_get_devnode(device));
407 } else {
408 size_t len;
409 const char *node;
410
411 len = strlen(udev_get_dev_path(udev));
412 node = udev_device_get_devnode(device);
413 if (node == NULL) {
414 fprintf(stderr, "no device node found\n");
415 rc = 5;
416 goto exit;
417 }
418 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
419 }
420 break;
421 case QUERY_SYMLINK:
422 list_entry = udev_device_get_devlinks_list_entry(device);
423 while (list_entry != NULL) {
424 if (root) {
425 printf("%s", udev_list_entry_get_name(list_entry));
426 } else {
427 size_t len;
428
429 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
430 printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
431 }
432 list_entry = udev_list_entry_get_next(list_entry);
433 if (list_entry != NULL)
434 printf(" ");
435 }
436 printf("\n");
437 break;
438 case QUERY_PATH:
439 printf("%s\n", udev_device_get_devpath(device));
440 goto exit;
441 case QUERY_ENV:
442 list_entry = udev_device_get_properties_list_entry(device);
443 while (list_entry != NULL) {
444 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
445 list_entry = udev_list_entry_get_next(list_entry);
446 }
447 break;
448 case QUERY_ALL:
449 print_record(device);
450 break;
451 default:
452 fprintf(stderr, "unknown query type\n");
453 break;
454 }
455 break;
456 case ACTION_ATTRIBUTE_WALK:
457 if (device == NULL) {
458 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
459 rc = 4;
460 goto exit;
461 }
462 print_device_chain(device);
463 break;
464 case ACTION_DEVICE_ID_FILE:
465 if (stat_device(name, export, export_prefix) != 0)
466 rc = 1;
467 break;
468 case ACTION_ROOT:
469 printf("%s\n", udev_get_dev_path(udev));
470 break;
471 default:
472 fprintf(stderr, "missing option\n");
473 rc = 1;
474 break;
475 }
476
477 exit:
478 udev_device_unref(device);
479 return rc;
480 }