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