~ubuntu-core-dev/udev/ubuntu

« back to all changes in this revision

Viewing changes to udevinfo.c

  • Committer: Kay Sievers
  • Date: 2008-07-29 22:39:15 UTC
  • mto: (2352.4.2)
  • mto: This revision was merged to the branch mainline in revision 2363.
  • Revision ID: kay.sievers@vrfy.org-20080729223915-i3gxfsu2ms63rl5n
delete all Makefiles and move udev source to udev/

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (C) 2004-2006 Kay Sievers <kay.sievers@vrfy.org>
3
 
 *
4
 
 *      This program is free software; you can redistribute it and/or modify it
5
 
 *      under the terms of the GNU General Public License as published by the
6
 
 *      Free Software Foundation version 2 of the License.
7
 
 * 
8
 
 *      This program is distributed in the hope that it will be useful, but
9
 
 *      WITHOUT ANY WARRANTY; without even the implied warranty of
10
 
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
 
 *      General Public License for more details.
12
 
 * 
13
 
 *      You should have received a copy of the GNU General Public License along
14
 
 *      with this program; if not, write to the Free Software Foundation, Inc.,
15
 
 *      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
16
 
 *
17
 
 */
18
 
 
19
 
#include <stdlib.h>
20
 
#include <string.h>
21
 
#include <stdio.h>
22
 
#include <stddef.h>
23
 
#include <ctype.h>
24
 
#include <stdarg.h>
25
 
#include <unistd.h>
26
 
#include <dirent.h>
27
 
#include <errno.h>
28
 
#include <getopt.h>
29
 
#include <sys/stat.h>
30
 
#include <sys/types.h>
31
 
 
32
 
#include "udev.h"
33
 
 
34
 
static void print_all_attributes(const char *devpath, const char *key)
35
 
{
36
 
        char path[PATH_SIZE];
37
 
        DIR *dir;
38
 
        struct dirent *dent;
39
 
 
40
 
        strlcpy(path, sysfs_path, sizeof(path));
41
 
        strlcat(path, devpath, sizeof(path));
42
 
 
43
 
        dir = opendir(path);
44
 
        if (dir != NULL) {
45
 
                for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
46
 
                        struct stat statbuf;
47
 
                        char filename[PATH_SIZE];
48
 
                        char *attr_value;
49
 
                        char value[NAME_SIZE];
50
 
                        size_t len;
51
 
 
52
 
                        if (dent->d_name[0] == '.')
53
 
                                continue;
54
 
 
55
 
                        if (strcmp(dent->d_name, "uevent") == 0)
56
 
                                continue;
57
 
                        if (strcmp(dent->d_name, "dev") == 0)
58
 
                                continue;
59
 
 
60
 
                        strlcpy(filename, path, sizeof(filename));
61
 
                        strlcat(filename, "/", sizeof(filename));
62
 
                        strlcat(filename, dent->d_name, sizeof(filename));
63
 
                        if (lstat(filename, &statbuf) != 0)
64
 
                                continue;
65
 
                        if (S_ISLNK(statbuf.st_mode))
66
 
                                continue;
67
 
 
68
 
                        attr_value = sysfs_attr_get_value(devpath, dent->d_name);
69
 
                        if (attr_value == NULL)
70
 
                                continue;
71
 
                        len = strlcpy(value, attr_value, sizeof(value));
72
 
                        if(len >= sizeof(value))
73
 
                                len = sizeof(value) - 1;
74
 
                        dbg("attr '%s'='%s'(%zi)\n", dent->d_name, value, len);
75
 
 
76
 
                        /* remove trailing newlines */
77
 
                        while (len && value[len-1] == '\n')
78
 
                                value[--len] = '\0';
79
 
 
80
 
                        /* skip nonprintable attributes */
81
 
                        while (len && isprint(value[len-1]))
82
 
                                len--;
83
 
                        if (len) {
84
 
                                dbg("attribute value of '%s' non-printable, skip\n", dent->d_name);
85
 
                                continue;
86
 
                        }
87
 
 
88
 
                        printf("    %s{%s}==\"%s\"\n", key, dent->d_name, value);
89
 
                }
90
 
        }
91
 
        printf("\n");
92
 
}
93
 
 
94
 
