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