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