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