chiark / gitweb /
[PATCH] replace tdb database by simple lockless file database
[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  *
7  *      This program is free software; you can redistribute it and/or modify it
8  *      under the terms of the GNU General Public License as published by the
9  *      Free Software Foundation version 2 of the License.
10  * 
11  *      This program is distributed in the hope that it will be useful, but
12  *      WITHOUT ANY WARRANTY; without even the implied warranty of
13  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *      General Public License for more details.
15  * 
16  *      You should have received a copy of the GNU General Public License along
17  *      with this program; if not, write to the Free Software Foundation, Inc.,
18  *      675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  */
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <ctype.h>
26 #include <stdarg.h>
27 #include <unistd.h>
28 #include <errno.h>
29
30 #include "libsysfs/sysfs/libsysfs.h"
31 #include "libsysfs/dlist.h"
32 #include "udev.h"
33 #include "udev_lib.h"
34 #include "udev_version.h"
35 #include "logging.h"
36 #include "udevdb.h"
37
38
39 # define SYSFS_VALUE_MAX 200
40
41 char **main_argv;
42 int main_argc;
43
44 #ifdef LOG
45 unsigned char logname[LOGNAME_SIZE];
46 void log_message (int level, const char *format, ...)
47 {
48         va_list args;
49
50         va_start(args, format);
51         vsyslog(level, format, args);
52         va_end(args);
53 }
54 #endif
55
56 static int print_all_attributes(const char *path)
57 {
58         struct dlist *attributes;
59         struct sysfs_attribute *attr;
60         struct sysfs_directory *sysfs_dir;
61         char value[SYSFS_VALUE_MAX];
62         int len;
63         int retval = 0;
64
65         sysfs_dir = sysfs_open_directory(path);
66         if (sysfs_dir == NULL)
67                 return -1;
68
69         attributes = sysfs_get_dir_attributes(sysfs_dir);
70         if (attributes == NULL) {
71                 retval = -1;
72                 goto exit;
73         }
74
75         dlist_for_each_data(attributes, attr, struct sysfs_attribute) {
76                 if (attr->value != NULL) {
77                         strfieldcpy(value, attr->value);
78                         len = strlen(value);
79                         if (len == 0)
80                                 continue;
81
82                         /* remove trailing newline */
83                         if (value[len-1] == '\n') {
84                                 value[len-1] = '\0';
85                                 len--;
86                         }
87
88                         /* skip nonprintable values */
89                         while (len) {
90                                 if (isprint(value[len-1]) == 0)
91                                         break;
92                                 len--;
93                         }
94                         if (len == 0)
95                                 printf("    SYSFS{%s}=\"%s\"\n", attr->name, value);
96                 }
97         }
98         printf("\n");
99
100 exit:
101         sysfs_close_directory(sysfs_dir);
102
103         return retval;
104 }
105
106 static int print_record(struct udevice *udev)
107 {
108         printf("P: %s\n", udev->devpath);
109         printf("N: %s\n", udev->name);
110         printf("S: %s\n", udev->symlink);
111         printf("\n");
112         return 0;
113 }
114
115 enum query_type {
116         NONE,
117         NAME,
118         PATH,
119         SYMLINK,
120         ALL
121 };
122
123 static int print_device_chain(const char *path)
124 {
125         struct sysfs_class_device *class_dev;
126         struct sysfs_class_device *class_dev_parent;
127         struct sysfs_attribute *attr;
128         struct sysfs_device *sysfs_dev;
129         struct sysfs_device *sysfs_dev_parent;
130         int retval = 0;
131         char type;
132
133         type = get_device_type(path, "");
134         dbg("device type is %c", type);
135
136         /*  get the class dev */
137         class_dev = sysfs_open_class_device_path(path);
138         if (class_dev == NULL) {
139                 printf("couldn't get the class device\n");
140                 return -1;
141         }
142
143         printf("\nudevinfo starts with the device the node belongs to and then walks up the\n"
144                "device chain, to print for every device found, all possibly useful attributes\n"
145                "in the udev key format.\n"
146                "Only attributes within one device section may be used together in one rule,\n"
147                "to match the device for which the node will be created.\n"
148                "\n");
149
150         if (type == 'b' || type =='c') {
151                 /* read the 'dev' file for major/minor*/
152                 attr = sysfs_get_classdev_attr(class_dev, "dev");
153                 if (attr == NULL) {
154                         printf("couldn't get the \"dev\" file\n");
155                         retval = -1;
156                         goto exit;
157                 }
158                 printf("device '%s' has major:minor %s", class_dev->path, attr->value);
159         }
160
161         /* open sysfs class device directory and print all attributes */
162         printf("  looking at class device '%s':\n", class_dev->path);
163         if (print_all_attributes(class_dev->path) != 0) {
164                 printf("couldn't open class device directory\n");
165                 retval = -1;
166                 goto exit;
167         }
168
169         /* get the device link (if parent exists look here) */
170         class_dev_parent = sysfs_get_classdev_parent(class_dev);
171         if (class_dev_parent != NULL) 
172                 sysfs_dev = sysfs_get_classdev_device(class_dev_parent);
173         else 
174                 sysfs_dev = sysfs_get_classdev_device(class_dev);
175         
176         if (sysfs_dev != NULL)
177                 printf("follow the class device's \"device\"\n");
178
179         /* look the device chain upwards */
180         while (sysfs_dev != NULL) {
181                 printf("  looking at the device chain at '%s':\n", sysfs_dev->path);
182                 printf("    BUS=\"%s\"\n", sysfs_dev->bus);
183                 printf("    ID=\"%s\"\n", sysfs_dev->bus_id);
184
185                 /* open sysfs device directory and print all attributes */
186                 print_all_attributes(sysfs_dev->path);
187
188                 sysfs_dev_parent = sysfs_get_device_parent(sysfs_dev);
189                 if (sysfs_dev_parent == NULL)
190                         break;
191
192                 sysfs_dev = sysfs_dev_parent;
193         }
194
195 exit:
196         sysfs_close_class_device(class_dev);
197         return retval;
198 }
199
200 static int process_options(void)
201 {
202         static const char short_options[] = "adn:p:q:rVh";
203         int option;
204         int retval = 1;
205         struct udevice udev;
206         int root = 0;
207         int attributes = 0;
208         enum query_type query = NONE;
209         char result[NAME_SIZE] = "";
210         char path[NAME_SIZE] = "";
211         char name[NAME_SIZE] = "";
212         char temp[NAME_SIZE];
213         char *pos;
214
215         /* get command line options */
216         while (1) {
217                 option = getopt(main_argc, main_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                         strfieldcpy(name, optarg);
226                         break;
227
228                 case 'p':
229                         dbg("udev path: %s\n", optarg);
230                         strfieldcpy(path, optarg);
231                         break;
232
233                 case 'q':
234                         dbg("udev query: %s\n", optarg);
235
236                         if (strcmp(optarg, "name") == 0) {
237                                 query = NAME;
238                                 break;
239                         }
240
241                         if (strcmp(optarg, "symlink") == 0) {
242                                 query = SYMLINK;
243                                 break;
244                         }
245
246                         if (strcmp(optarg, "path") == 0) {
247                                 query = PATH;
248                                 break;
249                         }
250
251                         if (strcmp(optarg, "all") == 0) {
252                                 query = ALL;
253                                 break;
254                         }
255
256                         printf("unknown query type\n");
257                         exit(1);
258
259                 case 'r':
260                         root = 1;
261                         break;
262
263                 case 'a':
264                         attributes = 1;
265                         break;
266
267                 case 'V':
268                         printf("udevinfo, version %s\n", UDEV_VERSION);
269                         exit(0);
270
271                 case 'h':
272                         retval = 0;
273                 case '?':
274                 default:
275                         goto help;
276                 }
277         }
278
279         /* process options */
280         if (query != NONE) {
281                 if (path[0] != '\0') {
282                         /* remove sysfs_path if given */
283                         if (strncmp(path, sysfs_path, strlen(sysfs_path)) == 0) {
284                                 pos = path + strlen(sysfs_path);
285                         } else {
286                                 if (path[0] != '/') {
287                                         /* prepend '/' if missing */
288                                         strfieldcat(temp, "/");
289                                         strfieldcat(temp, path);
290                                         pos = temp;
291                                 } else {
292                                         pos = path;
293                                 }
294                         }
295                         memset(&udev, 0x00, sizeof(struct udevice));
296                         strfieldcpy(udev.devpath, pos);
297                         retval = udevdb_get_dev(&udev);
298                         if (retval != 0) {
299                                 printf("device not found in database\n");
300                                 goto exit;
301                         }
302                         goto print;
303                 }
304
305                 if (name[0] != '\0') {
306                         /* remove udev_root if given */
307                         int len = strlen(udev_root);
308
309                         if (strncmp(name, udev_root, len) == 0) {
310                                 pos = &name[len+1];
311                         } else
312                                 pos = name;
313
314                         memset(&udev, 0x00, sizeof(struct udevice));
315                         strfieldcpy(udev.name, pos);
316                         retval = udevdb_get_dev_byname(&udev, pos);
317                         if (retval != 0) {
318                                 printf("device not found in database\n");
319                                 goto exit;
320                         }
321
322                         goto print;
323                 }
324
325                 printf("query needs device path(-p) or node name(-n) specified\n");
326                 goto exit;
327
328 print:
329                 switch(query) {
330                 case NAME:
331                         if (root) {
332                                 snprintf(result, NAME_SIZE-1, "%s/%s", udev_root, udev.name);
333                                 result[NAME_SIZE-1] = '\0';
334                         } else {
335                                 strfieldcpy(result, udev.name);
336                         }
337                         break;
338
339                 case SYMLINK:
340                         strfieldcpy(result, udev.symlink);
341                         break;
342
343                 case PATH:
344                         strfieldcpy(result, path);
345                         break;
346
347                 case ALL:
348                         print_record(&udev);
349                         goto exit;
350
351                 default:
352                         goto exit;
353                 }
354                 printf("%s\n", result);
355
356 exit:
357                 return retval;
358         }
359
360         if (attributes) {
361                 if (path[0] == '\0') {
362                         printf("attribute walk on device chain needs path(-p) specified\n");
363                         return -EINVAL;
364                 } else {
365                         if (strncmp(path, sysfs_path, strlen(sysfs_path)) != 0) {
366                                 /* prepend sysfs mountpoint if not given */
367                                 strfieldcpy(temp, path);
368                                 strfieldcpy(path, sysfs_path);
369                                 strfieldcat(path, temp);
370                         }
371                         print_device_chain(path);
372                         return 0;
373                 }
374         }
375
376         if (root) {
377                 printf("%s\n", udev_root);
378                 return 0;
379         }
380
381 help:
382         printf("Usage: [-anpqrdVh]\n"
383                "  -q TYPE  query database for the specified value:\n"
384                "             'name'    name of device node\n"
385                "             'symlink' pointing to node\n"
386                "             'path'    sysfs device path\n"
387                "             'all'     all values\n"
388                "\n"
389                "  -p PATH  sysfs device path used for query or chain\n"
390                "  -n NAME  node/symlink name used for query\n"
391                "\n"
392                "  -r       print udev root\n"
393                "  -a       print all SYSFS_attributes along the device chain\n"
394                "  -V       print udev version\n"
395                "  -h       print this help text\n"
396                "\n");
397         return retval;
398 }
399
400 int main(int argc, char *argv[], char *envp[])
401 {
402         int rc = 0;
403
404         main_argv = argv;
405         main_argc = argc;
406
407         logging_init("udevinfo");
408
409         /* initialize our configuration */
410         udev_init_config();
411
412         rc = process_options();
413
414         logging_close();
415         exit(rc);
416 }