chiark / gitweb /
[PATCH] udev selinux fix
[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 print_dump(struct udevice *udev) {
182         printf("%s:%s/%s\n", udev->devpath, udev_root, udev->name);
183         return 0;
184 }
185
186 static int process_options(int argc, char *argv[])
187 {
188         static const char short_options[] = "adn:p:q:rVh";
189         int option;
190         int retval = 1;
191         struct udevice udev;
192         int root = 0;
193         int attributes = 0;
194         enum query_type query = NONE;
195         char result[1024] = "";
196         char path[NAME_SIZE] = "";
197         char name[NAME_SIZE] = "";
198         char temp[NAME_SIZE];
199         char *pos;
200
201         /* get command line options */
202         while (1) {
203                 option = getopt(argc, argv, short_options);
204                 if (option == -1)
205                         break;
206
207                 dbg("option '%c'", option);
208                 switch (option) {
209                 case 'n':
210                         dbg("udev name: %s\n", optarg);
211                         strfieldcpy(name, optarg);
212                         break;
213
214                 case 'p':
215                         dbg("udev path: %s\n", optarg);
216                         strfieldcpy(path, optarg);
217                         break;
218
219                 case 'q':
220                         dbg("udev query: %s\n", optarg);
221
222                         if (strcmp(optarg, "name") == 0) {
223                                 query = NAME;
224                                 break;
225                         }
226
227                         if (strcmp(optarg, "symlink") == 0) {
228                                 query = SYMLINK;
229                                 break;
230                         }
231
232                         if (strcmp(optarg, "path") == 0) {
233                                 query = PATH;
234                                 break;
235                         }
236
237                         if (strcmp(optarg, "all") == 0) {
238                                 query = ALL;
239                                 break;
240                         }
241
242                         printf("unknown query type\n");
243                         exit(1);
244
245                 case 'r':
246                         root = 1;
247                         break;
248
249                 case 'a':
250                         attributes = 1;
251                         break;
252
253                 case 'd':
254                         udev_db_call_foreach(print_dump);
255                         exit(0);
256
257                 case 'V':
258                         printf("udevinfo, version %s\n", UDEV_VERSION);
259                         exit(0);
260
261                 case 'h':
262                         retval = 0;
263                 case '?':
264                 default:
265                         goto help;
266                 }
267         }
268
269         /* process options */
270         if (query != NONE) {
271                 if (path[0] != '\0') {
272                         /* remove sysfs_path if given */
273                         if (strncmp(path, sysfs_path, strlen(sysfs_path)) == 0) {
274                                 pos = path + strlen(sysfs_path);
275                         } else {
276                                 if (path[0] != '/') {
277                                         /* prepend '/' if missing */
278                                         strfieldcat(temp, "/");
279                                         strfieldcat(temp, path);
280                                         pos = temp;
281                                 } else {
282                                         pos = path;
283                                 }
284                         }
285                         memset(&udev, 0x00, sizeof(struct udevice));
286                         retval = udev_db_get_device_by_devpath(&udev, pos);
287                         if (retval != 0) {
288                                 printf("device not found in database\n");
289                                 goto exit;
290                         }
291                         goto print;
292                 }
293
294                 if (name[0] != '\0') {
295                         /* remove udev_root if given */
296                         int len = strlen(udev_root);
297
298                         if (strncmp(name, udev_root, len) == 0) {
299                                 pos = &name[len+1];
300                         } else
301                                 pos = name;
302
303                         memset(&udev, 0x00, sizeof(struct udevice));
304                         strfieldcpy(udev.name, pos);
305                         retval = udev_db_get_device_by_name(&udev, pos);
306                         if (retval != 0) {
307                                 printf("device not found in database\n");
308                                 goto exit;
309                         }
310
311                         goto print;
312                 }
313
314                 printf("query needs device path(-p) or node name(-n) specified\n");
315                 goto exit;
316
317 print:
318                 switch(query) {
319                 case NAME:
320                         if (root) {
321                                 snprintf(result, NAME_SIZE-1, "%s/%s", udev_root, udev.name);
322                                 result[NAME_SIZE-1] = '\0';
323                         } else {
324                                 strfieldcpy(result, udev.name);
325                         }
326                         break;
327
328                 case SYMLINK:
329                         if (root) {
330                                 int slen;
331                                 char *spos;
332                                 char slink[NAME_SIZE];
333
334                                 pos = result;
335                                 foreach_strpart(udev.symlink, " \n\r", spos, slen) {
336                                         strncpy(slink, spos, slen);
337                                         slink[slen] = '\0';
338                                         pos += sprintf(pos, "%s/%s ", udev_root, slink);
339                                 }
340                         } else {
341                                 strfieldcpy(result, udev.symlink);
342                         }
343                         break;
344
345                 case PATH:
346                         strfieldcpy(result, udev.devpath);
347                         break;
348
349                 case ALL:
350                         print_record(&udev);
351                         goto exit;
352
353                 default:
354                         goto exit;
355                 }
356                 printf("%s\n", result);
357
358 exit:
359                 return retval;
360         }
361
362         if (attributes) {
363                 if (path[0] == '\0') {
364                         printf("attribute walk on device chain needs path(-p) specified\n");
365                         return -EINVAL;
366                 } else {
367                         if (strncmp(path, sysfs_path, strlen(sysfs_path)) != 0) {
368                                 /* prepend sysfs mountpoint if not given */
369                                 strfieldcpy(temp, path);
370                                 strfieldcpy(path, sysfs_path);
371                                 strfieldcat(path, temp);
372                         }
373                         print_device_chain(path);
374                         return 0;
375                 }
376         }
377
378         if (root) {
379                 printf("%s\n", udev_root);
380                 return 0;
381         }
382
383 help:
384         printf("Usage: udevinfo [-anpqrVh]\n"
385                "  -q TYPE  query database for the specified value:\n"
386                "             'name'    name of device node\n"
387                "             'symlink' pointing to node\n"
388                "             'path'    sysfs device path\n"
389                "             'all'     all values\n"
390                "\n"
391                "  -p PATH  sysfs device path used for query or chain\n"
392                "  -n NAME  node/symlink name used for query\n"
393                "\n"
394                "  -r       print udev root\n"
395                "  -a       print all SYSFS_attributes along the device chain\n"
396                "  -d       print the relationship of devpath and the node name for all\n"
397                "           devices available in the database\n"
398                "  -V       print udev version\n"
399                "  -h       print this help text\n"
400                "\n");
401         return retval;
402 }
403
404 int main(int argc, char *argv[], char *envp[])
405 {
406         int rc = 0;
407
408         logging_init("udevinfo");
409
410         /* initialize our configuration */
411         udev_init_config();
412
413         rc = process_options(argc, argv);
414
415         logging_close();
416         exit(rc);
417 }