udev-builtin-hwdb.c revision e448a1c3a3eac4d73261bf8648110fc9f7aae806
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 <stdlib.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <fnmatch.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <getopt.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "udev.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "sd-hwdb.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "hwdb-util.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "udev-util.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic sd_hwdb *hwdb;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringint udev_builtin_hwdb_lookup(struct udev_device *dev,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const char *prefix, const char *modalias,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const char *filter, bool test) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering _cleanup_free_ const char *lookup = NULL;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering const char *key, *value;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int n = 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!hwdb)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -ENOENT;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (prefix) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering lookup = strjoin(prefix, modalias, NULL);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!lookup)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -ENOMEM;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering modalias = lookup;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering SD_HWDB_FOREACH_PROPERTY(hwdb, modalias, key, value) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (filter && fnmatch(filter, key, FNM_NOESCAPE) != 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering continue;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (udev_builtin_add_property(dev, test, key, value) < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -ENOMEM;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering n++;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return n;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic const char *modalias_usb(struct udev_device *dev, char *s, size_t size) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const char *v, *p;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int vn, pn;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering v = udev_device_get_sysattr_value(dev, "idVendor");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!v)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return NULL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering p = udev_device_get_sysattr_value(dev, "idProduct");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!p)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return NULL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering vn = strtol(v, NULL, 16);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (vn <= 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return NULL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering pn = strtol(p, NULL, 16);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (pn <= 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart 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];
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering bool last = false;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int r = 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(dev);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!srcdev)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering srcdev = dev;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (d = srcdev; d && !last; d = udev_device_get_parent(d)) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const char *dsubsys;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const char *modalias = NULL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering dsubsys = udev_device_get_subsystem(d);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!dsubsys)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering continue;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* look only at devices of a specific subsystem */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (subsystem && !streq(dsubsys, subsystem))
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering continue;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering modalias = udev_device_get_property_value(d, "MODALIAS");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (streq(dsubsys, "usb") && streq_ptr(udev_device_get_devtype(d), "usb_device")) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* if the usb_device does not have a modalias, compose one */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!modalias)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering modalias = modalias_usb(d, s, sizeof(s));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* avoid looking at any parent device, they are usually just a USB hub */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering last = true;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!modalias)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering continue;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = udev_builtin_hwdb_lookup(dev, prefix, modalias, filter, test);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r > 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering break;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poetteringstatic int builtin_hwdb(struct udev_device *dev, int argc, char *argv[], bool test) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering static const struct option options[] = {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering { "filter", required_argument, NULL, 'f' },
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering { "device", required_argument, NULL, 'd' },
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering { "subsystem", required_argument, NULL, 's' },
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering { "lookup-prefix", required_argument, NULL, 'p' },
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering {}
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering };
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering const char *filter = NULL;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering const char *device = NULL;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering const char *subsystem = NULL;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering const char *prefix = NULL;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering _cleanup_udev_device_unref_ struct udev_device *srcdev = NULL;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (!hwdb)
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return EXIT_FAILURE;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering for (;;) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering int option;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering option = getopt_long(argc, argv, "f:d:s:p:", options, NULL);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (option == -1)
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering break;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering switch (option) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering case 'f':
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering filter = optarg;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering break;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering case 'd':
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering device = optarg;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering break;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering case 's':
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering subsystem = optarg;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering break;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering case 'p':
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering prefix = optarg;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering break;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering }
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering }
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering /* query a specific key given as argument */
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (argv[optind]) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (udev_builtin_hwdb_lookup(dev, prefix, argv[optind], filter, test) > 0)
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return EXIT_SUCCESS;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return EXIT_FAILURE;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering }
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering /* read data from another device than the device we will store the data */
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (device) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering srcdev = udev_device_new_from_device_id(udev_device_get_udev(dev), device);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (!srcdev)
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return EXIT_FAILURE;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering }
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (udev_builtin_hwdb_search(dev, srcdev, subsystem, prefix, filter, test) > 0)
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return EXIT_SUCCESS;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return EXIT_FAILURE;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering}
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering/* called at udev startup and reload */
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poetteringstatic int builtin_hwdb_init(struct udev *udev) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering int r;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (hwdb)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = sd_hwdb_new(&hwdb);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/* called on udev shutdown and reload request */
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poetteringstatic void builtin_hwdb_exit(struct udev *udev) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering hwdb = sd_hwdb_unref(hwdb);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/* called every couple of seconds during event activity; 'true' if config has changed */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic bool builtin_hwdb_validate(struct udev *udev) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return hwdb_validate(hwdb);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringconst struct udev_builtin udev_builtin_hwdb = {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering .name = "hwdb",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering .cmd = builtin_hwdb,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering .init = builtin_hwdb_init,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering .exit = builtin_hwdb_exit,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering .validate = builtin_hwdb_validate,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering .help = "Hardware database",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering};
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering