chiark / gitweb /
[PATCH] big cleanup of internal udev api
[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 /* callback for database dump */
107 static int print_record(const char *path, struct udevice *dev)
108 {
109         printf("P: %s\n", path);
110         printf("N: %s\n", dev->name);
111         printf("T: %c\n", dev->type);
112         printf("M: %#o\n", dev->mode);
113         printf("S: %s\n", dev->symlink);
114         printf("O: %s\n", dev->owner);
115         printf("G: %s\n", dev->group);
116         printf("F: %s\n", dev->config_file);
117         printf("L: %i\n", dev->config_line);
118         printf("U: %li\n", dev->config_uptime);
119         printf("\n");
120         return 0;
121 }
122
123 enum query_type {
124         NONE,
125         NAME,
126         PATH,
127         SYMLINK,
128         MODE,
129         OWNER,
130         GROUP,
131         ALL
132 };
133
134 static int print_device_chain(const char *path)
135 {
136         struct sysfs_class_device *class_dev;
137         struct sysfs_class_device *class_dev_parent;
138         struct sysfs_attribute *attr;
139         struct sysfs_device *sysfs_dev;
140         struct sysfs_device *sysfs_dev_parent;
141         int retval = 0;
142         char type;
143
144         type = get_device_type(path, "");
145         dbg("device type is %c", type);
146
147         /*  get the class dev */
148         class_dev = sysfs_open_class_device_path(path);
149         if (class_dev == NULL) {
150                 printf("couldn't get the class device\n");
151                 return -1;
152         }
153
154         printf("\nudevinfo starts with the device the node belongs to and then walks up the\n"
155                "device chain, to print for every device found, all possibly useful attributes\n"
156                "in the udev key format.\n"
157                "Only attributes within one device section may be used together in one rule,\n"
158                "to match the device for which the node will be created.\n"
159                "\n");
160
161         if (type == 'b' || type =='c') {
162                 /* read the 'dev' file for major/minor*/
163                 attr = sysfs_get_classdev_attr(class_dev, "dev");
164                 if (attr == NULL) {
165                         printf("couldn't get the \"dev\" file\n");
166                         retval = -1;
167                         goto exit;
168                 }
169                 printf("device '%s' has major:minor %s", class_dev->path, attr->value);
170         }
171
172         /* open sysfs class device directory and print all attributes */
173         printf("  looking at class device '%s':\n", class_dev->path);
174         if (print_all_attributes(class_dev->path) != 0) {
175                 printf("couldn't open class device directory\n");
176                 retval = -1;
177                 goto exit;
178         }
179
180         /* get the device link (if parent exists look here) */
181         class_dev_parent = sysfs_get_classdev_parent(class_dev);
182         if (class_dev_parent != NULL) 
183                 sysfs_dev = sysfs_get_classdev_device(class_dev_parent);
184         else 
185                 sysfs_dev = sysfs_get_classdev_device(class_dev);
186         
187         if (sysfs_dev != NULL)
188                 printf("follow the class device's \"device\"\n");
189
190         /* look the device chain upwards */
191         while (sysfs_dev != NULL) {
192                 printf("  looking at the device chain at '%s':\n", sysfs_dev->path);
193                 printf("    BUS=\"%s\"\n", sysfs_dev->bus);
194                 printf("    ID=\"%s\"\n", sysfs_dev->bus_id);
195
196                 /* open sysfs device directory and print all attributes */
197                 print_all_attributes(sysfs_dev->path);
198
199                 sysfs_dev_parent = sysfs_get_device_parent(sysfs_dev);
200                 if (sysfs_dev_parent == NULL)
201                         break;
202
203                 sysfs_dev = sysfs_dev_parent;
204         }
205
206 exit:
207         sysfs_close_class_device(class_dev);
208         return retval;
209 }
210
211 static int process_options(void)
212 {
213         static const char short_options[] = "adn:p:q:rVh";
214         int option;
215         int retval = 1;
216         struct udevice dev;
217         int root = 0;
218         int attributes = 0;
219         enum query_type query = NONE;
220         char result[NAME_SIZE] = "";
221         char path[NAME_SIZE] = "";
222         char name[NAME_SIZE] = "";
223         char temp[NAME_SIZE];
224         char *pos;
225
226         /* get command line options */
227         while (1) {
228                 option = getopt(main_argc, main_argv, short_options);
229                 if (option == -1)
230                         break;
231
232                 dbg("option '%c'", option);
233                 switch (option) {
234                 case 'n':
235                         dbg("udev name: %s\n", optarg);
236                         strfieldcpy(name, optarg);
237                         break;
238
239                 case 'p':
240                         dbg("udev path: %s\n", optarg);
241                         strfieldcpy(path, optarg);
242                         break;
243
244                 case 'q':
245                         dbg("udev query: %s\n", optarg);
246
247                         if (strcmp(optarg, "name") == 0) {
248                                 query = NAME;
249                                 break;
250                         }
251
252                         if (strcmp(optarg, "symlink") == 0) {
253                                 query = SYMLINK;
254                                 break;
255                         }
256
257                         if (strcmp(optarg, "mode") == 0) {
258                                 query = MODE;
259                                 break;
260                         }
261
262                         if (strcmp(optarg, "owner") == 0) {
263                                 query = OWNER;
264                                 break;
265                         }
266
267                         if (strcmp(optarg, "group") == 0) {
268                                 query = GROUP;
269                                 break;
270                         }
271
272                         if (strcmp(optarg, "path") == 0) {
273                                 query = PATH;
274                                 break;
275                         }
276
277                         if (strcmp(optarg, "all") == 0) {
278                                 query = ALL;
279                                 break;
280                         }
281
282                         printf("unknown query type\n");
283                         exit(1);
284
285                 case 'r':
286                         root = 1;
287                         break;
288
289                 case 'a':
290                         attributes = 1;
291                         break;
292
293                 case 'd':
294                         retval = udevdb_open_ro();
295                         if (retval != 0) {
296                                 printf("unable to open udev database\n");
297                                 exit(2);
298                         }
299                         udevdb_call_foreach(print_record);
300                         udevdb_exit();
301                         exit(0);
302
303                 case 'V':
304                         printf("udevinfo, version %s\n", UDEV_VERSION);
305                         exit(0);
306
307                 case 'h':
308                         retval = 0;
309                 case '?':
310                 default:
311                         goto help;
312                 }
313         }
314
315         /* process options */
316         if (query != NONE) {
317                 retval = udevdb_open_ro();
318                 if (retval != 0) {
319                         printf("unable to open udev database\n");
320                         return -EACCES;
321                 }
322
323                 if (path[0] != '\0') {
324                         /* remove sysfs_path if given */
325                         if (strncmp(path, sysfs_path, strlen(sysfs_path)) == 0) {
326                                 pos = path + strlen(sysfs_path);
327                         } else {
328                                 if (path[0] != '/') {
329                                         /* prepend '/' if missing */
330                                         strfieldcat(temp, "/");
331                                         strfieldcat(temp, path);
332                                         pos = temp;
333                                 } else {
334                                         pos = path;
335                                 }
336                         }
337                         retval = udevdb_get_dev(pos, &dev);
338                         if (retval != 0) {
339                                 printf("device not found in database\n");
340                                 goto exit;
341                         }
342                         goto print;
343                 }
344
345                 if (name[0] != '\0') {
346                         /* remove udev_root if given */
347                         if (strncmp(name, udev_root, strlen(udev_root)) == 0) {
348                                 pos = name + strlen(udev_root);
349                         } else
350                                 pos = name;
351                         retval = udevdb_get_dev_byname(pos, path, &dev);
352                         if (retval != 0) {
353                                 printf("device not found in database\n");
354                                 goto exit;
355                         }
356                         goto print;
357                 }
358
359                 printf("query needs device path(-p) or node name(-n) specified\n");
360                 goto exit;
361
362 print:
363                 switch(query) {
364                 case NAME:
365                         if (root)
366                                 strfieldcpy(result, udev_root);
367                         strfieldcat(result, dev.name);
368                         break;
369
370                 case SYMLINK:
371                         strfieldcpy(result, dev.symlink);
372                         break;
373
374                 case MODE:
375                         sprintf(result, "%#o", dev.mode);
376                         break;
377
378                 case GROUP:
379                         strfieldcpy(result, dev.group);
380                         break;
381
382                 case OWNER:
383                         strfieldcpy(result, dev.owner);
384                         break;
385
386                 case PATH:
387                         strfieldcpy(result, path);
388                         break;
389
390                 case ALL:
391                         print_record(path, &dev);
392                         goto exit;
393
394                 default:
395                         goto exit;
396                 }
397                 printf("%s\n", result);
398
399 exit:
400                 udevdb_exit();
401                 return retval;
402         }
403
404         if (attributes) {
405                 if (path[0] == '\0') {
406                         printf("attribute walk on device chain needs path(-p) specified\n");
407                         return -EINVAL;
408                 } else {
409                         if (strncmp(path, sysfs_path, strlen(sysfs_path)) != 0) {
410                                 /* prepend sysfs mountpoint if not given */
411                                 strfieldcpy(temp, path);
412                                 strfieldcpy(path, sysfs_path);
413                                 strfieldcat(path, temp);
414                         }
415                         print_device_chain(path);
416                         return 0;
417                 }
418         }
419
420         if (root) {
421                 printf("%s\n", udev_root);
422                 return 0;
423         }
424
425 help:
426         printf("Usage: [-anpqrdVh]\n"
427                "  -q TYPE  query database for the specified value:\n"
428                "             'name'    name of device node\n"
429                "             'symlink' pointing to node\n"
430                "             'mode'    permissions of node\n"
431                "             'owner'   of node\n"
432                "             'group'   of node\n"
433                "             'path'    sysfs device path\n"
434                "             'all'     all values\n"
435                "\n"
436                "  -p PATH  sysfs device path used for query or chain\n"
437                "  -n NAME  node/symlink name used for query\n"
438                "\n"
439                "  -r       print udev root\n"
440                "  -a       print all SYSFS_attributes along the device chain\n"
441                "  -d       dump whole database\n"
442                "  -V       print udev version\n"
443                "  -h       print this help text\n"
444                "\n");
445         return retval;
446 }
447
448 int main(int argc, char *argv[], char *envp[])
449 {
450         int rc = 0;
451
452         main_argv = argv;
453         main_argc = argc;
454
455         logging_init("udevinfo");
456
457         /* initialize our configuration */
458         udev_init_config();
459
460         rc = process_options();
461
462         logging_close();
463         exit(rc);
464 }