chiark / gitweb /
4d13a5f6dc65027e34eb7676c2a72044ff7e80e4
[elogind.git] / udevinfo.c
1 /*
2  * udevinfo - fetches attributes for a device
3  *
4  * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
5  *
6  *      This program is free software; you can redistribute it and/or modify it
7  *      under the terms of the GNU General Public License as published by the
8  *      Free Software Foundation version 2 of the License.
9  * 
10  *      This program is distributed in the hope that it will be useful, but
11  *      WITHOUT ANY WARRANTY; without even the implied warranty of
12  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *      General Public License for more details.
14  * 
15  *      You should have received a copy of the GNU General Public License along
16  *      with this program; if not, write to the Free Software Foundation, Inc.,
17  *      675 Mass Ave, Cambridge, MA 02139, USA.
18  *
19  */
20
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <ctype.h>
25 #include <stdarg.h>
26 #include <unistd.h>
27 #include <errno.h>
28
29 #include "libsysfs/sysfs/libsysfs.h"
30 #include "libsysfs/dlist.h"
31 #include "udev_libc_wrapper.h"
32 #include "udev.h"
33 #include "udev_utils.h"
34 #include "udev_version.h"
35 #include "udev_db.h"
36 #include "logging.h"
37
38
39 #ifdef USE_LOG
40 void log_message (int level, const char *format, ...)
41 {
42         va_list args;
43
44         va_start(args, format);
45         vsyslog(level, format, args);
46         va_end(args);
47 }
48 #endif
49
50 static void print_all_attributes(struct dlist *attr_list)
51 {
52         struct sysfs_attribute *attr;
53         char value[VALUE_SIZE];
54         int len;
55
56         dlist_for_each_data(attr_list, attr, struct sysfs_attribute) {
57                 if (attr->value != NULL) {
58                         strlcpy(value, attr->value, sizeof(value));
59                         len = strlen(value);
60                         if (len == 0)
61                                 continue;
62
63                         /* remove trailing newline */
64                         if (value[len-1] == '\n') {
65                                 value[len-1] = '\0';
66                                 len--;
67                         }
68
69                         /* skip nonprintable values */
70                         while (len) {
71                                 if (isprint(value[len-1]) == 0)
72                                         break;
73                                 len--;
74                         }
75                         if (len == 0)
76                                 printf("    SYSFS{%s}=\"%s\"\n", attr->name, value);
77                 }
78         }
79         printf("\n");
80 }
81
82 static int print_record(struct udevice *udev)
83 {
84         struct name_entry *name_loop;
85
86         printf("P: %s\n", udev->devpath);
87         printf("N: %s\n", udev->name);
88         list_for_each_entry(name_loop, &udev->symlink_list, node)
89                 printf("S: %s\n", name_loop->name);
90
91         return 0;
92 }
93
94 enum query_type {
95         NONE,
96         NAME,
97         PATH,
98         SYMLINK,
99         ALL,
100 };
101
102 static int print_device_chain(const char *path)
103 {
104         struct sysfs_class_device *class_dev;
105         struct sysfs_class_device *class_dev_parent;
106         struct sysfs_attribute *attr;
107         struct sysfs_device *sysfs_dev;
108         struct sysfs_device *sysfs_dev_parent;
109         struct dlist *attr_list;
110         int retval = 0;
111
112         /*  get the class dev */
113         class_dev = sysfs_open_class_device_path(path);
114         if (class_dev == NULL) {
115                 printf("couldn't get the class device\n");
116                 return -1;
117         }
118
119         printf("\nudevinfo starts with the device the node belongs to and then walks up the\n"
120                "device chain, to print for every device found, all possibly useful attributes\n"
121                "in the udev key format.\n"
122                "Only attributes within one device section may be used together in one rule,\n"
123                "to match the device for which the node will be created.\n"
124                "\n");
125
126         /* look for the 'dev' file */
127         attr = sysfs_get_classdev_attr(class_dev, "dev");
128         if (attr != NULL)
129                 printf("device '%s' has major:minor %s", class_dev->path, attr->value);
130
131         /* open sysfs class device directory and print all attributes */
132         printf("  looking at class device '%s':\n", class_dev->path);
133         printf("    SUBSYSTEM=\"%s\"\n", class_dev->classname);
134
135         attr_list = sysfs_get_classdev_attributes(class_dev);
136         if (attr_list == NULL) {
137                 printf("couldn't open class device directory\n");
138                 retval = -1;
139                 goto exit;
140         }
141         print_all_attributes(attr_list);
142
143         /* get the device link (if parent exists look here) */
144         class_dev_parent = sysfs_get_classdev_parent(class_dev);
145         if (class_dev_parent != NULL) 
146                 sysfs_dev = sysfs_get_classdev_device(class_dev_parent);
147         else 
148                 sysfs_dev = sysfs_get_classdev_device(class_dev);
149         
150         if (sysfs_dev != NULL)
151                 printf("follow the class device's \"device\"\n");
152
153         /* look the device chain upwards */
154         while (sysfs_dev != NULL) {
155                 attr_list = sysfs_get_device_attributes(sysfs_dev);
156                 if (attr_list == NULL) {
157                         printf("couldn't open device directory\n");
158                         retval = -1;
159                         goto exit;
160                 }
161
162                 printf("  looking at the device chain at '%s':\n", sysfs_dev->path);
163                 printf("    BUS=\"%s\"\n", sysfs_dev->bus);
164                 printf("    ID=\"%s\"\n", sysfs_dev->bus_id);
165                 printf("    DRIVER=\"%s\"\n", sysfs_dev->driver_name);
166
167                 /* open sysfs device directory and print all attributes */
168                 print_all_attributes(attr_list);
169
170                 sysfs_dev_parent = sysfs_get_device_parent(sysfs_dev);
171                 if (sysfs_dev_parent == NULL)
172                         break;
173
174                 sysfs_dev = sysfs_dev_parent;
175         }
176
177 exit:
178         sysfs_close_class_device(class_dev);
179         return retval;
180 }
181
182 static int print_dump(const char *devpath, const char *name) {
183         printf("%s:%s/%s\n", devpath, udev_root, name);
184         return 0;
185 }
186
187 int main(int argc, char *argv[], char *envp[])
188 {
189         static const char short_options[] = "adn:p:q:rVh";
190         int option;
191         struct udevice udev;
192         int root = 0;
193         int attributes = 0;
194         enum query_type query = NONE;
195         char path[PATH_SIZE] = "";
196         char name[PATH_SIZE] = "";
197         char temp[PATH_SIZE];
198         struct name_entry *name_loop;
199         char *pos;
200         int retval = 0;
201
202         logging_init("udevinfo");
203
204         udev_init_config();
205         udev_init_device(&udev, NULL, NULL);
206
207         /* get command line options */
208         while (1) {
209                 option = getopt(argc, argv, short_options);
210                 if (option == -1)
211                         break;
212
213                 dbg("option '%c'", option);
214                 switch (option) {
215                 case 'n':
216                         dbg("udev name: %s\n", optarg);
217                         strlcpy(name, optarg, sizeof(name));
218                         break;
219
220                 case 'p':
221                         dbg("udev path: %s\n", optarg);
222                         strlcpy(path, optarg, sizeof(path));
223                         break;
224
225                 case 'q':
226                         dbg("udev query: %s\n", optarg);
227
228                         if (strcmp(optarg, "name") == 0) {
229                                 query = NAME;
230                                 break;
231                         }
232
233                         if (strcmp(optarg, "symlink") == 0) {
234                                 query = SYMLINK;
235                                 break;
236                         }
237
238                         if (strcmp(optarg, "path") == 0) {
239                                 query = PATH;
240                                 break;
241                         }
242
243                         if (strcmp(optarg, "all") == 0) {
244                                 query = ALL;
245                                 break;
246                         }
247
248                         printf("unknown query type\n");
249                         retval = 1;
250                         goto exit;
251
252                 case 'r':
253                         root = 1;
254                         break;
255
256                 case 'a':
257                         attributes = 1;
258                         break;
259
260                 case 'd':
261                         udev_db_dump_names(print_dump);
262                         goto exit;
263
264                 case 'V':
265                         printf("udevinfo, version %s\n", UDEV_VERSION);
266                         goto exit;
267
268                 case 'h':
269                         retval = 2;
270                 case '?':
271                 default:
272                         goto help;
273                 }
274         }
275
276         /* process options */
277         if (query != NONE) {
278                 if (path[0] != '\0') {
279                         /* remove sysfs_path if given */
280                         if (strncmp(path, sysfs_path, strlen(sysfs_path)) == 0) {
281                                 pos = path + strlen(sysfs_path);
282                         } else {
283                                 if (path[0] != '/') {
284                                         /* prepend '/' if missing */
285                                         strcpy(temp, "/");
286                                         strlcpy(temp, path, sizeof(temp));
287                                         pos = temp;
288                                 } else {
289                                         pos = path;
290                                 }
291                         }
292                         retval = udev_db_get_device(&udev, pos);
293                         if (retval != 0) {
294                                 printf("device not found in database\n");
295                                 goto exit;
296                         }
297                         goto print;
298                 }
299
300                 if (name[0] != '\0') {
301                         char devpath[PATH_SIZE];
302                         int len;
303
304                         /* remove udev_root if given */
305                         len = strlen(udev_root);
306                         if (strncmp(name, udev_root, len) == 0) {
307                                 pos = &name[len+1];
308                         } else
309                                 pos = name;
310
311                         retval = udev_db_search_name(devpath, sizeof(devpath), pos);
312                         if (retval != 0) {
313                                 printf("device not found in database\n");
314                                 goto exit;
315                         }
316                         udev_db_get_device(&udev, devpath);
317                         goto print;
318                 }
319
320                 printf("query needs device path(-p) or node name(-n) specified\n");
321                 retval = 3;
322                 goto exit;
323
324 print:
325                 switch(query) {
326                 case NAME:
327                         if (root)
328                                 printf("%s/%s\n", udev_root, udev.name);
329                         else
330                                 printf("%s\n", udev.name);
331                         goto exit;
332                 case SYMLINK:
333                         if (list_empty(&udev.symlink_list))
334                                 break;
335                         if (root)
336                                 list_for_each_entry(name_loop, &udev.symlink_list, node)
337                                         printf("%s/%s ", udev_root, name_loop->name);
338                         else
339                                 list_for_each_entry(name_loop, &udev.symlink_list, node)
340                                         printf("%s ", name_loop->name);
341                         printf("\n");
342                         goto exit;
343                 case PATH:
344                         printf("%s\n", udev.devpath);
345                         goto exit;
346                 case ALL:
347                         print_record(&udev);
348                         goto exit;
349                 default:
350                         goto help;
351                 }
352         }
353
354         if (attributes) {
355                 if (path[0] == '\0') {
356                         printf("attribute walk on device chain needs path(-p) specified\n");
357                         retval = 4;
358                         goto exit;
359                 } else {
360                         if (strncmp(path, sysfs_path, strlen(sysfs_path)) != 0) {
361                                 /* prepend sysfs mountpoint if not given */
362                                 snprintf(temp, sizeof(temp), "%s%s", sysfs_path, path);
363                                 temp[sizeof(temp)-1] = '\0';
364                                 strlcpy(path, temp, sizeof(temp));
365                         }
366                         print_device_chain(path);
367                         goto exit;
368                 }
369         }
370
371         if (root) {
372                 printf("%s\n", udev_root);
373                 goto exit;
374         }
375
376 help:
377         printf("Usage: udevinfo [-anpqrVh]\n"
378                "  -q TYPE  query database for the specified value:\n"
379                "             'name'    name of device node\n"
380                "             'symlink' pointing to node\n"
381                "             'path'    sysfs device path\n"
382                "             'all'     all values\n"
383                "\n"
384                "  -p PATH  sysfs device path used for query or chain\n"
385                "  -n NAME  node/symlink name used for query\n"
386                "\n"
387                "  -r       print udev root\n"
388                "  -a       print all SYSFS_attributes along the device chain\n"
389                "  -d       print the relationship of devpath and the node name for all\n"
390                "           devices available in the database\n"
391                "  -V       print udev version\n"
392                "  -h       print this help text\n"
393                "\n");
394
395 exit:
396         udev_cleanup_device(&udev);
397         logging_close();
398         return retval;
399 }