udev-builtin-hwdb.c revision 6824690f140f45064157d220a24b9afbeb1d093f
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>
8bdbb8d9cbe1d35708385573d70984ab4533812dLennart Poettering#include <string.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <inttypes.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <ctype.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <stdlib.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <fnmatch.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <getopt.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering#include "udev.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersenstatic struct udev_hwdb *hwdb;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringint udev_builtin_hwdb_lookup(struct udev_device *dev,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const char *modalias, const char *filter, bool test) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering struct udev_list_entry *entry;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen int n = 0;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!hwdb)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -ENOENT;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, modalias, 0)) {
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering if (filter && fnmatch(filter, udev_list_entry_get_name(entry), FNM_NOESCAPE) != 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering continue;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (udev_builtin_add_property(dev, test,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering udev_list_entry_get_name(entry),
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering udev_list_entry_get_value(entry)) < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -ENOMEM;
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen n++;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return n;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
d21ed1ead18d16d35c30299a69d3366847f8a039Lennart 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);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (vn <= 0)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen return NULL;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen pn = strtol(p, NULL, 16);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen 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
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersenstatic int udev_builtin_hwdb_search(struct udev_device *dev, struct udev_device *srcdev,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen const char *subsystem, const char *filter, bool test) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen struct udev_device *d;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen char s[16];
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen int n = 0;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen for (d = srcdev; d; d = udev_device_get_parent(d)) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen const char *dsubsys;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen const char *modalias = NULL;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen dsubsys = udev_device_get_subsystem(d);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!dsubsys)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering continue;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen /* look only at devices of a specific subsystem */
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen if (subsystem && !streq(dsubsys, subsystem))
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering continue;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen /* the usb_device does not have a modalias, compose one */
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering if (streq(dsubsys, "usb"))
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering modalias = modalias_usb(d, s, sizeof(s));
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!modalias)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering modalias = udev_device_get_property_value(d, "MODALIAS");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!modalias)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen continue;
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen n = udev_builtin_hwdb_lookup(dev, modalias, filter, test);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (n > 0)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen break;
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen return n;
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int builtin_hwdb(struct udev_device *dev, int argc, char *argv[], bool test) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering static const struct option options[] = {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering { "filter", required_argument, NULL, 'f' },
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering { "device", required_argument, NULL, 'd' },
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen { "subsystem", required_argument, NULL, 's' },
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen {}
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering };
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering const char *filter = NULL;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering const char *device = NULL;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering const char *subsystem = NULL;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering struct udev_device *srcdev;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (!hwdb)
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return EXIT_FAILURE;
d21ed1ead18d16d35c30299a69d3366847f8a039Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering for (;;) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering int option;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering option = getopt_long(argc, argv, "s", options, NULL);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (option == -1)
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering break;
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering switch (option) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering case 'f':
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering filter = optarg;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering break;
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering case 'd':
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen device = optarg;
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering break;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen case 's':
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering subsystem = optarg;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering break;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering }
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering }
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering /* query a specific key given as argument */
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (argv[optind]) {
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering if (udev_builtin_hwdb_lookup(dev, argv[optind], filter, test) > 0)
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering return EXIT_SUCCESS;
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering return EXIT_FAILURE;
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering }
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering
9d12709626bccc0cae677a7035f62efe6aabb4abLennart 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 } else
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering srcdev = dev;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (udev_builtin_hwdb_search(dev, srcdev, subsystem, filter, test) < 0)
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return EXIT_FAILURE;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return EXIT_SUCCESS;
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering}
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering/* called at udev startup and reload */
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poetteringstatic int builtin_hwdb_init(struct udev *udev)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering{
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers if (hwdb)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers hwdb = udev_hwdb_new(udev);
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers if (!hwdb)
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering return -ENOMEM;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/* called on udev shutdown and reload request */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic void builtin_hwdb_exit(struct udev *udev)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen{
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering hwdb = udev_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{
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return udev_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