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