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