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