static int print_device_chain(const char *devpath)
95
 
{
96
 
        struct sysfs_device *dev;
97
 
 
98
 
        dev = sysfs_device_get(devpath);
99
 
        if (dev == NULL)
100
 
                return -1;
101
 
 
102
 
        printf("\n"
103
 
               "Udevinfo starts with the device specified by the devpath and then\n"
104
 
               "walks up the chain of parent devices. It prints for every device\n"
105
 
               "found, all possible attributes in the udev rules key format.\n"
106
 
               "A rule to match, can be composed by the attributes of the device\n"
107
 
               "and the attributes from one single parent device.\n"
108
 
               "\n");
109
 
 
110
 
        printf("  looking at device '%s':\n", dev->devpath);
111
 
        printf("    KERNEL==\"%s\"\n", dev->kernel);
112
 
        printf("    SUBSYSTEM==\"%s\"\n", dev->subsystem);
113
 
        printf("    DRIVER==\"%s\"\n", dev->driver);
114
 
        print_all_attributes(dev->devpath, "ATTR");
115
 
 
116
 
        /* walk up the chain of devices */
117
 
        while (1) {
118
 
                dev = sysfs_device_get_parent(dev);
119
 
                if (dev == NULL)
120
 
                        break;
121
 
                printf("  looking at parent device '%s':\n", dev->devpath);
122
 
                printf("    KERNELS==\"%s\"\n", dev->kernel);
123
 
                printf("    SUBSYSTEMS==\"%s\"\n", dev->subsystem);
124
 
                printf("    DRIVERS==\"%s\"\n", dev->driver);
125
 
 
126
 
                print_all_attributes(dev->devpath, "ATTRS");
127
 
        }
128
 
 
129
 
        return 0;
130
 
}
131
 
 
132
 
static void print_record(struct udevice *udev)
133
 
{
134
 
        struct name_entry *name_loop;
135
 
 
136
 
        printf("P: %s\n", udev->dev->devpath);
137
 
        printf("N: %s\n", udev->name);
138
 
        list_for_each_entry(name_loop, &udev->symlink_list, node)
139
 
                printf("S: %s\n", name_loop->name);
140
 
        if (udev->link_priority != 0)
141
 
                printf("L: %i\n", udev->link_priority);
142
 
        if (udev->partitions != 0)
143
 
                printf("A:%u\n", udev->partitions);
144
 
        if (udev->ignore_remove)
145
 
                printf("R:%u\n", udev->ignore_remove);
146
 
        list_for_each_entry(name_loop, &udev->env_list, node)
147
 
                printf("E: %s\n", name_loop->name);
148
 
}
149
 
 
150
 
static void export_db(void) {
151
 
        LIST_HEAD(name_list);
152
 
        struct name_entry *name_loop;
153
 
 
154
 
        udev_db_get_all_entries(&name_list);
155
 
        list_for_each_entry(name_loop, &name_list, node) {
156
 
                struct udevice *udev_db;
157
 
 
158
 
                udev_db = udev_device_init(NULL);
159
 
                if (udev_db == NULL)
160
 
                        continue;
161
 
                if (udev_db_get_device(udev_db, name_loop->name) == 0)
162
 
                        print_record(udev_db);
163
 
                        printf("\n");
164
 
                udev_device_cleanup(udev_db);
165
 
        }
166
 
        name_list_cleanup(&name_list);
167
 
}
168
 
 
169
 
static int lookup_device_by_name(struct udevice *udev, const char *name)
170
 
{
171
 
        LIST_HEAD(name_list);
172
 
        int count;
173
 
        struct name_entry *device;
174
 
        int rc  = -1;
175
 
 
176
 
        count = udev_db_get_devices_by_name(name, &name_list);
177
 
        if (count <= 0)
178
 
                goto out;
179
 
 
180
 
        info("found %i devices for '%s'\n", count, name);
181
 
 
182
 
        /* select the device that seems to match */
183
 
        list_for_each_entry(device, &name_list, node) {
184
 
                char filename[PATH_SIZE];
185
 
                struct stat statbuf;
186
 
 
187
 
                udev_device_init(udev);
188
 
                if (udev_db_get_device(udev, device->name) != 0)
189
 
                        continue;
190
 
                info("found db entry '%s'\n", device->name);
191
 
 
192
 
                /* make sure, we don't get a link of a differnt device */
193
 
                strlcpy(filename, udev_root, sizeof(filename));
194
 
                strlcat(filename, "/", sizeof(filename));
195
 
                strlcat(filename, name, sizeof(filename));
196
 
                if (stat(filename, &statbuf) != 0)
197
 
                        continue;
198
 
                if (major(udev->devt) > 0 && udev->devt != statbuf.st_rdev) {
199
 
                        info("skip '%s', dev_t doesn't match\n", udev->name);
200
 
                        continue;
201
 
                }
202
 
                rc = 0;
203
 
                break;
204
 
        }
205
 
out:
206
 
        name_list_cleanup(&name_list);
207
 
        return rc;
208
 
}
209
 
 
210
 
