chiark / gitweb /
libudev: enumerate_get_devices_list -> enumerate_get_list
[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         DIR *dir;
36         struct dirent *dent;
37
38         dir = opendir(udev_device_get_syspath(device));
39         if (dir != NULL) {
40                 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
41                         struct stat statbuf;
42                         char filename[UTIL_PATH_SIZE];
43                         const char *value;
44                         size_t len;
45
46                         if (dent->d_name[0] == '.')
47                                 continue;
48
49                         if (strcmp(dent->d_name, "uevent") == 0)
50                                 continue;
51                         if (strcmp(dent->d_name, "dev") == 0)
52                                 continue;
53
54                         util_strlcpy(filename, udev_device_get_syspath(device), sizeof(filename));
55                         util_strlcat(filename, "/", sizeof(filename));
56                         util_strlcat(filename, dent->d_name, sizeof(filename));
57                         if (lstat(filename, &statbuf) != 0)
58                                 continue;
59                         if (S_ISLNK(statbuf.st_mode))
60                                 continue;
61
62                         value = udev_device_get_attr_value(device, dent->d_name);
63                         if (value == NULL)
64                                 continue;
65                         dbg(udev, "attr '%s'='%s'(%zi)\n", dent->d_name, value, len);
66
67                         /* skip nonprintable attributes */
68                         len = strlen(value);
69                         while (len > 0 && isprint(value[len-1]))
70                                 len--;
71                         if (len > 0) {
72                                 dbg(info, "attribute value of '%s' non-printable, skip\n", dent->d_name);
73                                 continue;
74                         }
75
76                         printf("    %s{%s}==\"%s\"\n", key, dent->d_name, value);
77                 }
78                 closedir(dir);
79         }
80         printf("\n");
81 }
82
83 static int print_device_chain(struct udev_device *device)
84 {
85         struct udev_device *device_parent;
86         const char *str;
87
88         printf("\n"
89                "Udevinfo starts with the device specified by the devpath and then\n"
90                "walks up the chain of parent devices. It prints for every device\n"
91                "found, all possible attributes in the udev rules key format.\n"
92                "A rule to match, can be composed by the attributes of the device\n"
93                "and the attributes from one single parent device.\n"
94                "\n");
95
96         printf("  looking at device '%s':\n", udev_device_get_devpath(device));
97         printf("    KERNEL==\"%s\"\n", udev_device_get_sysname(device));
98         str = udev_device_get_subsystem(device);
99         if (str == NULL)
100                 str = "";
101         printf("    SUBSYSTEM==\"%s\"\n", str);
102         str = udev_device_get_driver(device);
103         if (str == NULL)
104                 str = "";
105         printf("    DRIVER==\"%s\"\n", str);
106         print_all_attributes(device, "ATTR");
107
108         device_parent = device;
109         do {
110                 device_parent = udev_device_get_parent(device_parent);
111                 if (device_parent == NULL)
112                         break;
113                 printf("  looking at parent device '%s':\n", udev_device_get_devpath(device_parent));
114                 printf("    KERNELS==\"%s\"\n", udev_device_get_sysname(device_parent));
115                 str = udev_device_get_subsystem(device_parent);
116                 if (str == NULL)
117                         str = "";
118                 printf("    SUBSYSTEMS==\"%s\"\n", str);
119                 str = udev_device_get_driver(device_parent);
120                 if (str == NULL)
121                         str = "";
122                 printf("    DRIVERS==\"%s\"\n", str);
123                 print_all_attributes(device_parent, "ATTRS");
124         } while (device_parent != NULL);
125
126         return 0;
127 }
128
129 static void print_record(struct udev_device *device)
130 {
131         size_t len;
132         int i;
133         struct udev_list *list;
134
135         printf("P: %s\n", udev_device_get_devpath(device));
136
137         len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
138         printf("N: %s\n", &udev_device_get_devnode(device)[len+1]);
139
140         i = device_get_devlink_priority(device);
141         if (i != 0)
142                 printf("L: %i\n", i);
143
144         i = device_get_num_fake_partitions(device);
145         if (i != 0)
146                 printf("A:%u\n", i);
147
148         i = device_get_ignore_remove(device);
149         if (i != 0)
150                 printf("R:%u\n", i);
151
152         list = udev_device_get_devlinks_list(device);
153         while (list != NULL) {
154                 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
155                 printf("S: %s\n", &udev_list_get_name(list)[len+1]);
156                 list = udev_list_get_next(list);
157         }
158
159         list = udev_device_get_properties_list(device);
160         while (list != NULL) {
161                 printf("E: %s=%s\n", udev_list_get_name(list), udev_list_get_value(list));
162                 list = udev_list_get_next(list);
163         }
164
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 *enumerate;
190         struct udev_list *list;
191
192         enumerate = udev_enumerate_new_from_subsystems(udev, NULL);
193         if (enumerate == NULL)
194                 return -1;
195         list = udev_enumerate_get_list(enumerate);
196         while (list != NULL) {
197                 struct udev_device *device;
198
199                 device = udev_device_new_from_syspath(udev, udev_list_get_name(list));
200                 if (device != NULL) {
201                         if (udev_device_get_devnode(device) != NULL)
202                                 print_record(device);
203                         udev_device_unref(device);
204                 }
205                 list = udev_list_get_next(list);
206         }
207         udev_enumerate_unref(enumerate);
208         return 0;
209 }
210
211 int udevadm_info(struct udev *udev, int argc, char *argv[])
212 {
213         struct udev_device *device = NULL;
214         int root = 0;
215         int export = 0;
216         const char *export_prefix = NULL;
217         char path[UTIL_PATH_SIZE];
218         char name[UTIL_PATH_SIZE];
219         struct udev_list *list;
220         int rc = 0;
221
222         static const struct option options[] = {
223                 { "name", 1, NULL, 'n' },
224                 { "path", 1, NULL, 'p' },
225                 { "query", 1, NULL, 'q' },
226                 { "attribute-walk", 0, NULL, 'a' },
227                 { "export-db", 0, NULL, 'e' },
228                 { "root", 0, NULL, 'r' },
229                 { "device-id-of-file", 1, NULL, 'd' },
230                 { "export", 0, NULL, 'x' },
231                 { "export-prefix", 1, NULL, 'P' },
232                 { "version", 0, NULL, 1 }, /* -V outputs braindead format */
233                 { "help", 0, NULL, 'h' },
234                 {}
235         };
236
237         enum action_type {
238                 ACTION_NONE,
239                 ACTION_QUERY,
240                 ACTION_ATTRIBUTE_WALK,
241                 ACTION_ROOT,
242                 ACTION_DEVICE_ID_FILE,
243         } action = ACTION_NONE;
244
245         enum query_type {
246                 QUERY_NONE,
247                 QUERY_NAME,
248                 QUERY_PATH,
249                 QUERY_SYMLINK,
250                 QUERY_ENV,
251                 QUERY_ALL,
252         } query = QUERY_NONE;
253
254         while (1) {
255                 int option;
256                 struct stat statbuf;
257
258                 option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL);
259                 if (option == -1)
260                         break;
261
262                 dbg(udev, "option '%c'\n", option);
263                 switch (option) {
264                 case 'n':
265                         if (device != NULL) {
266                                 fprintf(stderr, "device already specified\n");
267                                 rc = 2;
268                                 goto exit;
269                         }
270                         /* remove /dev if given */
271                         if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0) {
272                                 util_strlcpy(name, udev_get_dev_path(udev), sizeof(name));
273                                 util_strlcat(name, "/", sizeof(name));
274                                 util_strlcat(name, optarg, sizeof(name));
275                         } else {
276                                 util_strlcpy(name, optarg, sizeof(name));
277                         }
278                         util_remove_trailing_chars(name, '/');
279                         if (stat(name, &statbuf) < 0) {
280                                 fprintf(stderr, "device node not found\n");
281                                 rc = 2;
282                                 goto exit;
283                         } else {
284                                 char type;
285
286                                 if (S_ISBLK(statbuf.st_mode)) {
287                                         type = 'b';
288                                 } else if (S_ISCHR(statbuf.st_mode)) {
289                                         type = 'c';
290                                 } else {
291                                         fprintf(stderr, "device node has wrong file type\n");
292                                         rc = 2;
293                                         goto exit;
294                                 }
295                                 device = udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
296                                 if (device == NULL) {
297                                         fprintf(stderr, "device node not found\n");
298                                         rc = 2;
299                                         goto exit;
300                                 }
301                         }
302                         break;
303                 case 'p':
304                         if (device != NULL) {
305                                 fprintf(stderr, "device already specified\n");
306                                 rc = 2;
307                                 goto exit;
308                         }
309                         /* add /sys if needed */
310                         if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0) {
311                                 util_strlcpy(path, udev_get_sys_path(udev), sizeof(path));
312                                 util_strlcat(path, optarg, sizeof(path));
313                         } else {
314                                 util_strlcpy(path, optarg, sizeof(path));
315                         }
316                         util_remove_trailing_chars(path, '/');
317                         device = udev_device_new_from_syspath(udev, path);
318                         if (device == NULL) {
319                                 fprintf(stderr, "device path not found\n");
320                                 rc = 2;
321                                 goto exit;
322                         }
323                         break;
324                 case 'q':
325                         action = ACTION_QUERY;
326                         if (strcmp(optarg, "name") == 0) {
327                                 query = QUERY_NAME;
328                                 break;
329                         }
330                         if (strcmp(optarg, "symlink") == 0) {
331                                 query = QUERY_SYMLINK;
332                                 break;
333                         }
334                         if (strcmp(optarg, "path") == 0) {
335                                 query = QUERY_PATH;
336                                 break;
337                         }
338                         if (strcmp(optarg, "env") == 0) {
339                                 query = QUERY_ENV;
340                                 break;
341                         }
342                         if (strcmp(optarg, "all") == 0) {
343                                 query = QUERY_ALL;
344                                 break;
345                         }
346                         fprintf(stderr, "unknown query type\n");
347                         rc = 2;
348                         goto exit;
349                 case 'r':
350                         if (action == ACTION_NONE)
351                                 action = ACTION_ROOT;
352                         root = 1;
353                         break;
354                 case 'd':
355                         action = ACTION_DEVICE_ID_FILE;
356                         util_strlcpy(name, optarg, sizeof(name));
357                         break;
358                 case 'a':
359                         action = ACTION_ATTRIBUTE_WALK;
360                         break;
361                 case 'e':
362                         export_devices(udev);
363                         goto exit;
364                 case 'x':
365                         export = 1;
366                         break;
367                 case 'P':
368                         export_prefix = optarg;
369                         break;
370                 case 1:
371                         printf("%s\n", VERSION);
372                         goto exit;
373                 case 'V':
374                         printf("udevinfo, version %s\n", VERSION);
375                         goto exit;
376                 case 'h':
377                         printf("Usage: udevadm info OPTIONS\n"
378                                "  --query=<type>             query device information:\n"
379                                "      name                     name of device node\n"
380                                "      symlink                  pointing to node\n"
381                                "      path                     sys device path\n"
382                                "      env                      the device related imported environment\n"
383                                "      all                      all values\n"
384                                "  --path=<syspath>           sys device path used for query or attribute walk\n"
385                                "  --name=<name>              node or symlink name used for query or attribute walk\n"
386                                "  --root                     prepend dev directory to path names\n"
387                                "  --attribute-walk           print all key matches while walking along the chain\n"
388                                "                             of parent devices\n"
389                                "  --device-id-of-file=<file> print major:minor of device containing this file\n"
390                                "  --export-db                export the content of the udev database\n"
391                                "  --help                     print this text\n"
392                                "\n");
393                         goto exit;
394                 default:
395                         goto exit;
396                 }
397         }
398
399         switch (action) {
400         case ACTION_QUERY:
401                 if (device == NULL) {
402                         fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
403                         rc = 4;
404                         goto exit;
405                 }
406
407                 switch(query) {
408                 case QUERY_NAME:
409                         if (root) {
410                                 printf("%s\n", udev_device_get_devnode(device));
411                         } else {
412                                 size_t len;
413
414                                 len = strlen(udev_get_dev_path(udev));
415                                 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
416                         }
417                         break;
418                 case QUERY_SYMLINK:
419                         list = udev_device_get_devlinks_list(device);
420                         while (list != NULL) {
421                                 if (root) {
422                                         printf("%s", udev_list_get_name(list));
423                                 } else {
424                                         size_t len;
425
426                                         len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
427                                         printf("%s", &udev_list_get_name(list)[len+1]);
428                                 }
429                                 list = udev_list_get_next(list);
430                                 if (list != NULL)
431                                         printf(" ");
432                         }
433                         printf("\n");
434                         break;
435                 case QUERY_PATH:
436                         printf("%s\n", udev_device_get_devpath(device));
437                         goto exit;
438                 case QUERY_ENV:
439                         list = udev_device_get_properties_list(device);
440                         while (list != NULL) {
441                                 printf("%s=%s\n", udev_list_get_name(list), udev_list_get_value(list));
442                                 list = udev_list_get_next(list);
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 = 5;
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 = 6;
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 }