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