chiark / gitweb /
fix the fix and change the file to wait for to the "bus" link
[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         size_t len;
57
58         dlist_for_each_data(attr_list, attr, struct sysfs_attribute) {
59                 if (attr->value == NULL)
60                         continue;
61                 len = strlcpy(value, attr->value, sizeof(value));
62                 if (len >= sizeof(value)) {
63                         dbg("attribute value of '%s' too long, skip", attr->name);
64                         continue;
65                 }
66
67                 /* remove trailing newlines */
68                 while (len && value[len-1] == '\n')
69                         value[--len] = '\0';
70                 /* skip nonprintable attributes */
71                 while (len && isprint(value[len-1]))
72                         len--;
73                 if (len) {
74                         dbg("attribute value of '%s' non-printable, skip", attr->name);
75                         continue;
76                 }
77                 replace_untrusted_chars(value);
78                 printf("    SYSFS{%s}==\"%s\"\n", attr->name, value);
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 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                 fprintf(stderr, "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                 fprintf(stderr, "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 \"device\"-link to the physical device:\n");
152
153         /* look the device chain upwards */
154         while (sysfs_dev != NULL) {
155                 printf("  looking at the device chain at '%s':\n", sysfs_dev->path);
156                 printf("    BUS==\"%s\"\n", sysfs_dev->bus);
157                 printf("    ID==\"%s\"\n", sysfs_dev->bus_id);
158                 printf("    DRIVER==\"%s\"\n", sysfs_dev->driver_name);
159
160                 attr_list = sysfs_get_device_attributes(sysfs_dev);
161                 if (attr_list != NULL)
162                         print_all_attributes(attr_list);
163                 else
164                         printf("\n");
165
166                 sysfs_dev = sysfs_get_device_parent(sysfs_dev);
167                 if (sysfs_dev == NULL)
168                         break;
169         }
170
171 exit:
172         sysfs_close_class_device(class_dev);
173         return retval;
174 }
175
176 static int print_dump(const char *devpath, const char *name) {
177         printf("%s=%s/%s\n", devpath, udev_root, name);
178         return 0;
179 }
180
181 int main(int argc, char *argv[], char *envp[])
182 {
183         static const char short_options[] = "adn:p:q:rVh";
184         int option;
185         struct udevice udev;
186         int root = 0;
187         int attributes = 0;
188         enum query_type query = NONE;
189         char path[PATH_SIZE] = "";
190         char name[PATH_SIZE] = "";
191         char temp[PATH_SIZE];
192         struct name_entry *name_loop;
193         char *pos;
194         int retval = 0;
195
196         logging_init("udevinfo");
197
198         udev_init_config();
199         udev_init_device(&udev, NULL, NULL, NULL);
200
201         /* get command line options */
202         while (1) {
203                 option = getopt(argc, argv, short_options);
204                 if (option == -1)
205                         break;
206
207                 dbg("option '%c'", option);
208                 switch (option) {
209                 case 'n':
210                         dbg("udev name: %s\n", optarg);
211                         strlcpy(name, optarg, sizeof(name));
212                         break;
213
214                 case 'p':
215                         dbg("udev path: %s\n", optarg);
216                         strlcpy(path, optarg, sizeof(path));
217                         break;
218
219                 case 'q':
220                         dbg("udev query: %s\n", optarg);
221
222                         if (strcmp(optarg, "name") == 0) {
223                                 query = NAME;
224                                 break;
225                         }
226
227                         if (strcmp(optarg, "symlink") == 0) {
228                                 query = SYMLINK;
229                                 break;
230                         }
231
232                         if (strcmp(optarg, "path") == 0) {
233                                 query = PATH;
234                                 break;
235                         }
236
237                         if (strcmp(optarg, "all") == 0) {
238                                 query = ALL;
239                                 break;
240                         }
241
242                         fprintf(stderr, "unknown query type\n");
243                         retval = 1;
244                         goto exit;
245
246                 case 'r':
247                         root = 1;
248                         break;
249
250                 case 'a':
251                         attributes = 1;
252                         break;
253
254                 case 'd':
255                         udev_db_dump_names(print_dump);
256                         goto exit;
257
258                 case 'V':
259                         printf("udevinfo, version %s\n", UDEV_VERSION);
260                         goto exit;
261
262                 case 'h':
263                         retval = 2;
264                 case '?':
265                 default:
266                         goto help;
267                 }
268         }
269
270         /* process options */
271         if (query != NONE) {
272                 if (path[0] != '\0') {
273                         /* remove sysfs_path if given */
274                         if (strncmp(path, sysfs_path, strlen(sysfs_path)) == 0) {
275                                 pos = path + strlen(sysfs_path);
276                         } else {
277                                 if (path[0] != '/') {
278                                         /* prepend '/' if missing */
279                                         strcpy(temp, "/");
280                                         strlcpy(temp, path, sizeof(temp));
281                                         pos = temp;
282                                 } else {
283                                         pos = path;
284                                 }
285                         }
286                         retval = udev_db_get_device(&udev, pos);
287                         if (retval != 0) {
288                                 fprintf(stderr, "device not found in database\n");
289                                 goto exit;
290                         }
291                         goto print;
292                 }
293
294                 if (name[0] != '\0') {
295                         char devpath[PATH_SIZE];
296                         int len;
297
298                         /* remove udev_root if given */
299                         len = strlen(udev_root);
300                         if (strncmp(name, udev_root, len) == 0) {
301                                 pos = &name[len+1];
302                         } else
303                                 pos = name;
304
305                         retval = udev_db_search_name(devpath, sizeof(devpath), pos);
306                         if (retval != 0) {
307                                 fprintf(stderr, "device not found in database\n");
308                                 goto exit;
309                         }
310                         udev_db_get_device(&udev, devpath);
311                         goto print;
312                 }
313
314                 fprintf(stderr, "query needs device path(-p) or node name(-n) specified\n");
315                 retval = 3;
316                 goto exit;
317
318 print:
319                 switch(query) {
320                 case NAME:
321                         if (root)
322                                 printf("%s/%s\n", udev_root, udev.name);
323                         else
324                                 printf("%s\n", udev.name);
325                         goto exit;
326                 case SYMLINK:
327                         if (list_empty(&udev.symlink_list))
328                                 break;
329                         if (root)
330                                 list_for_each_entry(name_loop, &udev.symlink_list, node)
331                                         printf("%s/%s ", udev_root, name_loop->name);
332                         else
333                                 list_for_each_entry(name_loop, &udev.symlink_list, node)
334                                         printf("%s ", name_loop->name);
335                         printf("\n");
336                         goto exit;
337                 case PATH:
338                         printf("%s\n", udev.devpath);
339                         goto exit;
340                 case ALL:
341                         print_record(&udev);
342                         goto exit;
343                 default:
344                         goto help;
345                 }
346         }
347
348         if (attributes) {
349                 if (path[0] == '\0') {
350                         fprintf(stderr, "attribute walk on device chain needs path(-p) specified\n");
351                         retval = 4;
352                         goto exit;
353                 } else {
354                         if (strncmp(path, sysfs_path, strlen(sysfs_path)) != 0) {
355                                 /* prepend sysfs mountpoint if not given */
356                                 snprintf(temp, sizeof(temp), "%s%s", sysfs_path, path);
357                                 temp[sizeof(temp)-1] = '\0';
358                                 strlcpy(path, temp, sizeof(temp));
359                         }
360                         print_device_chain(path);
361                         goto exit;
362                 }
363         }
364
365         if (root) {
366                 printf("%s\n", udev_root);
367                 goto exit;
368         }
369
370 help:
371         fprintf(stderr, "Usage: udevinfo [-anpqrVh]\n"
372                "  -q TYPE  query database for the specified value:\n"
373                "             'name'    name of device node\n"
374                "             'symlink' pointing to node\n"
375                "             'path'    sysfs device path\n"
376                "             'all'     all values\n"
377                "\n"
378                "  -p PATH  sysfs device path used for query or chain\n"
379                "  -n NAME  node/symlink name used for query\n"
380                "\n"
381                "  -r       print udev root\n"
382                "  -a       print all SYSFS_attributes along the device chain\n"
383                "  -d       print the relationship of devpath and the node name for all\n"
384                "           devices available in the database\n"
385                "  -V       print udev version\n"
386                "  -h       print this help text\n"
387                "\n");
388
389 exit:
390         udev_cleanup_device(&udev);
391         logging_close();
392         return retval;
393 }