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