udev-builtin-hwdb.c revision beef8df837fb0ef708143b34aa85a897400e8992
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/***
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering This file is part of systemd.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Copyright 2012 Kay Sievers <kay@vrfy.org>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is free software; you can redistribute it and/or modify it
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering under the terms of the GNU Lesser General Public License as published by
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (at your option) any later version.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is distributed in the hope that it will be useful, but
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Lesser General Public License for more details.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering You should have received a copy of the GNU Lesser General Public License
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering***/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <stdio.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <errno.h>
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering#include <string.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <inttypes.h>
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering#include <ctype.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <stdlib.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <fnmatch.h>
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering#include <getopt.h>
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering#include "udev.h"
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poetteringstatic struct udev_hwdb *hwdb;
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering
eef46c372f64f40dd75415b2c504c73138719c8dLennart Poetteringint udev_builtin_hwdb_lookup(struct udev_device *dev,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen const char *prefix, const char *modalias,
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering const char *filter, bool test) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen struct udev_list_entry *list;
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering struct udev_list_entry *entry;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int n = 0;
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering if (!hwdb)
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering return -ENOENT;
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering if (prefix) {
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering _cleanup_free_ const char *lookup;
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering lookup = strjoin(prefix, modalias, NULL);
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering if (!lookup)
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering return -ENOMEM;
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering list = udev_hwdb_get_properties_list_entry(hwdb, lookup, 0);
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering } else
0b452006de98294d1690f045f6ea2f7f6630ec3bRonny Chevalier list = udev_hwdb_get_properties_list_entry(hwdb, modalias, 0);
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering
24882e06c135584f16f31ba8a00fecde8b7f6fadLennart Poettering udev_list_entry_foreach(entry, list) {
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering if (filter && fnmatch(filter, udev_list_entry_get_name(entry), FNM_NOESCAPE) != 0)
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering continue;
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering if (udev_builtin_add_property(dev, test,
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering udev_list_entry_get_name(entry),
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering udev_list_entry_get_value(entry)) < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -ENOMEM;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering n++;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return n;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic const char *modalias_usb(struct udev_device *dev, char *s, size_t size) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const char *v, *p;
d21ed1ead18d16d35c30299a69d3366847f8a039Lennart Poettering int vn, pn;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering v = udev_device_get_sysattr_value(dev, "idVendor");
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (!v)
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poettering return NULL;
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering p = udev_device_get_sysattr_value(dev, "idProduct");
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering if (!p)
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering return NULL;
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering vn = strtol(v, NULL, 16);
6e18cc9fa078d2a967251017ddb5baefb104b720Lennart Poettering if (vn <= 0)
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering return NULL;
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering pn = strtol(p, NULL, 16);
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering if (pn <= 0)
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering return NULL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering snprintf(s, size, "usb:v%04Xp%04X*", vn, pn);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return s;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int udev_builtin_hwdb_search(struct udev_device *dev, struct udev_device *srcdev,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const char *subsystem, const char *prefix,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const char *filter, bool test) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering struct udev_device *d;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering char s[16];
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering int n = 0;
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering for (d = srcdev; d; d = udev_device_get_parent(d)) {
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering const char *dsubsys;
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering const char *modalias = NULL;
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering dsubsys = udev_device_get_subsystem(d);
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering if (!dsubsys)
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering continue;
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering /* look only at devices of a specific subsystem */
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering if (subsystem && !streq(dsubsys, subsystem))
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering continue;
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering /* the usb_device does not have a modalias, compose one */
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering if (streq(dsubsys, "usb"))
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering modalias = modalias_usb(d, s, sizeof(s));
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering if (!modalias)
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering modalias = udev_device_get_property_value(d, "MODALIAS");
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering if (!modalias)
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering continue;
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering n = udev_builtin_hwdb_lookup(dev, prefix, modalias, filter, test);
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering if (n > 0)
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering break;
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering }
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering return n;
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering}
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poetteringstatic int builtin_hwdb(struct udev_device *dev, int argc, char *argv[], bool test) {
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering static const struct option options[] = {
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering { "filter", required_argument, NULL, 'f' },
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering { "device", required_argument, NULL, 'd' },
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering { "subsystem", required_argument, NULL, 's' },
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen { "lookup-prefix", required_argument, NULL, 'p' },
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering {}
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering };
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen const char *filter = NULL;
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering const char *device = NULL;
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering const char *subsystem = NULL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const char *prefix = NULL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering struct udev_device *srcdev;
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering if (!hwdb)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return EXIT_FAILURE;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen for (;;) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen int option;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen option = getopt_long(argc, argv, "f:d:s:p:", options, NULL);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (option == -1)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen break;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen switch (option) {
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering case 'f':
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen filter = optarg;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen break;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering case 'd':
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering device = optarg;
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering break;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering case 's':
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering subsystem = optarg;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen break;
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering case 'p':
fee6d013d859bc66f5c993530898fece53fab06dLennart Poettering prefix = optarg;
fee6d013d859bc66f5c993530898fece53fab06dLennart Poettering break;
fee6d013d859bc66f5c993530898fece53fab06dLennart Poettering }
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering }
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* query a specific key given as argument */
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering if (argv[optind]) {
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering if (udev_builtin_hwdb_lookup(dev, prefix, argv[optind], filter, test) > 0)
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering return EXIT_SUCCESS;
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering return EXIT_FAILURE;
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering }
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering /* read data from another device than the device we will store the data */
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering if (device) {
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering srcdev = udev_device_new_from_device_id(udev_device_get_udev(dev), device);
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering if (!srcdev)
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering return EXIT_FAILURE;
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering } else
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering srcdev = dev;
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering if (udev_builtin_hwdb_search(dev, srcdev, subsystem, prefix, filter, test) > 0)
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering return EXIT_SUCCESS;
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering return EXIT_FAILURE;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering/* called at udev startup and reload */
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersenstatic int builtin_hwdb_init(struct udev *udev)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen{
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (hwdb)
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering hwdb = udev_hwdb_new(udev);
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering if (!hwdb)
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering return -ENOMEM;
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering return 0;
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering}
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering/* called on udev shutdown and reload request */
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poetteringstatic void builtin_hwdb_exit(struct udev *udev)
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering{
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering hwdb = udev_hwdb_unref(hwdb);
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering}
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering/* called every couple of seconds during event activity; 'true' if config has changed */
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poetteringstatic bool builtin_hwdb_validate(struct udev *udev)
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering{
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen return udev_hwdb_validate(hwdb);
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringconst struct udev_builtin udev_builtin_hwdb = {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering .name = "hwdb",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering .cmd = builtin_hwdb,
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering .init = builtin_hwdb_init,
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering .exit = builtin_hwdb_exit,
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering .validate = builtin_hwdb_validate,
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering .help = "hardware database",
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering};
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering