1a46c0ec8Sopenharmony_ci/* 2a46c0ec8Sopenharmony_ci * Copyright © 2018 Red Hat, Inc. 3a46c0ec8Sopenharmony_ci * 4a46c0ec8Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5a46c0ec8Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6a46c0ec8Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7a46c0ec8Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8a46c0ec8Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9a46c0ec8Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10a46c0ec8Sopenharmony_ci * 11a46c0ec8Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12a46c0ec8Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13a46c0ec8Sopenharmony_ci * Software. 14a46c0ec8Sopenharmony_ci * 15a46c0ec8Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16a46c0ec8Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17a46c0ec8Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18a46c0ec8Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19a46c0ec8Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20a46c0ec8Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21a46c0ec8Sopenharmony_ci * DEALINGS IN THE SOFTWARE. 22a46c0ec8Sopenharmony_ci */ 23a46c0ec8Sopenharmony_ci 24a46c0ec8Sopenharmony_ci#include "config.h" 25a46c0ec8Sopenharmony_ci 26a46c0ec8Sopenharmony_ci#include <stdio.h> 27a46c0ec8Sopenharmony_ci#include <stdlib.h> 28a46c0ec8Sopenharmony_ci#include <errno.h> 29a46c0ec8Sopenharmony_ci#include <getopt.h> 30a46c0ec8Sopenharmony_ci#include <sys/stat.h> 31a46c0ec8Sopenharmony_ci 32a46c0ec8Sopenharmony_ci#include "quirks.h" 33a46c0ec8Sopenharmony_ci#include "shared.h" 34a46c0ec8Sopenharmony_ci#include "builddir.h" 35a46c0ec8Sopenharmony_ci 36a46c0ec8Sopenharmony_cistatic bool verbose = false; 37a46c0ec8Sopenharmony_ci 38a46c0ec8Sopenharmony_ciLIBINPUT_ATTRIBUTE_PRINTF(3, 0) 39a46c0ec8Sopenharmony_cistatic void 40a46c0ec8Sopenharmony_cilog_handler(struct libinput *this_is_null, 41a46c0ec8Sopenharmony_ci enum libinput_log_priority priority, 42a46c0ec8Sopenharmony_ci const char *format, 43a46c0ec8Sopenharmony_ci va_list args) 44a46c0ec8Sopenharmony_ci{ 45a46c0ec8Sopenharmony_ci FILE *out = stdout; 46a46c0ec8Sopenharmony_ci enum quirks_log_priorities p = (enum quirks_log_priorities)priority; 47a46c0ec8Sopenharmony_ci char buf[256] = {0}; 48a46c0ec8Sopenharmony_ci const char *prefix = NULL; 49a46c0ec8Sopenharmony_ci 50a46c0ec8Sopenharmony_ci switch (p) { 51a46c0ec8Sopenharmony_ci case QLOG_NOISE: 52a46c0ec8Sopenharmony_ci case QLOG_DEBUG: 53a46c0ec8Sopenharmony_ci if (!verbose) 54a46c0ec8Sopenharmony_ci return; 55a46c0ec8Sopenharmony_ci prefix = "quirks debug"; 56a46c0ec8Sopenharmony_ci break; 57a46c0ec8Sopenharmony_ci case QLOG_INFO: 58a46c0ec8Sopenharmony_ci prefix = "quirks info"; 59a46c0ec8Sopenharmony_ci break; 60a46c0ec8Sopenharmony_ci case QLOG_ERROR: 61a46c0ec8Sopenharmony_ci out = stderr; 62a46c0ec8Sopenharmony_ci prefix = "quirks error"; 63a46c0ec8Sopenharmony_ci break; 64a46c0ec8Sopenharmony_ci case QLOG_PARSER_ERROR: 65a46c0ec8Sopenharmony_ci out = stderr; 66a46c0ec8Sopenharmony_ci prefix = "quirks parser error"; 67a46c0ec8Sopenharmony_ci break; 68a46c0ec8Sopenharmony_ci } 69a46c0ec8Sopenharmony_ci 70a46c0ec8Sopenharmony_ci snprintf(buf, sizeof(buf), "%s: %s", prefix, format); 71a46c0ec8Sopenharmony_ci#pragma GCC diagnostic push 72a46c0ec8Sopenharmony_ci#pragma GCC diagnostic ignored "-Wformat-nonliteral" 73a46c0ec8Sopenharmony_ci vfprintf(out, buf, args); 74a46c0ec8Sopenharmony_ci#pragma GCC diagnostic pop 75a46c0ec8Sopenharmony_ci} 76a46c0ec8Sopenharmony_ci 77a46c0ec8Sopenharmony_cistatic void 78a46c0ec8Sopenharmony_ciusage(void) 79a46c0ec8Sopenharmony_ci{ 80a46c0ec8Sopenharmony_ci printf("Usage:\n" 81a46c0ec8Sopenharmony_ci " libinput quirks list [--data-dir /path/to/quirks/dir] /dev/input/event0\n" 82a46c0ec8Sopenharmony_ci " Print the quirks for the given device\n" 83a46c0ec8Sopenharmony_ci "\n" 84a46c0ec8Sopenharmony_ci " libinput quirks validate [--data-dir /path/to/quirks/dir]\n" 85a46c0ec8Sopenharmony_ci " Validate the database\n"); 86a46c0ec8Sopenharmony_ci} 87a46c0ec8Sopenharmony_ci 88a46c0ec8Sopenharmony_cistatic void 89a46c0ec8Sopenharmony_cisimple_printf(void *userdata, const char *val) 90a46c0ec8Sopenharmony_ci{ 91a46c0ec8Sopenharmony_ci printf("%s\n", val); 92a46c0ec8Sopenharmony_ci} 93a46c0ec8Sopenharmony_ci 94a46c0ec8Sopenharmony_ciint 95a46c0ec8Sopenharmony_cimain(int argc, char **argv) 96a46c0ec8Sopenharmony_ci{ 97a46c0ec8Sopenharmony_ci struct udev *udev = NULL; 98a46c0ec8Sopenharmony_ci struct udev_device *device = NULL; 99a46c0ec8Sopenharmony_ci const char *path; 100a46c0ec8Sopenharmony_ci const char *data_path = NULL, 101a46c0ec8Sopenharmony_ci *override_file = NULL; 102a46c0ec8Sopenharmony_ci int rc = 1; 103a46c0ec8Sopenharmony_ci struct quirks_context *quirks; 104a46c0ec8Sopenharmony_ci bool validate = false; 105a46c0ec8Sopenharmony_ci 106a46c0ec8Sopenharmony_ci while (1) { 107a46c0ec8Sopenharmony_ci int c; 108a46c0ec8Sopenharmony_ci int option_index = 0; 109a46c0ec8Sopenharmony_ci enum { 110a46c0ec8Sopenharmony_ci OPT_VERBOSE, 111a46c0ec8Sopenharmony_ci OPT_DATADIR, 112a46c0ec8Sopenharmony_ci }; 113a46c0ec8Sopenharmony_ci static struct option opts[] = { 114a46c0ec8Sopenharmony_ci { "help", no_argument, 0, 'h' }, 115a46c0ec8Sopenharmony_ci { "verbose", no_argument, 0, OPT_VERBOSE }, 116a46c0ec8Sopenharmony_ci { "data-dir", required_argument, 0, OPT_DATADIR }, 117a46c0ec8Sopenharmony_ci { 0, 0, 0, 0} 118a46c0ec8Sopenharmony_ci }; 119a46c0ec8Sopenharmony_ci 120a46c0ec8Sopenharmony_ci c = getopt_long(argc, argv, "h", opts, &option_index); 121a46c0ec8Sopenharmony_ci if (c == -1) 122a46c0ec8Sopenharmony_ci break; 123a46c0ec8Sopenharmony_ci 124a46c0ec8Sopenharmony_ci switch(c) { 125a46c0ec8Sopenharmony_ci case '?': 126a46c0ec8Sopenharmony_ci exit(1); 127a46c0ec8Sopenharmony_ci break; 128a46c0ec8Sopenharmony_ci case 'h': 129a46c0ec8Sopenharmony_ci usage(); 130a46c0ec8Sopenharmony_ci exit(0); 131a46c0ec8Sopenharmony_ci break; 132a46c0ec8Sopenharmony_ci case OPT_VERBOSE: 133a46c0ec8Sopenharmony_ci verbose = true; 134a46c0ec8Sopenharmony_ci break; 135a46c0ec8Sopenharmony_ci case OPT_DATADIR: 136a46c0ec8Sopenharmony_ci data_path = optarg; 137a46c0ec8Sopenharmony_ci break; 138a46c0ec8Sopenharmony_ci default: 139a46c0ec8Sopenharmony_ci usage(); 140a46c0ec8Sopenharmony_ci return 1; 141a46c0ec8Sopenharmony_ci } 142a46c0ec8Sopenharmony_ci } 143a46c0ec8Sopenharmony_ci 144a46c0ec8Sopenharmony_ci if (optind >= argc) { 145a46c0ec8Sopenharmony_ci usage(); 146a46c0ec8Sopenharmony_ci return 1; 147a46c0ec8Sopenharmony_ci } 148a46c0ec8Sopenharmony_ci 149a46c0ec8Sopenharmony_ci if (streq(argv[optind], "list")) { 150a46c0ec8Sopenharmony_ci optind++; 151a46c0ec8Sopenharmony_ci if (optind >= argc) { 152a46c0ec8Sopenharmony_ci usage(); 153a46c0ec8Sopenharmony_ci return 1; 154a46c0ec8Sopenharmony_ci } 155a46c0ec8Sopenharmony_ci } else if (streq(argv[optind], "validate")) { 156a46c0ec8Sopenharmony_ci optind++; 157a46c0ec8Sopenharmony_ci if (optind < argc) { 158a46c0ec8Sopenharmony_ci usage(); 159a46c0ec8Sopenharmony_ci return 1; 160a46c0ec8Sopenharmony_ci } 161a46c0ec8Sopenharmony_ci validate = true; 162a46c0ec8Sopenharmony_ci } else { 163a46c0ec8Sopenharmony_ci fprintf(stderr, "Unnkown action '%s'\n", argv[optind]); 164a46c0ec8Sopenharmony_ci return 1; 165a46c0ec8Sopenharmony_ci } 166a46c0ec8Sopenharmony_ci 167a46c0ec8Sopenharmony_ci /* Overriding the data dir means no custom override file */ 168a46c0ec8Sopenharmony_ci if (!data_path) { 169a46c0ec8Sopenharmony_ci char *builddir = builddir_lookup(); 170a46c0ec8Sopenharmony_ci if (builddir) { 171a46c0ec8Sopenharmony_ci data_path = LIBINPUT_QUIRKS_SRCDIR; 172a46c0ec8Sopenharmony_ci free(builddir); 173a46c0ec8Sopenharmony_ci } else { 174a46c0ec8Sopenharmony_ci data_path = LIBINPUT_QUIRKS_DIR; 175a46c0ec8Sopenharmony_ci override_file = LIBINPUT_QUIRKS_OVERRIDE_FILE; 176a46c0ec8Sopenharmony_ci } 177a46c0ec8Sopenharmony_ci } 178a46c0ec8Sopenharmony_ci 179a46c0ec8Sopenharmony_ci quirks = quirks_init_subsystem(data_path, 180a46c0ec8Sopenharmony_ci override_file, 181a46c0ec8Sopenharmony_ci log_handler, 182a46c0ec8Sopenharmony_ci NULL, 183a46c0ec8Sopenharmony_ci QLOG_CUSTOM_LOG_PRIORITIES); 184a46c0ec8Sopenharmony_ci if (!quirks) { 185a46c0ec8Sopenharmony_ci fprintf(stderr, 186a46c0ec8Sopenharmony_ci "Failed to initialize the device quirks. " 187a46c0ec8Sopenharmony_ci "Please see the above errors " 188a46c0ec8Sopenharmony_ci "and/or re-run with --verbose for more details\n"); 189a46c0ec8Sopenharmony_ci return 1; 190a46c0ec8Sopenharmony_ci } 191a46c0ec8Sopenharmony_ci 192a46c0ec8Sopenharmony_ci if (validate) { 193a46c0ec8Sopenharmony_ci rc = 0; 194a46c0ec8Sopenharmony_ci goto out; 195a46c0ec8Sopenharmony_ci } 196a46c0ec8Sopenharmony_ci 197a46c0ec8Sopenharmony_ci udev = udev_new(); 198a46c0ec8Sopenharmony_ci if (!udev) 199a46c0ec8Sopenharmony_ci goto out; 200a46c0ec8Sopenharmony_ci 201a46c0ec8Sopenharmony_ci path = argv[optind]; 202a46c0ec8Sopenharmony_ci if (strneq(path, "/sys/", 5)) { 203a46c0ec8Sopenharmony_ci device = udev_device_new_from_syspath(udev, path); 204a46c0ec8Sopenharmony_ci } else { 205a46c0ec8Sopenharmony_ci struct stat st; 206a46c0ec8Sopenharmony_ci if (stat(path, &st) < 0) { 207a46c0ec8Sopenharmony_ci fprintf(stderr, "Error: %s: %m\n", path); 208a46c0ec8Sopenharmony_ci goto out; 209a46c0ec8Sopenharmony_ci } 210a46c0ec8Sopenharmony_ci 211a46c0ec8Sopenharmony_ci device = udev_device_new_from_devnum(udev, 'c', st.st_rdev); 212a46c0ec8Sopenharmony_ci } 213a46c0ec8Sopenharmony_ci if (device) { 214a46c0ec8Sopenharmony_ci tools_list_device_quirks(quirks, device, simple_printf, NULL); 215a46c0ec8Sopenharmony_ci rc = 0; 216a46c0ec8Sopenharmony_ci } else { 217a46c0ec8Sopenharmony_ci usage(); 218a46c0ec8Sopenharmony_ci rc = 1; 219a46c0ec8Sopenharmony_ci } 220a46c0ec8Sopenharmony_ci 221a46c0ec8Sopenharmony_ci udev_device_unref(device); 222a46c0ec8Sopenharmony_ciout: 223a46c0ec8Sopenharmony_ci udev_unref(udev); 224a46c0ec8Sopenharmony_ci 225a46c0ec8Sopenharmony_ci quirks_context_unref(quirks); 226a46c0ec8Sopenharmony_ci 227a46c0ec8Sopenharmony_ci return rc; 228a46c0ec8Sopenharmony_ci} 229