chiark / gitweb /
[PATCH] big libsysfs diet (pre 2.0 version)
[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_utils.h"
34 #include "udev_version.h"
35 #include "udev_db.h"
36 #include "logging.h"
37
38
39 #define SYSFS_VALUE_SIZE                256
40
41 #ifdef LOG
42 void log_message (int level, const char *format, ...)
43 {
44         va_list args;
45
46         va_start(args, format);
47         vsyslog(level, format, args);
48         va_end(args);
49 }
50 #endif
51
52 static void print_all_attributes(struct dlist *attr_list)
53 {
54         struct sysfs_attribute *attr;
55         char value[SYSFS_VALUE_SIZE];
56         int len;
57
58         dlist_for_each_data(attr_list, attr, struct sysfs_attribute) {
59                 if (attr->value != NULL) {
60                         strfieldcpy(value, attr->value);
61                         len = strlen(value);
62                         if (len == 0)
63                                 continue;
64
65                         /* remove trailing newline */
66                         if (value[len-1] == '\n') {
67                                 value[len-1] = '\0';
68                                 len--;
69                         }
70
71                         /* skip nonprintable values */
72                         while (len) {
73                                 if (isprint(value[len-1]) == 0)
74                                         break;
75                                 len--;
76                         }
77                         if (len == 0)
78                                 printf("    SYSFS{%s}=\"%s\"\n", attr->name, value);
79                 }
80         }
81         printf("\n");
82 }
83
84 static int print_record(struct udevice *udev)
85 {
86         printf("P: %s\n", udev->devpath);
87         printf("N: %s\n", udev->name);
88         printf("S: %s\n", udev->symlink);
89         printf("\n");
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 process_options(int argc, char *argv[])
182 {
183         static const char short_options[] = "an:p:q:rVh";
184         int option;
185         int retval = 1;
186         struct udevice udev;
187         int root = 0;
188         int attributes = 0;
189         enum query_type query = NONE;
190         char result[1024] = "";
191         char path[NAME_SIZE] = "";
192         char name[NAME_SIZE] = "";
193         char temp[NAME_SIZE];
194         char *pos;
195
196         /* get command line options */
197         while (1) {
198                 option = getopt(argc, argv, short_options);
199                 if (option == -1)
200                         break;
201
202                 dbg("option '%c'", option);
203                 switch (option) {
204                 case 'n':
205                         dbg("udev name: %s\n", optarg);
206                         strfieldcpy(name, optarg);
207                         break;
208
209                 case 'p':
210                         dbg("udev path: %s\n", optarg);
211                         strfieldcpy(path, optarg);
212                         break;
213
214                 case 'q':
215                         dbg("udev query: %s\n", optarg);
216
217                         if (strcmp(optarg, "name") == 0) {
218                                 query = NAME;
219                                 break;
220                         }
221
222                         if (strcmp(optarg, "symlink") == 0) {
223                                 query = SYMLINK;
224                                 break;
225                         }
226
227                         if (strcmp(optarg, "path") == 0) {
228                                 query = PATH;
229                                 break;
230                         }
231
232                         if (strcmp(optarg, "all") == 0) {
233                                 query = ALL;
234                                 break;
235                         }
236
237                         printf("unknown query type\n");
238                         exit(1);
239
240                 case 'r':
241                         root = 1;
242                         break;
243
244                 case 'a':
245                         attributes = 1;
246                         break;
247
248                 case 'V':
249                         printf("udevinfo, version %s\n", UDEV_VERSION);
250                         exit(0);
251
252                 case 'h':
253                         retval = 0;
254                 case '?':
255                 default:
256                         goto help;
257                 }
258         }
259
260         /* process options */
261         if (query != NONE) {
262                 if (path[0] != '\0') {
263                         /* remove sysfs_path if given */
264                         if (strncmp(path, sysfs_path, strlen(sysfs_path)) == 0) {
265                                 pos = path + strlen(sysfs_path);
266                         } else {
267                                 if (path[0] != '/') {
268                                         /* prepend '/' if missing */
269                                         strfieldcat(temp, "/");
270                                         strfieldcat(temp, path);
271                                         pos = temp;
272                                 } else {
273                                         pos = path;
274                                 }
275                         }
276                         memset(&udev, 0x00, sizeof(struct udevice));
277                         retval = udev_db_get_device_by_devpath(&udev, pos);
278                         if (retval != 0) {
279                                 printf("device not found in database\n");
280                                 goto exit;
281                         }
282                         goto print;
283                 }
284
285                 if (name[0] != '\0') {
286                         /* remove udev_root if given */
287                         int len = strlen(udev_root);
288
289                         if (strncmp(name, udev_root, len) == 0) {
290                                 pos = &name[len+1];
291                         } else
292                                 pos = name;
293
294                         memset(&udev, 0x00, sizeof(struct udevice));
295                         strfieldcpy(udev.name, pos);
296                         retval = udev_db_get_device_byname(&udev, pos);
297                         if (retval != 0) {
298                                 printf("device not found in database\n");
299                                 goto exit;
300                         }
301
302                         goto print;
303                 }
304
305                 printf("query needs device path(-p) or node name(-n) specified\n");
306                 goto exit;
307
308 print:
309                 switch(query) {
310                 case NAME:
311                         if (root) {
312                                 snprintf(result, NAME_SIZE-1, "%s/%s", udev_root, udev.name);
313                                 result[NAME_SIZE-1] = '\0';
314                         } else {
315                                 strfieldcpy(result, udev.name);
316                         }
317                         break;
318
319                 case SYMLINK:
320                         if (root) {
321                                 int slen;
322                                 char *spos;
323                                 char slink[NAME_SIZE];
324
325                                 pos = result;
326                                 foreach_strpart(udev.symlink, " \n\r", spos, slen) {
327                                         strncpy(slink, spos, slen);
328                                         slink[slen] = '\0';
329                                         pos += sprintf(pos, "%s/%s ", udev_root, slink);
330                                 }
331                         } else {
332                                 strfieldcpy(result, udev.symlink);
333                         }
334                         break;
335
336                 case PATH:
337                         strfieldcpy(result, udev.devpath);
338                         break;
339
340                 case ALL:
341                         print_record(&udev);
342                         goto exit;
343
344                 default:
345                         goto exit;
346                 }
347                 printf("%s\n", result);
348
349 exit:
350                 return retval;
351         }
352
353         if (attributes) {
354                 if (path[0] == '\0') {
355                         printf("attribute walk on device chain needs path(-p) specified\n");
356                         return -EINVAL;
357                 } else {
358                         if (strncmp(path, sysfs_path, strlen(sysfs_path)) != 0) {
359                                 /* prepend sysfs mountpoint if not given */
360                                 strfieldcpy(temp, path);
361                                 strfieldcpy(path, sysfs_path);
362                                 strfieldcat(path, temp);
363                         }
364                         print_device_chain(path);
365                         return 0;
366                 }
367         }
368
369         if (root) {
370                 printf("%s\n", udev_root);
371                 return 0;
372         }
373
374 help:
375         printf("Usage: udevinfo [-anpqrVh]\n"
376                "  -q TYPE  query database for the specified value:\n"
377                "             'name'    name of device node\n"
378                "             'symlink' pointing to node\n"
379                "             'path'    sysfs device path\n"
380                "             'all'     all values\n"
381                "\n"
382                "  -p PATH  sysfs device path used for query or chain\n"
383                "  -n NAME  node/symlink name used for query\n"
384                "\n"
385                "  -r       print udev root\n"
386                "  -a       print all SYSFS_attributes along the device chain\n"
387                "  -s       print all sysfs devices with major/minor, physical device and bus\n"
388                "  -V       print udev version\n"
389                "  -h       print this help text\n"
390                "\n");
391         return retval;
392 }
393
394 int main(int argc, char *argv[], char *envp[])
395 {
396         int rc = 0;
397
398         logging_init("udevinfo");
399
400         /* initialize our configuration */
401         udev_init_config();
402
403         rc = process_options(argc, argv);
404
405         logging_close();
406         exit(rc);
407 }