static int stat_device(const char *name, int export, const char *prefix)
211
 
{
212
 
        struct stat statbuf;
213
 
 
214
 
        if (stat(name, &statbuf) != 0)
215
 
                return -1;
216
 
 
217
 
        if (export) {
218
 
                if (prefix == NULL)
219
 
                        prefix = "INFO_";
220
 
                printf("%sMAJOR=%d\n"
221
 
                       "%sMINOR=%d\n",
222
 
                       prefix, major(statbuf.st_dev),
223
 
                       prefix, minor(statbuf.st_dev));
224
 
        } else
225
 
                printf("%d %d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
226
 
        return 0;
227
 
}
228
 
 
229
 
int udevinfo(int argc, char *argv[], char *envp[])
230
 
{
231
 
        int option;
232
 
        struct udevice *udev;
233
 
        int root = 0;
234
 
        int export = 0;
235
 
        const char *export_prefix = NULL;
236
 
 
237
 
        static const struct option options[] = {
238
 
                { "name", 1, NULL, 'n' },
239
 
                { "path", 1, NULL, 'p' },
240
 
                { "query", 1, NULL, 'q' },
241
 
                { "attribute-walk", 0, NULL, 'a' },
242
 
                { "export-db", 0, NULL, 'e' },
243
 
                { "root", 0, NULL, 'r' },
244
 
                { "device-id-of-file", 1, NULL, 'd' },
245
 
                { "export", 0, NULL, 'x' },
246
 
                { "export-prefix", 1, NULL, 'P' },
247
 
                { "version", 0, NULL, 1 }, /* -V outputs braindead format */
248
 
                { "help", 0, NULL, 'h' },
249
 
                {}
250
 
        };
251
 
 
252
 
        enum action_type {
253
 
                ACTION_NONE,
254
 
                ACTION_QUERY,
255
 
                ACTION_ATTRIBUTE_WALK,
256
 
                ACTION_ROOT,
257
 
                ACTION_DEVICE_ID_FILE,
258
 
        } action = ACTION_NONE;
259
 
 
260
 
        enum query_type {
261
 
                QUERY_NONE,
262
 
                QUERY_NAME,
263
 
                QUERY_PATH,
264
 
                QUERY_SYMLINK,
265
 
                QUERY_ENV,
266
 
                QUERY_ALL,
267
 
        } query = QUERY_NONE;
268
 
 
269
 
        char path[PATH_SIZE] = "";
270
 
        char name[PATH_SIZE] = "";
271
 
        struct name_entry *name_loop;
272
 
        int rc = 0;
273
 
 
274
 
        logging_init("udevinfo");
275
 
        udev_config_init();
276
 
        sysfs_init();
277
 
 
278
 
        udev = udev_device_init(NULL);
279
 
        if (udev == NULL) {
280
 
                rc = 1;
281
 
                goto exit;
282
 
        }
283
 
 
284
 
        while (1) {
285
 
                option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL);
286
 
                if (option == -1)
287
 
                        break;
288
 
 
289
 
                dbg("option '%c'\n", option);
290
 
                switch (option) {
291
 
                case 'n':
292
 
                        /* remove /dev if given */
293
 
                        if (strncmp(optarg, udev_root, strlen(udev_root)) == 0)
294
 
                                strlcpy(name, &optarg[strlen(udev_root)+1], sizeof(name));
295
 
                        else
296
 
                                strlcpy(name, optarg, sizeof(name));
297
 
                        remove_trailing_chars(name, '/');
298
 
                        dbg("name: %s\n", name);
299
 
                        break;
300
 
                case 'p':
301
 
                        /* remove /sys if given */
302
 
                        if (strncmp(optarg, sysfs_path, strlen(sysfs_path)) == 0)
303
 
                                strlcpy(path, &optarg[strlen(sysfs_path)], sizeof(path));
304
 
                        else
305
 
                                strlcpy(path, optarg, sizeof(path));
306
 
                        remove_trailing_chars(path, '/');
307
 
 
308
 
                        /* possibly resolve to real devpath */
309
 
                        if (sysfs_resolve_link(path, sizeof(path)) != 0) {
310
 
                                char temp[PATH_SIZE];
311
 
                                char *pos;
312
 
 
313
 
                                /* also check if the parent is a link */
314
 
                                strlcpy(temp, path, sizeof(temp));
315
 
                                pos = strrchr(temp, '/');
316
 
                                if (pos != 0) {
317
 
                                        char tail[PATH_SIZE];
318
 
 
319
 
                                        strlcpy(tail, pos, sizeof(tail));
320
 
                                        pos[0] = '\0';
321
 
                                        if (sysfs_resolve_link(temp, sizeof(temp)) == 0) {
322
 
                                                strlcpy(path, temp, sizeof(path));
323
 
                                                strlcat(path, tail, sizeof(path));
324
 
                                        }
325
 
                                }
326
 
                        }
327
 
                        dbg("path: %s\n", path);
328
 
                        break;
329
 
                case 'q':
330
 
                        action = ACTION_QUERY;
331
 
                        if (strcmp(optarg, "name") == 0) {
332
 
                                query = QUERY_NAME;
333
 
                                break;
334
 
                        }
335
 
                        if (strcmp(optarg, "symlink") == 0) {
336
 
                                query = QUERY_SYMLINK;
337
 
                                break;
338
 
                        }
339
 
                        if (strcmp(optarg, "path") == 0) {
340
 
                                query = QUERY_PATH;
341
 
                                break;
342
 
                        }
343
 
                        if (strcmp(optarg, "env") == 0) {
344
 
                                query = QUERY_ENV;
345
 
                                break;
346
 
                        }
347
 
                        if (strcmp(optarg, "all") == 0) {
348
 
                                query = QUERY_ALL;
349
 
                                break;
350
 
                        }
351
 
                        fprintf(stderr, "unknown query type\n");
352
 
                        rc = 2;
353
 
                        goto exit;
354
 
                case 'r':
355
 
                        if (action == ACTION_NONE)
356
 
                                action = ACTION_ROOT;
357
 
                        root = 1;
358
 
                        break;
359
 
                case 'd':
360
 
                        action = ACTION_DEVICE_ID_FILE;
361
 
                        strlcpy(name, optarg, sizeof(name));
362
 
                        break;
363
 
                case 'a':
364
 
                        action = ACTION_ATTRIBUTE_WALK;
365
 
                        break;
366
 
                case 'e':
367
 
                        export_db();
368
 
                        goto exit;
369
 
                case 'x':
370
 
                        export = 1;
371
 
                        break;
372
 
                case 'P':
373
 
                        export_prefix = optarg;
374
 
                        break;
375
 
                case 1:
376
 
                        printf("%s\n", UDEV_VERSION);
377
 
                        goto exit;
378
 
                case 'V':
379
 
                        printf("udevinfo, version %s\n", UDEV_VERSION);
380
 
                        goto exit;
381
 
                case 'h':
382
 
                        printf("Usage: udevadm info OPTIONS\n"
383
 
                               "  --query=<type>             query database for the specified value:\n"
384
 
                               "      name                     name of device node\n"
385
 
                               "      symlink                  pointing to node\n"
386
 
                               "      path                     sysfs device path\n"
387
 
                               "      env                      the device related imported environment\n"
388
 
                               "      all                      all values\n"
389
 
                               "  --path=<devpath>           sysfs device path used for query or chain\n"
390
 
                               "  --name=<name>              node or symlink name used for query\n"
391
 
                               "  --root                     prepend to query result or print udev_root\n"
392
 
                               "  --attribute-walk           print all key matches while walking along chain\n"
393
 
                               "                             of parent devices\n"
394
 
                               "  --device-id-of-file=<file> print major/minor of underlying device\n"
395
 
                               "  --export-db                export the content of the udev database\n"
396
 
                               "  --help                     print this text\n"
397
 
                               "\n");
398
 
                        goto exit;
399
 
                default:
400
 
                        goto exit;
401
 
                }
402
 
        }
403
 
 
404
 
        /* run action */
405
 
        switch (action) {
406
 
        case ACTION_QUERY:
407
 
                /* needs devpath or node/symlink name for query */
408
 
                if (path[0] != '\0') {
409
 
                        if (udev_db_get_device(udev, path) != 0) {
410
 
                                fprintf(stderr, "no record for '%s' in database\n", path);
411
 
                                rc = 3;
412
 
                                goto exit;
413
 
                        }
414
 
                } else if (name[0] != '\0') {
415
 
                        if (lookup_device_by_name(udev, name) != 0) {
416
 
                                fprintf(stderr, "node name not found\n");
417
 
                                rc = 4;
418
 
                                goto exit;
419
 
                        }
420
 
                } else {
421
 
                        fprintf(stderr, "query needs --path or node --name specified\n");
422
 
                        rc = 4;
423
 
                        goto exit;
424
 
                }
425
 
 
426
 
                switch(query) {
427
 
                case QUERY_NAME:
428
 
                        if (root)
429
 
                                printf("%s/%s\n", udev_root, udev->name);
430
 
                        else
431
 
                                printf("%s\n", udev->name);
432
 
                        break;
433
 
                case QUERY_SYMLINK:
434
 
                        list_for_each_entry(name_loop, &udev->symlink_list, node) {
435
 
                                char c = name_loop->node.next != &udev->symlink_list ? ' ' : '\n';
436
 
 
437
 
                                if (root)
438
 
                                        printf("%s/%s%c", udev_root, name_loop->name, c);
439
 
                                else
440
 
                                        printf("%s%c", name_loop->name, c);
441
 
                        }
442
 
                        break;
443
 
                case QUERY_PATH:
444
 
                        printf("%s\n", udev->dev->devpath);
445
 
                        goto exit;
446
 
                case QUERY_ENV:
447
 
                        list_for_each_entry(name_loop, &udev->env_list, node)
448
 
                                printf("%s\n", name_loop->name);
449
 
                        break;
450
 
                case QUERY_ALL:
451
 
                        print_record(udev);
452
 
                        break;
453
 
                default:
454
 
                        fprintf(stderr, "unknown query type\n");
455
 
                        break;
456
 
                }
457
 
                break;
458
 
        case ACTION_ATTRIBUTE_WALK:
459
 
                if (path[0] != '\0') {
460
 
                        if (print_device_chain(path) != 0) {
461
 
                                fprintf(stderr, "no valid sysfs device found\n");
462
 
                                rc = 4;
463
 
                                goto exit;
464
 
                        }
465
 
                } else if (name[0] != '\0') {
466
 
                        if (lookup_device_by_name(udev, name) != 0) {
467
 
                                fprintf(stderr, "node name not found\n");
468
 
                                rc = 4;
469
 
                                goto exit;
470
 
                        }
471
 
                        if (print_device_chain(udev->dev->devpath) != 0) {
472
 
                                fprintf(stderr, "no valid sysfs device found\n");
473
 
                                rc = 4;
474
 
                                goto exit;
475
 
                        }
476
 
                } else {
477
 
                        fprintf(stderr, "attribute walk needs --path or node --name specified\n");
478
 
                        rc = 5;
479
 
                        goto exit;
480
 
                }
481
 
                break;
482
 
        case ACTION_DEVICE_ID_FILE:
483
 
                if (stat_device(name, export, export_prefix) != 0)
484
 
                        rc = 6;
485
 
                break;
486
 
        case ACTION_ROOT:
487
 
                printf("%s\n", udev_root);
488
 
                break;
489
 
        default:
490
 
                fprintf(stderr, "missing option\n");
491
 
                rc = 1;
492
 
                break;
493
 
        }
494
 
 
495
 
exit:
496
 
        udev_device_cleanup(udev);
497
 
        sysfs_cleanup();
498
 
        logging_close();
499
 
        return rc;
500
 
}