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