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
36 static bool verbose = false;
37
38 static void
log_handler(struct libinput * this_is_null,enum libinput_log_priority priority,const char * format,va_list args)39 log_handler(struct libinput *this_is_null,
40 enum libinput_log_priority priority,
41 const char *format,
42 va_list args)
43 {
44 FILE *out = stdout;
45 enum quirks_log_priorities p = (enum quirks_log_priorities)priority;
46 char buf[256] = {0};
47 const char *prefix = "";
48
49 switch (p) {
50 case QLOG_NOISE:
51 case QLOG_DEBUG:
52 if (!verbose)
53 return;
54 prefix = "quirks debug";
55 break;
56 case QLOG_INFO:
57 prefix = "quirks info";
58 break;
59 case QLOG_ERROR:
60 out = stderr;
61 prefix = "quirks error";
62 break;
63 case QLOG_PARSER_ERROR:
64 out = stderr;
65 prefix = "quirks parser error";
66 break;
67 }
68
69 snprintf(buf, sizeof(buf), "%s: %s", prefix, format);
70 vfprintf(out, buf, args);
71 }
72
73 static void
usage(void)74 usage(void)
75 {
76 printf("Usage:\n"
77 " libinput quirks list [--data-dir /path/to/quirks/dir] /dev/input/event0\n"
78 " Print the quirks for the given device\n"
79 "\n"
80 " libinput quirks validate [--data-dir /path/to/quirks/dir]\n"
81 " Validate the database\n");
82 }
83
84 static void
simple_printf(void * userdata,const char * val)85 simple_printf(void *userdata, const char *val)
86 {
87 printf("%s\n", val);
88 }
89
90 int
main(int argc,char ** argv)91 main(int argc, char **argv)
92 {
93 struct udev *udev = NULL;
94 struct udev_device *device = NULL;
95 const char *path;
96 const char *data_path = NULL,
97 *override_file = NULL;
98 int rc = 1;
99 struct quirks_context *quirks;
100 bool validate = false;
101
102 while (1) {
103 int c;
104 int option_index = 0;
105 enum {
106 OPT_VERBOSE,
107 OPT_DATADIR,
108 };
109 static struct option opts[] = {
110 { "help", no_argument, 0, 'h' },
111 { "verbose", no_argument, 0, OPT_VERBOSE },
112 { "data-dir", required_argument, 0, OPT_DATADIR },
113 { 0, 0, 0, 0}
114 };
115
116 c = getopt_long(argc, argv, "h", opts, &option_index);
117 if (c == -1)
118 break;
119
120 switch(c) {
121 case '?':
122 exit(1);
123 break;
124 case 'h':
125 usage();
126 exit(0);
127 break;
128 case OPT_VERBOSE:
129 verbose = true;
130 break;
131 case OPT_DATADIR:
132 data_path = optarg;
133 break;
134 default:
135 usage();
136 return 1;
137 }
138 }
139
140 if (optind >= argc) {
141 usage();
142 return 1;
143 }
144
145 if (streq(argv[optind], "list")) {
146 optind++;
147 if (optind >= argc) {
148 usage();
149 return 1;
150 }
151 } else if (streq(argv[optind], "validate")) {
152 optind++;
153 if (optind < argc) {
154 usage();
155 return 1;
156 }
157 validate = true;
158 } else {
159 fprintf(stderr, "Unnkown action '%s'\n", argv[optind]);
160 return 1;
161 }
162
163 /* Overriding the data dir means no custom override file */
164 if (!data_path) {
165 char *builddir = builddir_lookup();
166 if (builddir) {
167 data_path = LIBINPUT_QUIRKS_SRCDIR;
168 free(builddir);
169 } else {
170 data_path = LIBINPUT_QUIRKS_DIR;
171 override_file = LIBINPUT_QUIRKS_OVERRIDE_FILE;
172 }
173 }
174
175 quirks = quirks_init_subsystem(data_path,
176 override_file,
177 log_handler,
178 NULL,
179 QLOG_CUSTOM_LOG_PRIORITIES);
180 if (!quirks) {
181 fprintf(stderr,
182 "Failed to initialize the device quirks. "
183 "Please see the above errors "
184 "and/or re-run with --verbose for more details\n");
185 return 1;
186 }
187
188 if (validate) {
189 rc = 0;
190 goto out;
191 }
192
193 udev = udev_new();
194 path = argv[optind];
195 if (strneq(path, "/sys/", 5)) {
196 device = udev_device_new_from_syspath(udev, path);
197 } else {
198 struct stat st;
199 if (stat(path, &st) < 0) {
200 fprintf(stderr, "Error: %s: %m\n", path);
201 goto out;
202 }
203
204 device = udev_device_new_from_devnum(udev, 'c', st.st_rdev);
205 }
206 if (device) {
207 tools_list_device_quirks(quirks, device, simple_printf, NULL);
208 rc = 0;
209 } else {
210 usage();
211 rc = 1;
212 }
213
214 udev_device_unref(device);
215 out:
216 udev_unref(udev);
217
218 quirks_context_unref(quirks);
219
220 return rc;
221 }
222