udev-builtin-hwdb.c revision 33c770b174ec77d7da6e7e830e0bca9f74d54367
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers/***
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers This file is part of systemd.
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers Copyright 2012 Kay Sievers <kay@vrfy.org>
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers systemd is free software; you can redistribute it and/or modify it
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers under the terms of the GNU Lesser General Public License as published by
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers the Free Software Foundation; either version 2.1 of the License, or
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers (at your option) any later version.
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers systemd is distributed in the hope that it will be useful, but
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers WITHOUT ANY WARRANTY; without even the implied warranty of
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers Lesser General Public License for more details.
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers You should have received a copy of the GNU Lesser General Public License
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers along with systemd; If not, see <http://www.gnu.org/licenses/>.
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers***/
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers#include <stdio.h>
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers#include <errno.h>
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include <string.h>
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers#include <inttypes.h>
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include <ctype.h>
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers#include <stdlib.h>
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers#include <getopt.h>
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include "udev.h"
cf0fbc49e67b55f8d346fc94de28c90113505297Thomas Hindoe Paaboel Andersen
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poetteringstatic struct udev_hwdb *hwdb;
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poetteringint udev_builtin_hwdb_lookup(struct udev_device *dev, const char *modalias, bool test) {
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering struct udev_list_entry *entry;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers int n = 0;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers if (!hwdb)
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers return -ENOENT;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, modalias, 0)) {
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers if (udev_builtin_add_property(dev, test,
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers udev_list_entry_get_name(entry),
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers udev_list_entry_get_value(entry)) < 0)
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers return -ENOMEM;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers n++;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers }
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers return n;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers}
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sieversstatic const char *modalias_usb(struct udev_device *dev, char *s, size_t size) {
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers const char *v, *p;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers int vn, pn;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers v = udev_device_get_sysattr_value(dev, "idVendor");
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers if (!v)
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers return NULL;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers p = udev_device_get_sysattr_value(dev, "idProduct");
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers if (!p)
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers return NULL;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers vn = strtol(v, NULL, 16);
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers if (vn <= 0)
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers return NULL;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers pn = strtol(p, NULL, 16);
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers if (pn <= 0)
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers return NULL;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers snprintf(s, size, "usb:v%04Xp%04X*", vn, pn);
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers return s;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers}
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sieversstatic int udev_builtin_hwdb_search(struct udev_device *dev, const char *subsystem, bool test) {
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers struct udev_device *d;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers char s[16];
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers int n = 0;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers for (d = dev; d; d = udev_device_get_parent(d)) {
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers const char *dsubsys;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers const char *modalias = NULL;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers dsubsys = udev_device_get_subsystem(d);
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers if (!dsubsys)
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers continue;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers /* look only at devices of a specific subsystem */
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers if (subsystem && !streq(dsubsys, subsystem))
2c64a8d0caf84254e38f2e76528f2034d37da520Lennart Poettering continue;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers
39883f622f392d8579f4428fc5a789a102efbb10Lennart Poettering /* the usb_device does not have a modalias, compose one */
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers if (streq(dsubsys, "usb"))
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers modalias = modalias_usb(dev, s, sizeof(s));
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers if (!modalias)
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers modalias = udev_device_get_property_value(d, "MODALIAS");
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers if (!modalias)
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers continue;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers n = udev_builtin_hwdb_lookup(dev, modalias, test);
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers if (n > 0)
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers break;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers }
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers return n;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers}
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sieversstatic int builtin_hwdb(struct udev_device *dev, int argc, char *argv[], bool test) {
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers static const struct option options[] = {
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers { "subsystem", required_argument, NULL, 's' },
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers {}
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers };
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers const char *subsystem = NULL;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers if (!hwdb)
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers return EXIT_FAILURE;
f576cd2092bc40f9998415cdc3caf10035d4743aPavel Holica
f576cd2092bc40f9998415cdc3caf10035d4743aPavel Holica for (;;) {
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers int option;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers option = getopt_long(argc, argv, "s", options, NULL);
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers if (option == -1)
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers break;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers switch (option) {
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers case 's':
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers subsystem = optarg;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers break;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers }
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers }
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers if (udev_builtin_hwdb_search(dev, subsystem, test) < 0)
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers return EXIT_FAILURE;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers return EXIT_SUCCESS;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers}
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers/* called at udev startup and reload */
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sieversstatic int builtin_hwdb_init(struct udev *udev)
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers{
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers if (hwdb)
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers return 0;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers hwdb = udev_hwdb_new(udev);
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers if (!hwdb)
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers return -ENOMEM;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers return 0;
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers}
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers/* called on udev shutdown and reload request */
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sieversstatic void builtin_hwdb_exit(struct udev *udev)
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers{
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers hwdb = udev_hwdb_unref(hwdb);
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers}
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers/* called every couple of seconds during event activity; 'true' if config has changed */
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sieversstatic bool builtin_hwdb_validate(struct udev *udev)
6c7980093c4e39d07bf06484f96f489e236c7c29Kay Sievers{
6c7980093c4e39d07bf06484f96f489e236c7c29Kay Sievers return udev_hwdb_validate(hwdb);
6c7980093c4e39d07bf06484f96f489e236c7c29Kay Sievers}
6c7980093c4e39d07bf06484f96f489e236c7c29Kay Sievers
6c7980093c4e39d07bf06484f96f489e236c7c29Kay Sieversconst struct udev_builtin udev_builtin_hwdb = {
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers .name = "hwdb",
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers .cmd = builtin_hwdb,
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers .init = builtin_hwdb_init,
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers .exit = builtin_hwdb_exit,
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers .validate = builtin_hwdb_validate,
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers .help = "hardware database",
c51d84dc09476d9c06b8aac726220bf3c7d62e8dKay Sievers};