]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/udev/udev-builtin-hwdb.c
udev-ctrl: move prototypes of udev_ctrl_*() to udev-ctrl.h
[thirdparty/systemd.git] / src / udev / udev-builtin-hwdb.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
ccba91c7 2
67410e9f 3#include <fnmatch.h>
796b06c2 4#include <getopt.h>
07630cea
LP
5#include <stdio.h>
6#include <stdlib.h>
ccba91c7 7
c532d8a0 8#include "sd-hwdb.h"
ccba91c7 9
b5efdb8a 10#include "alloc-util.h"
c532d8a0 11#include "hwdb-util.h"
5547c125 12#include "parse-util.h"
07630cea 13#include "string-util.h"
07630cea 14#include "udev.h"
c532d8a0
TG
15
16static sd_hwdb *hwdb;
ccba91c7 17
67410e9f 18int udev_builtin_hwdb_lookup(struct udev_device *dev,
a4bbef09
KS
19 const char *prefix, const char *modalias,
20 const char *filter, bool test) {
45d9a304 21 _cleanup_free_ char *lookup = NULL;
c532d8a0 22 const char *key, *value;
59803c38
KS
23 int n = 0;
24
33c770b1
KS
25 if (!hwdb)
26 return -ENOENT;
27
a4bbef09 28 if (prefix) {
605405c6 29 lookup = strjoin(prefix, modalias);
a4bbef09
KS
30 if (!lookup)
31 return -ENOMEM;
c532d8a0
TG
32 modalias = lookup;
33 }
a4bbef09 34
c532d8a0
TG
35 SD_HWDB_FOREACH_PROPERTY(hwdb, modalias, key, value) {
36 if (filter && fnmatch(filter, key, FNM_NOESCAPE) != 0)
67410e9f
KS
37 continue;
38
c532d8a0 39 if (udev_builtin_add_property(dev, test, key, value) < 0)
59803c38
KS
40 return -ENOMEM;
41 n++;
42 }
43 return n;
44}
45
46static const char *modalias_usb(struct udev_device *dev, char *s, size_t size) {
47 const char *v, *p;
5547c125 48 uint16_t vn, pn;
59803c38
KS
49
50 v = udev_device_get_sysattr_value(dev, "idVendor");
51 if (!v)
52 return NULL;
53 p = udev_device_get_sysattr_value(dev, "idProduct");
54 if (!p)
55 return NULL;
5547c125 56 if (safe_atoux16(v, &vn) < 0)
2f5fa62b 57 return NULL;
5547c125 58 if (safe_atoux16(p, &pn) < 0)
2f5fa62b 59 return NULL;
59803c38
KS
60 snprintf(s, size, "usb:v%04Xp%04X*", vn, pn);
61 return s;
62}
63
67410e9f 64static int udev_builtin_hwdb_search(struct udev_device *dev, struct udev_device *srcdev,
a4bbef09
KS
65 const char *subsystem, const char *prefix,
66 const char *filter, bool test) {
59803c38
KS
67 struct udev_device *d;
68 char s[16];
77cf759e
KS
69 bool last = false;
70 int r = 0;
59803c38 71
3b64e4d4
TG
72 assert(dev);
73
e448a1c3
TG
74 if (!srcdev)
75 srcdev = dev;
76
77cf759e 77 for (d = srcdev; d && !last; d = udev_device_get_parent(d)) {
59803c38
KS
78 const char *dsubsys;
79 const char *modalias = NULL;
80
81 dsubsys = udev_device_get_subsystem(d);
82 if (!dsubsys)
83 continue;
84
85 /* look only at devices of a specific subsystem */
86 if (subsystem && !streq(dsubsys, subsystem))
87 continue;
88
0238cf7c
KS
89 modalias = udev_device_get_property_value(d, "MODALIAS");
90
77cf759e
KS
91 if (streq(dsubsys, "usb") && streq_ptr(udev_device_get_devtype(d), "usb_device")) {
92 /* if the usb_device does not have a modalias, compose one */
93 if (!modalias)
94 modalias = modalias_usb(d, s, sizeof(s));
95
96 /* avoid looking at any parent device, they are usually just a USB hub */
97 last = true;
98 }
59803c38 99
59803c38
KS
100 if (!modalias)
101 continue;
67410e9f 102
77cf759e
KS
103 r = udev_builtin_hwdb_lookup(dev, prefix, modalias, filter, test);
104 if (r > 0)
59803c38
KS
105 break;
106 }
107
77cf759e 108 return r;
59803c38
KS
109}
110
2001208c
KS
111static int builtin_hwdb(struct udev_device *dev, int argc, char *argv[], bool test) {
112 static const struct option options[] = {
67410e9f
KS
113 { "filter", required_argument, NULL, 'f' },
114 { "device", required_argument, NULL, 'd' },
2001208c 115 { "subsystem", required_argument, NULL, 's' },
a4bbef09 116 { "lookup-prefix", required_argument, NULL, 'p' },
2001208c 117 {}
796b06c2 118 };
67410e9f
KS
119 const char *filter = NULL;
120 const char *device = NULL;
59803c38 121 const char *subsystem = NULL;
a4bbef09 122 const char *prefix = NULL;
8e766630 123 _cleanup_(udev_device_unrefp) struct udev_device *srcdev = NULL;
ccba91c7 124
2001208c
KS
125 if (!hwdb)
126 return EXIT_FAILURE;
ccba91c7 127
2001208c
KS
128 for (;;) {
129 int option;
ccba91c7 130
a4bbef09 131 option = getopt_long(argc, argv, "f:d:s:p:", options, NULL);
2001208c
KS
132 if (option == -1)
133 break;
ccba91c7 134
2001208c 135 switch (option) {
67410e9f
KS
136 case 'f':
137 filter = optarg;
138 break;
139
140 case 'd':
141 device = optarg;
142 break;
143
2001208c 144 case 's':
59803c38 145 subsystem = optarg;
2001208c 146 break;
a4bbef09
KS
147
148 case 'p':
149 prefix = optarg;
150 break;
912541b0
KS
151 }
152 }
ccba91c7 153
6824690f
KS
154 /* query a specific key given as argument */
155 if (argv[optind]) {
a4bbef09 156 if (udev_builtin_hwdb_lookup(dev, prefix, argv[optind], filter, test) > 0)
6824690f
KS
157 return EXIT_SUCCESS;
158 return EXIT_FAILURE;
159 }
160
67410e9f
KS
161 /* read data from another device than the device we will store the data */
162 if (device) {
2024ed61 163 srcdev = udev_device_new_from_device_id(NULL, device);
67410e9f
KS
164 if (!srcdev)
165 return EXIT_FAILURE;
e448a1c3 166 }
67410e9f 167
beef8df8
KS
168 if (udev_builtin_hwdb_search(dev, srcdev, subsystem, prefix, filter, test) > 0)
169 return EXIT_SUCCESS;
170 return EXIT_FAILURE;
796b06c2 171}
ccba91c7 172
796b06c2 173/* called at udev startup and reload */
2024ed61 174static int builtin_hwdb_init(void) {
c532d8a0
TG
175 int r;
176
2001208c 177 if (hwdb)
5b4d50ef 178 return 0;
c532d8a0
TG
179
180 r = sd_hwdb_new(&hwdb);
181 if (r < 0)
182 return r;
183
912541b0 184 return 0;
3cf5266b 185}
ccba91c7 186
796b06c2 187/* called on udev shutdown and reload request */
2024ed61 188static void builtin_hwdb_exit(void) {
c532d8a0 189 hwdb = sd_hwdb_unref(hwdb);
ccba91c7 190}
3cf5266b 191
796b06c2 192/* called every couple of seconds during event activity; 'true' if config has changed */
2024ed61 193static bool builtin_hwdb_validate(void) {
c532d8a0 194 return hwdb_validate(hwdb);
796b06c2 195}
3cf5266b 196
796b06c2
KS
197const struct udev_builtin udev_builtin_hwdb = {
198 .name = "hwdb",
199 .cmd = builtin_hwdb,
200 .init = builtin_hwdb_init,
201 .exit = builtin_hwdb_exit,
202 .validate = builtin_hwdb_validate,
5ac0162c 203 .help = "Hardware database",
3cf5266b 204};