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