• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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