chiark / gitweb /
change parameter order of udev_db_search_name()
[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         struct name_entry *tmp_loop;
174
175         udev_db_get_all_entries(&name_list);
176         list_for_each_entry_safe(name_loop, tmp_loop, &name_list, node) {
177                 struct udevice udev_db;
178
179                 udev_init_device(&udev_db, NULL, NULL, NULL);
180                 if (udev_db_get_device(&udev_db, name_loop->name) == 0) {
181                         printf("%s=%s/%s\n", udev_db.devpath, udev_root, udev_db.name);
182                         free(name_loop);
183                 }
184                 udev_cleanup_device(&udev_db);
185         }
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 {
196                 QUERY_NONE,
197                 QUERY_NAME,
198                 QUERY_PATH,
199                 QUERY_SYMLINK,
200                 QUERY_ENV,
201                 QUERY_ALL,
202         } query = QUERY_NONE;
203         char path[PATH_SIZE] = "";
204         char name[PATH_SIZE] = "";
205         char temp[PATH_SIZE];
206         struct name_entry *name_loop;
207         char *pos;
208         int retval = 0;
209
210         logging_init("udevinfo");
211
212         udev_init_config();
213         udev_init_device(&udev, NULL, NULL, NULL);
214
215         /* get command line options */
216         while (1) {
217                 option = getopt(argc, argv, short_options);
218                 if (option == -1)
219                         break;
220
221                 dbg("option '%c'", option);
222                 switch (option) {
223                 case 'n':
224                         dbg("udev name: %s\n", optarg);
225                         strlcpy(name, optarg, sizeof(name));
226                         break;
227
228                 case 'p':
229                         dbg("udev path: %s\n", optarg);
230                         strlcpy(path, optarg, sizeof(path));
231                         break;
232
233                 case 'q':
234                         dbg("udev query: %s\n", optarg);
235
236                         if (strcmp(optarg, "name") == 0) {
237                                 query = QUERY_NAME;
238                                 break;
239                         }
240
241                         if (strcmp(optarg, "symlink") == 0) {
242                                 query = QUERY_SYMLINK;
243                                 break;
244                         }
245
246                         if (strcmp(optarg, "path") == 0) {
247                                 query = QUERY_PATH;
248                                 break;
249                         }
250
251                         if (strcmp(optarg, "env") == 0) {
252                                 query = QUERY_ENV;
253                                 break;
254                         }
255
256                         if (strcmp(optarg, "all") == 0) {
257                                 query = QUERY_ALL;
258                                 break;
259                         }
260
261                         fprintf(stderr, "unknown query type\n");
262                         retval = 1;
263                         goto exit;
264
265                 case 'r':
266                         root = 1;
267                         break;
268
269                 case 'a':
270                         attributes = 1;
271                         break;
272
273                 case 'd':
274                         dump_names();
275                         goto exit;
276
277                 case 'V':
278                         printf("udevinfo, version %s\n", UDEV_VERSION);
279                         goto exit;
280
281                 case 'h':
282                         retval = 2;
283                 case '?':
284                 default:
285                         goto help;
286                 }
287         }
288
289         /* process options */
290         if (query != QUERY_NONE) {
291                 if (path[0] != '\0') {
292                         /* remove sysfs_path if given */
293                         if (strncmp(path, sysfs_path, strlen(sysfs_path)) == 0) {
294                                 pos = path + strlen(sysfs_path);
295                         } else {
296                                 if (path[0] != '/') {
297                                         /* prepend '/' if missing */
298                                         strcpy(temp, "/");
299                                         strlcpy(temp, path, sizeof(temp));
300                                         pos = temp;
301                                 } else {
302                                         pos = path;
303                                 }
304                         }
305                         retval = udev_db_get_device(&udev, pos);
306                         if (retval != 0) {
307                                 fprintf(stderr, "no record for '%s' in database\n", pos);
308                                 goto exit;
309                         }
310                         goto print;
311                 }
312
313                 if (name[0] != '\0') {
314                         char devpath[PATH_SIZE];
315                         int len;
316
317                         /* remove udev_root if given */
318                         len = strlen(udev_root);
319                         if (strncmp(name, udev_root, len) == 0) {
320                                 pos = &name[len+1];
321                         } else
322                                 pos = name;
323
324                         retval = udev_db_search_name(pos, devpath, sizeof(devpath));
325                         if (retval != 0) {
326                                 fprintf(stderr, "no record for '%s' in database\n", pos);
327                                 goto exit;
328                         }
329                         udev_db_get_device(&udev, devpath);
330                         goto print;
331                 }
332
333                 fprintf(stderr, "query needs device path(-p) or node name(-n) specified\n");
334                 retval = 3;
335                 goto exit;
336
337 print:
338                 switch(query) {
339                 case QUERY_NAME:
340                         if (root)
341                                 printf("%s/%s\n", udev_root, udev.name);
342                         else
343                                 printf("%s\n", udev.name);
344                         goto exit;
345                 case QUERY_SYMLINK:
346                         if (list_empty(&udev.symlink_list))
347                                 goto exit;
348                         if (root)
349                                 list_for_each_entry(name_loop, &udev.symlink_list, node)
350                                         printf("%s/%s ", udev_root, name_loop->name);
351                         else
352                                 list_for_each_entry(name_loop, &udev.symlink_list, node)
353                                         printf("%s ", name_loop->name);
354                         printf("\n");
355                         goto exit;
356                 case QUERY_PATH:
357                         printf("%s\n", udev.devpath);
358                         goto exit;
359                 case QUERY_ENV:
360                         list_for_each_entry(name_loop, &udev.env_list, node)
361                                 printf("%s\n", name_loop->name);
362                         goto exit;
363                 case QUERY_ALL:
364                         print_record(&udev);
365                         goto exit;
366                 default:
367                         goto help;
368                 }
369         }
370
371         if (attributes) {
372                 if (path[0] == '\0') {
373                         fprintf(stderr, "attribute walk on device chain needs path(-p) specified\n");
374                         retval = 4;
375                         goto exit;
376                 } else {
377                         if (strncmp(path, sysfs_path, strlen(sysfs_path)) != 0) {
378                                 /* prepend sysfs mountpoint if not given */
379                                 snprintf(temp, sizeof(temp), "%s%s", sysfs_path, path);
380                                 temp[sizeof(temp)-1] = '\0';
381                                 strlcpy(path, temp, sizeof(temp));
382                         }
383                         print_device_chain(path);
384                         goto exit;
385                 }
386         }
387
388         if (root) {
389                 printf("%s\n", udev_root);
390                 goto exit;
391         }
392
393 help:
394         fprintf(stderr, "Usage: udevinfo [-anpqrVh]\n"
395                "  -q TYPE  query database for the specified value:\n"
396                "             'name'    name of device node\n"
397                "             'symlink' pointing to node\n"
398                "             'path'    sysfs device path\n"
399                "             'env'     the device related imported environment\n"
400                "             'all'     all values\n"
401                "\n"
402                "  -p PATH  sysfs device path used for query or chain\n"
403                "  -n NAME  node/symlink name used for query\n"
404                "\n"
405                "  -r       print udev root\n"
406                "  -a       print all SYSFS_attributes along the device chain\n"
407                "  -d       print the relationship of devpath and the node name for all\n"
408                "           devices available in the database\n"
409                "  -V       print udev version\n"
410                "  -h       print this help text\n"
411                "\n");
412
413 exit:
414         udev_cleanup_device(&udev);
415         logging_close();
416         return retval;
417 }