chiark / gitweb /
move /dev/.udev/ to /dev/.run/udev/ and convert old udev database at udevd startup
[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                 { "device-id-of-file", required_argument, NULL, 'd' },
222                 { "export", no_argument, NULL, 'x' },
223                 { "export-prefix", required_argument, NULL, 'P' },
224                 { "version", no_argument, NULL, 'V' },
225                 { "help", no_argument, NULL, 'h' },
226                 {}
227         };
228
229         enum action_type {
230                 ACTION_NONE,
231                 ACTION_QUERY,
232                 ACTION_ATTRIBUTE_WALK,
233                 ACTION_ROOT,
234                 ACTION_DEVICE_ID_FILE,
235         } action = ACTION_NONE;
236
237         enum query_type {
238                 QUERY_NONE,
239                 QUERY_NAME,
240                 QUERY_PATH,
241                 QUERY_SYMLINK,
242                 QUERY_PROPERTY,
243                 QUERY_ALL,
244         } query = QUERY_NONE;
245
246         for (;;) {
247                 int option;
248                 struct stat statbuf;
249
250                 option = getopt_long(argc, argv, "aed:n:p:q:rxP:Vh", options, NULL);
251                 if (option == -1)
252                         break;
253
254                 dbg(udev, "option '%c'\n", option);
255                 switch (option) {
256                 case 'n':
257                         if (device != NULL) {
258                                 fprintf(stderr, "device already specified\n");
259                                 rc = 2;
260                                 goto exit;
261                         }
262                         /* remove /dev if given */
263                         if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0)
264                                 util_strscpyl(name, sizeof(name), udev_get_dev_path(udev), "/", optarg, NULL);
265                         else
266                                 util_strscpy(name, sizeof(name), optarg);
267                         util_remove_trailing_chars(name, '/');
268                         if (stat(name, &statbuf) < 0) {
269                                 fprintf(stderr, "device node not found\n");
270                                 rc = 2;
271                                 goto exit;
272                         } else {
273                                 char type;
274
275                                 if (S_ISBLK(statbuf.st_mode)) {
276                                         type = 'b';
277                                 } else if (S_ISCHR(statbuf.st_mode)) {
278                                         type = 'c';
279                                 } else {
280                                         fprintf(stderr, "device node has wrong file type\n");
281                                         rc = 2;
282                                         goto exit;
283                                 }
284                                 device = udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
285                                 if (device == NULL) {
286                                         fprintf(stderr, "device node not found\n");
287                                         rc = 2;
288                                         goto exit;
289                                 }
290                         }
291                         break;
292                 case 'p':
293                         if (device != NULL) {
294                                 fprintf(stderr, "device already specified\n");
295                                 rc = 2;
296                                 goto exit;
297                         }
298                         /* add sys dir if needed */
299                         if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0)
300                                 util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), optarg, NULL);
301                         else
302                                 util_strscpy(path, sizeof(path), optarg);
303                         util_remove_trailing_chars(path, '/');
304                         device = udev_device_new_from_syspath(udev, path);
305                         if (device == NULL) {
306                                 fprintf(stderr, "device path not found\n");
307                                 rc = 2;
308                                 goto exit;
309                         }
310                         break;
311                 case 'q':
312                         action = ACTION_QUERY;
313                         if (strcmp(optarg, "property") == 0 || strcmp(optarg, "env") == 0) {
314                                 query = QUERY_PROPERTY;
315                         } else if (strcmp(optarg, "name") == 0) {
316                                 query = QUERY_NAME;
317                         } else if (strcmp(optarg, "symlink") == 0) {
318                                 query = QUERY_SYMLINK;
319                         } else if (strcmp(optarg, "path") == 0) {
320                                 query = QUERY_PATH;
321                         } else if (strcmp(optarg, "all") == 0) {
322                                 query = QUERY_ALL;
323                         } else {
324                                 fprintf(stderr, "unknown query type\n");
325                                 rc = 3;
326                                 goto exit;
327                         }
328                         break;
329                 case 'r':
330                         if (action == ACTION_NONE)
331                                 action = ACTION_ROOT;
332                         root = true;
333                         break;
334                 case 'd':
335                         action = ACTION_DEVICE_ID_FILE;
336                         util_strscpy(name, sizeof(name), optarg);
337                         break;
338                 case 'a':
339                         action = ACTION_ATTRIBUTE_WALK;
340                         break;
341                 case 'e':
342                         export_devices(udev);
343                         goto exit;
344                 case 'x':
345                         export = true;
346                         break;
347                 case 'P':
348                         export_prefix = optarg;
349                         break;
350                 case 'V':
351                         printf("%s\n", VERSION);
352                         goto exit;
353                 case 'h':
354                         printf("Usage: udevadm info OPTIONS\n"
355                                "  --query=<type>             query device information:\n"
356                                "      name                     name of device node\n"
357                                "      symlink                  pointing to node\n"
358                                "      path                     sys device path\n"
359                                "      property                 the device properties\n"
360                                "      all                      all values\n"
361                                "  --path=<syspath>           sys device path used for query or attribute walk\n"
362                                "  --name=<name>              node or symlink name used for query or attribute walk\n"
363                                "  --root                     prepend dev directory to path names\n"
364                                "  --attribute-walk           print all key matches while walking along the chain\n"
365                                "                             of parent devices\n"
366                                "  --device-id-of-file=<file> print major:minor of device containing this file\n"
367                                "  --export                   export key/value pairs\n"
368                                "  --export-prefix            export the key name with a prefix\n"
369                                "  --export-db                export the content of the udev database\n"
370                                "  --help\n\n");
371                         goto exit;
372                 default:
373                         goto exit;
374                 }
375         }
376
377         switch (action) {
378         case ACTION_QUERY:
379                 if (device == NULL) {
380                         fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
381                         rc = 4;
382                         goto exit;
383                 }
384
385                 switch(query) {
386                 case QUERY_NAME: {
387                         const char *node = udev_device_get_devnode(device);
388
389                         if (node == NULL) {
390                                 fprintf(stderr, "no device node found\n");
391                                 rc = 5;
392                                 goto exit;
393                         }
394
395                         if (root) {
396                                 printf("%s\n", udev_device_get_devnode(device));
397                         } else {
398                                 size_t len = strlen(udev_get_dev_path(udev));
399
400                                 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
401                         }
402                         break;
403                 }
404                 case QUERY_SYMLINK:
405                         list_entry = udev_device_get_devlinks_list_entry(device);
406                         while (list_entry != NULL) {
407                                 if (root) {
408                                         printf("%s", udev_list_entry_get_name(list_entry));
409                                 } else {
410                                         size_t len;
411
412                                         len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
413                                         printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
414                                 }
415                                 list_entry = udev_list_entry_get_next(list_entry);
416                                 if (list_entry != NULL)
417                                         printf(" ");
418                         }
419                         printf("\n");
420                         break;
421                 case QUERY_PATH:
422                         printf("%s\n", udev_device_get_devpath(device));
423                         goto exit;
424                 case QUERY_PROPERTY:
425                         list_entry = udev_device_get_properties_list_entry(device);
426                         while (list_entry != NULL) {
427                                 if (export) {
428                                         const char *prefix = export_prefix;
429
430                                         if (prefix == NULL)
431                                                 prefix = "";
432                                         printf("%s%s='%s'\n", prefix,
433                                                udev_list_entry_get_name(list_entry),
434                                                udev_list_entry_get_value(list_entry));
435                                 } else {
436                                         printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
437                                 }
438                                 list_entry = udev_list_entry_get_next(list_entry);
439                         }
440                         break;
441                 case QUERY_ALL:
442                         print_record(device);
443                         break;
444                 default:
445                         fprintf(stderr, "unknown query type\n");
446                         break;
447                 }
448                 break;
449         case ACTION_ATTRIBUTE_WALK:
450                 if (device == NULL) {
451                         fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
452                         rc = 4;
453                         goto exit;
454                 }
455                 print_device_chain(device);
456                 break;
457         case ACTION_DEVICE_ID_FILE:
458                 if (stat_device(name, export, export_prefix) != 0)
459                         rc = 1;
460                 break;
461         case ACTION_ROOT:
462                 printf("%s\n", udev_get_dev_path(udev));
463                 break;
464         default:
465                 fprintf(stderr, "missing option\n");
466                 rc = 1;
467                 break;
468         }
469
470 exit:
471         udev_device_unref(device);
472         return rc;
473 }