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