chiark / gitweb /
move some info() to dbg()
[elogind.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                "Udevinfo 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, 1 }, /* -V outputs braindead format */
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 1:
370                         printf("%s\n", VERSION);
371                         goto exit;
372                 case 'V':
373                         printf("udevinfo, version %s\n", VERSION);
374                         goto exit;
375                 case 'h':
376                         printf("Usage: udevadm info OPTIONS\n"
377                                "  --query=<type>             query device information:\n"
378                                "      name                     name of device node\n"
379                                "      symlink                  pointing to node\n"
380                                "      path                     sys device path\n"
381                                "      env                      the device related imported environment\n"
382                                "      all                      all values\n"
383                                "  --path=<syspath>           sys device path used for query or attribute walk\n"
384                                "  --name=<name>              node or symlink name used for query or attribute walk\n"
385                                "  --root                     prepend dev directory to path names\n"
386                                "  --attribute-walk           print all key matches while walking along the chain\n"
387                                "                             of parent devices\n"
388                                "  --device-id-of-file=<file> print major:minor of device containing this file\n"
389                                "  --export-db                export the content of the udev database\n"
390                                "  --help                     print this text\n"
391                                "\n");
392                         goto exit;
393                 default:
394                         goto exit;
395                 }
396         }
397
398         switch (action) {
399         case ACTION_QUERY:
400                 if (device == NULL) {
401                         fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
402                         rc = 4;
403                         goto exit;
404                 }
405
406                 switch(query) {
407                 case QUERY_NAME:
408                         if (root) {
409                                 printf("%s\n", udev_device_get_devnode(device));
410                         } else {
411                                 size_t len;
412                                 const char *node;
413
414                                 len = strlen(udev_get_dev_path(udev));
415                                 node = udev_device_get_devnode(device);
416                                 if (node == NULL) {
417                                         fprintf(stderr, "no device node found\n");
418                                         rc = 5;
419                                         goto exit;
420                                 }
421                                         printf("%s\n", &udev_device_get_devnode(device)[len+1]);
422                         }
423                         break;
424                 case QUERY_SYMLINK:
425                         list_entry = udev_device_get_devlinks_list_entry(device);
426                         while (list_entry != NULL) {
427                                 if (root) {
428                                         printf("%s", udev_list_entry_get_name(list_entry));
429                                 } else {
430                                         size_t len;
431
432                                         len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
433                                         printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
434                                 }
435                                 list_entry = udev_list_entry_get_next(list_entry);
436                                 if (list_entry != NULL)
437                                         printf(" ");
438                         }
439                         printf("\n");
440                         break;
441                 case QUERY_PATH:
442                         printf("%s\n", udev_device_get_devpath(device));
443                         goto exit;
444                 case QUERY_ENV:
445                         list_entry = udev_device_get_properties_list_entry(device);
446                         while (list_entry != NULL) {
447                                 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
448                                 list_entry = udev_list_entry_get_next(list_entry);
449                         }
450                         break;
451                 case QUERY_ALL:
452                         print_record(device);
453                         break;
454                 default:
455                         fprintf(stderr, "unknown query type\n");
456                         break;
457                 }
458                 break;
459         case ACTION_ATTRIBUTE_WALK:
460                 if (device == NULL) {
461                         fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
462                         rc = 4;
463                         goto exit;
464                 }
465                 print_device_chain(device);
466                 break;
467         case ACTION_DEVICE_ID_FILE:
468                 if (stat_device(name, export, export_prefix) != 0)
469                         rc = 1;
470                 break;
471         case ACTION_ROOT:
472                 printf("%s\n", udev_get_dev_path(udev));
473                 break;
474         default:
475                 fprintf(stderr, "missing option\n");
476                 rc = 1;
477                 break;
478         }
479
480 exit:
481         udev_device_unref(device);
482         return rc;
483 }