chiark / gitweb /
keymap: move force-release directory
[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_num_fake_partitions(device);
146         if (i != 0)
147                 printf("A: %u\n", i);
148
149         i = udev_device_get_ignore_remove(device);
150         if (i != 0)
151                 printf("R: %u\n", i);
152
153         i = udev_device_get_watch_handle(device);
154         if (i >= 0)
155                 printf("W: %u\n", i);
156
157         udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
158                 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
159                 printf("S: %s\n", &udev_list_entry_get_name(list_entry)[len+1]);
160         }
161
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));
166         printf("\n");
167 }
168
169 static int stat_device(const char *name, int export, const char *prefix)
170 {
171         struct stat statbuf;
172
173         if (stat(name, &statbuf) != 0)
174                 return -1;
175
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
184                 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
185         return 0;
186 }
187
188 static int export_devices(struct udev *udev)
189 {
190         struct udev_enumerate *udev_enumerate;
191         struct udev_list_entry *list_entry;
192
193         udev_enumerate = udev_enumerate_new(udev);
194         if (udev_enumerate == NULL)
195                 return -1;
196         udev_enumerate_scan_devices(udev_enumerate);
197         udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
198                 struct udev_device *device;
199
200                 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
201                 if (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_PROPERTY,
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_strscpyl(name, sizeof(name), udev_get_dev_path(udev), "/", optarg, NULL);
272                         else
273                                 util_strscpy(name, sizeof(name), optarg);
274                         util_remove_trailing_chars(name, '/');
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                         }
298                         break;
299                 case 'p':
300                         if (device != NULL) {
301                                 fprintf(stderr, "device already specified\n");
302                                 rc = 2;
303                                 goto exit;
304                         }
305                         /* add sys dir if needed */
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);
310                         util_remove_trailing_chars(path, '/');
311                         device = udev_device_new_from_syspath(udev, path);
312                         if (device == NULL) {
313                                 fprintf(stderr, "device path not found\n");
314                                 rc = 2;
315                                 goto exit;
316                         }
317                         break;
318                 case 'q':
319                         action = ACTION_QUERY;
320                         if (strcmp(optarg, "property") == 0 || strcmp(optarg, "env") == 0) {
321                                 query = QUERY_PROPERTY;
322                         } else if (strcmp(optarg, "name") == 0) {
323                                 query = QUERY_NAME;
324                         } else if (strcmp(optarg, "symlink") == 0) {
325                                 query = QUERY_SYMLINK;
326                         } else if (strcmp(optarg, "path") == 0) {
327                                 query = QUERY_PATH;
328                         } else if (strcmp(optarg, "all") == 0) {
329                                 query = QUERY_ALL;
330                         } else {
331                                 fprintf(stderr, "unknown query type\n");
332                                 rc = 3;
333                                 goto exit;
334                         }
335                         break;
336                 case 'r':
337                         if (action == ACTION_NONE)
338                                 action = ACTION_ROOT;
339                         root = 1;
340                         break;
341                 case 'd':
342                         action = ACTION_DEVICE_ID_FILE;
343                         util_strscpy(name, sizeof(name), optarg);
344                         break;
345                 case 'a':
346                         action = ACTION_ATTRIBUTE_WALK;
347                         break;
348                 case 'e':
349                         export_devices(udev);
350                         goto exit;
351                 case 'x':
352                         export = 1;
353                         break;
354                 case 'P':
355                         export_prefix = optarg;
356                         break;
357                 case 'V':
358                         printf("%s\n", VERSION);
359                         goto exit;
360                 case 'h':
361                         printf("Usage: udevadm info OPTIONS\n"
362                                "  --query=<type>             query device information:\n"
363                                "      name                     name of device node\n"
364                                "      symlink                  pointing to node\n"
365                                "      path                     sys device path\n"
366                                "      property                 the device properties\n"
367                                "      all                      all values\n"
368                                "  --path=<syspath>           sys device path used for query or attribute walk\n"
369                                "  --name=<name>              node or symlink name used for query or attribute walk\n"
370                                "  --root                     prepend dev directory to path names\n"
371                                "  --attribute-walk           print all key matches while walking along the chain\n"
372                                "                             of parent devices\n"
373                                "  --device-id-of-file=<file> print major:minor of device containing this file\n"
374                                "  --export-db                export the content of the udev database\n"
375                                "  --help\n\n");
376                         goto exit;
377                 default:
378                         goto exit;
379                 }
380         }
381
382         switch (action) {
383         case ACTION_QUERY:
384                 if (device == NULL) {
385                         fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
386                         rc = 4;
387                         goto exit;
388                 }
389
390                 switch(query) {
391                 case QUERY_NAME: {
392                         const char *node = udev_device_get_devnode(device);
393
394                         if (node == NULL) {
395                                 fprintf(stderr, "no device node found\n");
396                                 rc = 5;
397                                 goto exit;
398                         }
399
400                         if (root) {
401                                 printf("%s\n", udev_device_get_devnode(device));
402                         } else {
403                                 size_t len = strlen(udev_get_dev_path(udev));
404
405                                 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
406                         }
407                         break;
408                 }
409                 case QUERY_SYMLINK:
410                         list_entry = udev_device_get_devlinks_list_entry(device);
411                         while (list_entry != NULL) {
412                                 if (root) {
413                                         printf("%s", udev_list_entry_get_name(list_entry));
414                                 } else {
415                                         size_t len;
416
417                                         len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
418                                         printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
419                                 }
420                                 list_entry = udev_list_entry_get_next(list_entry);
421                                 if (list_entry != NULL)
422                                         printf(" ");
423                         }
424                         printf("\n");
425                         break;
426                 case QUERY_PATH:
427                         printf("%s\n", udev_device_get_devpath(device));
428                         goto exit;
429                 case QUERY_PROPERTY:
430                         list_entry = udev_device_get_properties_list_entry(device);
431                         while (list_entry != NULL) {
432                                 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
433                                 list_entry = udev_list_entry_get_next(list_entry);
434                         }
435                         break;
436                 case QUERY_ALL:
437                         print_record(device);
438                         break;
439                 default:
440                         fprintf(stderr, "unknown query type\n");
441                         break;
442                 }
443                 break;
444         case ACTION_ATTRIBUTE_WALK:
445                 if (device == NULL) {
446                         fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
447                         rc = 4;
448                         goto exit;
449                 }
450                 print_device_chain(device);
451                 break;
452         case ACTION_DEVICE_ID_FILE:
453                 if (stat_device(name, export, export_prefix) != 0)
454                         rc = 1;
455                 break;
456         case ACTION_ROOT:
457                 printf("%s\n", udev_get_dev_path(udev));
458                 break;
459         default:
460                 fprintf(stderr, "missing option\n");
461                 rc = 1;
462                 break;
463         }
464
465 exit:
466         udev_device_unref(device);
467         return rc;
468 }