chiark / gitweb /
remove "all_partitions" option
[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_ignore_remove(device);
146         if (i != 0)
147                 printf("R: %u\n", i);
148
149         i = udev_device_get_watch_handle(device);
150         if (i >= 0)
151                 printf("W: %u\n", i);
152
153         udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
154                 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
155                 printf("S: %s\n", &udev_list_entry_get_name(list_entry)[len+1]);
156         }
157
158         udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))
159                 printf("E: %s=%s\n",
160                        udev_list_entry_get_name(list_entry),
161                        udev_list_entry_get_value(list_entry));
162         printf("\n");
163 }
164
165 static int stat_device(const char *name, int export, const char *prefix)
166 {
167         struct stat statbuf;
168
169         if (stat(name, &statbuf) != 0)
170                 return -1;
171
172         if (export) {
173                 if (prefix == NULL)
174                         prefix = "INFO_";
175                 printf("%sMAJOR=%d\n"
176                        "%sMINOR=%d\n",
177                        prefix, major(statbuf.st_dev),
178                        prefix, minor(statbuf.st_dev));
179         } else
180                 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
181         return 0;
182 }
183
184 static int export_devices(struct udev *udev)
185 {
186         struct udev_enumerate *udev_enumerate;
187         struct udev_list_entry *list_entry;
188
189         udev_enumerate = udev_enumerate_new(udev);
190         if (udev_enumerate == NULL)
191                 return -1;
192         udev_enumerate_scan_devices(udev_enumerate);
193         udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
194                 struct udev_device *device;
195
196                 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
197                 if (device != NULL) {
198                         print_record(device);
199                         udev_device_unref(device);
200                 }
201         }
202         udev_enumerate_unref(udev_enumerate);
203         return 0;
204 }
205
206 int udevadm_info(struct udev *udev, int argc, char *argv[])
207 {
208         struct udev_device *device = NULL;
209         int root = 0;
210         int export = 0;
211         const char *export_prefix = NULL;
212         char path[UTIL_PATH_SIZE];
213         char name[UTIL_PATH_SIZE];
214         struct udev_list_entry *list_entry;
215         int rc = 0;
216
217         static const struct option options[] = {
218                 { "name", required_argument, NULL, 'n' },
219                 { "path", required_argument, NULL, 'p' },
220                 { "query", required_argument, NULL, 'q' },
221                 { "attribute-walk", no_argument, NULL, 'a' },
222                 { "export-db", no_argument, NULL, 'e' },
223                 { "root", no_argument, NULL, 'r' },
224                 { "device-id-of-file", required_argument, NULL, 'd' },
225                 { "export", no_argument, NULL, 'x' },
226                 { "export-prefix", required_argument, NULL, 'P' },
227                 { "version", no_argument, NULL, 'V' },
228                 { "help", no_argument, NULL, 'h' },
229                 {}
230         };
231
232         enum action_type {
233                 ACTION_NONE,
234                 ACTION_QUERY,
235                 ACTION_ATTRIBUTE_WALK,
236                 ACTION_ROOT,
237                 ACTION_DEVICE_ID_FILE,
238         } action = ACTION_NONE;
239
240         enum query_type {
241                 QUERY_NONE,
242                 QUERY_NAME,
243                 QUERY_PATH,
244                 QUERY_SYMLINK,
245                 QUERY_PROPERTY,
246                 QUERY_ALL,
247         } query = QUERY_NONE;
248
249         while (1) {
250                 int option;
251                 struct stat statbuf;
252
253                 option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL);
254                 if (option == -1)
255                         break;
256
257                 dbg(udev, "option '%c'\n", option);
258                 switch (option) {
259                 case 'n':
260                         if (device != NULL) {
261                                 fprintf(stderr, "device already specified\n");
262                                 rc = 2;
263                                 goto exit;
264                         }
265                         /* remove /dev if given */
266                         if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0)
267                                 util_strscpyl(name, sizeof(name), udev_get_dev_path(udev), "/", optarg, NULL);
268                         else
269                                 util_strscpy(name, sizeof(name), optarg);
270                         util_remove_trailing_chars(name, '/');
271                         if (stat(name, &statbuf) < 0) {
272                                 fprintf(stderr, "device node not found\n");
273                                 rc = 2;
274                                 goto exit;
275                         } else {
276                                 char type;
277
278                                 if (S_ISBLK(statbuf.st_mode)) {
279                                         type = 'b';
280                                 } else if (S_ISCHR(statbuf.st_mode)) {
281                                         type = 'c';
282                                 } else {
283                                         fprintf(stderr, "device node has wrong file type\n");
284                                         rc = 2;
285                                         goto exit;
286                                 }
287                                 device = udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
288                                 if (device == NULL) {
289                                         fprintf(stderr, "device node not found\n");
290                                         rc = 2;
291                                         goto exit;
292                                 }
293                         }
294                         break;
295                 case 'p':
296                         if (device != NULL) {
297                                 fprintf(stderr, "device already specified\n");
298                                 rc = 2;
299                                 goto exit;
300                         }
301                         /* add sys dir if needed */
302                         if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0)
303                                 util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), optarg, NULL);
304                         else
305                                 util_strscpy(path, sizeof(path), optarg);
306                         util_remove_trailing_chars(path, '/');
307                         device = udev_device_new_from_syspath(udev, path);
308                         if (device == NULL) {
309                                 fprintf(stderr, "device path not found\n");
310                                 rc = 2;
311                                 goto exit;
312                         }
313                         break;
314                 case 'q':
315                         action = ACTION_QUERY;
316                         if (strcmp(optarg, "property") == 0 || strcmp(optarg, "env") == 0) {
317                                 query = QUERY_PROPERTY;
318                         } else if (strcmp(optarg, "name") == 0) {
319                                 query = QUERY_NAME;
320                         } else if (strcmp(optarg, "symlink") == 0) {
321                                 query = QUERY_SYMLINK;
322                         } else if (strcmp(optarg, "path") == 0) {
323                                 query = QUERY_PATH;
324                         } else if (strcmp(optarg, "all") == 0) {
325                                 query = QUERY_ALL;
326                         } else {
327                                 fprintf(stderr, "unknown query type\n");
328                                 rc = 3;
329                                 goto exit;
330                         }
331                         break;
332                 case 'r':
333                         if (action == ACTION_NONE)
334                                 action = ACTION_ROOT;
335                         root = 1;
336                         break;
337                 case 'd':
338                         action = ACTION_DEVICE_ID_FILE;
339                         util_strscpy(name, sizeof(name), optarg);
340                         break;
341                 case 'a':
342                         action = ACTION_ATTRIBUTE_WALK;
343                         break;
344                 case 'e':
345                         export_devices(udev);
346                         goto exit;
347                 case 'x':
348                         export = 1;
349                         break;
350                 case 'P':
351                         export_prefix = optarg;
352                         break;
353                 case 'V':
354                         printf("%s\n", VERSION);
355                         goto exit;
356                 case 'h':
357                         printf("Usage: udevadm info OPTIONS\n"
358                                "  --query=<type>             query device information:\n"
359                                "      name                     name of device node\n"
360                                "      symlink                  pointing to node\n"
361                                "      path                     sys device path\n"
362                                "      property                 the device properties\n"
363                                "      all                      all values\n"
364                                "  --path=<syspath>           sys device path used for query or attribute walk\n"
365                                "  --name=<name>              node or symlink name used for query or attribute walk\n"
366                                "  --root                     prepend dev directory to path names\n"
367                                "  --attribute-walk           print all key matches while walking along the chain\n"
368                                "                             of parent devices\n"
369                                "  --device-id-of-file=<file> print major:minor of device containing this file\n"
370                                "  --export-db                export the content of the udev database\n"
371                                "  --help\n\n");
372                         goto exit;
373                 default:
374                         goto exit;
375                 }
376         }
377
378         switch (action) {
379         case ACTION_QUERY:
380                 if (device == NULL) {
381                         fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
382                         rc = 4;
383                         goto exit;
384                 }
385
386                 switch(query) {
387                 case QUERY_NAME: {
388                         const char *node = udev_device_get_devnode(device);
389
390                         if (node == NULL) {
391                                 fprintf(stderr, "no device node found\n");
392                                 rc = 5;
393                                 goto exit;
394                         }
395
396                         if (root) {
397                                 printf("%s\n", udev_device_get_devnode(device));
398                         } else {
399                                 size_t len = strlen(udev_get_dev_path(udev));
400
401                                 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
402                         }
403                         break;
404                 }
405                 case QUERY_SYMLINK:
406                         list_entry = udev_device_get_devlinks_list_entry(device);
407                         while (list_entry != NULL) {
408                                 if (root) {
409                                         printf("%s", udev_list_entry_get_name(list_entry));
410                                 } else {
411                                         size_t len;
412
413                                         len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
414                                         printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
415                                 }
416                                 list_entry = udev_list_entry_get_next(list_entry);
417                                 if (list_entry != NULL)
418                                         printf(" ");
419                         }
420                         printf("\n");
421                         break;
422                 case QUERY_PATH:
423                         printf("%s\n", udev_device_get_devpath(device));
424                         goto exit;
425                 case QUERY_PROPERTY:
426                         list_entry = udev_device_get_properties_list_entry(device);
427                         while (list_entry != NULL) {
428                                 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
429                                 list_entry = udev_list_entry_get_next(list_entry);
430                         }
431                         break;
432                 case QUERY_ALL:
433                         print_record(device);
434                         break;
435                 default:
436                         fprintf(stderr, "unknown query type\n");
437                         break;
438                 }
439                 break;
440         case ACTION_ATTRIBUTE_WALK:
441                 if (device == NULL) {
442                         fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
443                         rc = 4;
444                         goto exit;
445                 }
446                 print_device_chain(device);
447                 break;
448         case ACTION_DEVICE_ID_FILE:
449                 if (stat_device(name, export, export_prefix) != 0)
450                         rc = 1;
451                 break;
452         case ACTION_ROOT:
453                 printf("%s\n", udev_get_dev_path(udev));
454                 break;
455         default:
456                 fprintf(stderr, "missing option\n");
457                 rc = 1;
458                 break;
459         }
460
461 exit:
462         udev_device_unref(device);
463         return rc;
464 }