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