chiark / gitweb /
0a50199c15dd329ef1e81a84aeaea4843c21421b
[elogind.git] / src / udev / udev-builtin-hwdb.c
1 /***
2   This file is part of systemd.
3
4   Copyright 2012 Kay Sievers <kay@vrfy.org>
5
6   systemd is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10
11   systemd 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   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <stdio.h>
21 #include <errno.h>
22 #include <string.h>
23 #include <inttypes.h>
24 #include <ctype.h>
25 #include <stdlib.h>
26 #include <getopt.h>
27
28 #include "udev.h"
29
30 static struct udev_hwdb *hwdb;
31
32 static int builtin_hwdb(struct udev_device *dev, int argc, char *argv[], bool test) {
33         static const struct option options[] = {
34                 { "subsystem", required_argument, NULL, 's' },
35                 {}
36         };
37         const char *subsys = NULL;
38         struct udev_device *d;
39         const char *modalias;
40         char str[UTIL_NAME_SIZE];
41         struct udev_list_entry *entry;
42
43         if (!hwdb)
44                 return EXIT_FAILURE;
45
46         for (;;) {
47                 int option;
48
49                 option = getopt_long(argc, argv, "s", options, NULL);
50                 if (option == -1)
51                         break;
52
53                 switch (option) {
54                 case 's':
55                         subsys = optarg;
56                         break;
57                 }
58         }
59
60         /* search the first parent device with a modalias */
61         for (d = dev; d; d = udev_device_get_parent(d)) {
62                 const char *dsubsys = udev_device_get_subsystem(d);
63
64                 /* look only at devices of a specific subsystem */
65                 if (subsys && dsubsys && !streq(dsubsys, subsys))
66                         continue;
67
68                 modalias = udev_device_get_property_value(d, "MODALIAS");
69                 if (modalias)
70                         break;
71
72                 /* the usb_device does not have modalias, compose one */
73                 if (dsubsys && streq(dsubsys, "usb")) {
74                         const char *v, *p;
75                         int vn, pn;
76
77                         v = udev_device_get_sysattr_value(d, "idVendor");
78                         if (!v)
79                                 continue;
80                         p = udev_device_get_sysattr_value(d, "idProduct");
81                         if (!p)
82                                 continue;
83                         vn = strtol(v, NULL, 16);
84                         if (vn <= 0)
85                                 continue;
86                         pn = strtol(p, NULL, 16);
87                         if (pn <= 0)
88                                 continue;
89                         snprintf(str, sizeof(str), "usb:v%04Xp%04X*", vn, pn);
90                         modalias = str;
91                         break;
92                 }
93         }
94         if (!modalias)
95                 return EXIT_FAILURE;
96
97         udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, modalias, 0))
98         if (udev_builtin_add_property(dev, test,
99                                       udev_list_entry_get_name(entry),
100                                       udev_list_entry_get_value(entry)) < 0)
101                         return EXIT_FAILURE;
102         return EXIT_SUCCESS;
103 }
104
105 /* called at udev startup and reload */
106 static int builtin_hwdb_init(struct udev *udev)
107 {
108         if (hwdb)
109                 return 0;
110         hwdb = udev_hwdb_new(udev);
111         if (!hwdb)
112                 return -ENOMEM;
113         return 0;
114 }
115
116 /* called on udev shutdown and reload request */
117 static void builtin_hwdb_exit(struct udev *udev)
118 {
119         hwdb = udev_hwdb_unref(hwdb);
120 }
121
122 /* called every couple of seconds during event activity; 'true' if config has changed */
123 static bool builtin_hwdb_validate(struct udev *udev)
124 {
125         return udev_hwdb_validate(hwdb);
126 }
127
128 const struct udev_builtin udev_builtin_hwdb = {
129         .name = "hwdb",
130         .cmd = builtin_hwdb,
131         .init = builtin_hwdb_init,
132         .exit = builtin_hwdb_exit,
133         .validate = builtin_hwdb_validate,
134         .help = "hardware database",
135 };