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