1 #include "tests.h"
2
3 #ifdef HAVE_LINUX_INPUT_H
4
5 # include <inttypes.h>
6 # include <stdio.h>
7 # include <stdlib.h>
8 # include <sys/ioctl.h>
9 # include <linux/input.h>
10 # include "print_fields.h"
11
12 static const char *errstr;
13
14 struct evdev_check {
15 unsigned long cmd;
16 const char *cmd_str;
17 void *arg_ptr;
18 void (*print_arg)(long rc, void *ptr, void *arg);
19 };
20
21 static long
invoke_test_syscall(unsigned long cmd,void * p)22 invoke_test_syscall(unsigned long cmd, void *p)
23 {
24 long rc = ioctl(-1, cmd, p);
25 errstr = sprintrc(rc);
26 static char inj_errstr[4096];
27
28 snprintf(inj_errstr, sizeof(inj_errstr), "%s (INJECTED)", errstr);
29 errstr = inj_errstr;
30 return rc;
31 }
32
33 static void
test_evdev(struct evdev_check * check,void * arg)34 test_evdev(struct evdev_check *check, void *arg)
35 {
36 long rc = invoke_test_syscall(check->cmd, check->arg_ptr);
37 printf("ioctl(-1, %s, ", check->cmd_str);
38 if (check->print_arg)
39 check->print_arg(rc, check->arg_ptr, arg);
40 else
41 printf("%p", check->arg_ptr);
42 printf(") = %s\n", errstr);
43 }
44
45 static void
print_input_absinfo(long rc,void * ptr,void * arg)46 print_input_absinfo(long rc, void *ptr, void *arg)
47 {
48 struct input_absinfo *absinfo = ptr;
49
50 if (rc < 0) {
51 printf("%p", absinfo);
52 return;
53 }
54 PRINT_FIELD_U("{", *absinfo, value);
55 PRINT_FIELD_U(", ", *absinfo, minimum);
56 # if VERBOSE
57 PRINT_FIELD_U(", ", *absinfo, maximum);
58 PRINT_FIELD_U(", ", *absinfo, fuzz);
59 PRINT_FIELD_U(", ", *absinfo, flat);
60 # ifdef HAVE_STRUCT_INPUT_ABSINFO_RESOLUTION
61 PRINT_FIELD_U(", ", *absinfo, resolution);
62 # endif
63 # else
64 printf(", ...");
65 # endif
66 printf("}");
67 }
68
69 static void
print_input_id(long rc,void * ptr,void * arg)70 print_input_id(long rc, void *ptr, void *arg)
71 {
72 struct input_id *id = ptr;
73
74 if (rc < 0) {
75 printf("%p", id);
76 return;
77 }
78 printf("{ID_BUS=%" PRIu16
79 ", ID_VENDOR=%" PRIu16
80 ", ID_PRODUCT=%" PRIu16
81 ", ID_VERSION=%" PRIu16 "}",
82 id->bustype, id->vendor, id->product, id->version);
83 }
84
85 # ifdef EVIOCGMTSLOTS
86 static void
print_mtslots(long rc,void * ptr,void * arg)87 print_mtslots(long rc, void *ptr, void *arg)
88 {
89 int *buffer = ptr;
90 const char **str = arg;
91 int num = atoi(*(str + 1));
92
93 if (rc < 0) {
94 printf("%p", buffer);
95 return;
96 }
97
98 printf("{code=%s", *str);
99 printf(", values=[");
100 for (unsigned int i = 1; i <= (unsigned) num; i++)
101 printf("%s%s", i > 1 ? ", " : "", *(str + i + 1));
102 printf("]}");
103 }
104 # endif
105
106 static void
print_getbit(long rc,void * ptr,void * arg)107 print_getbit(long rc, void *ptr, void *arg)
108 {
109 const char **str = arg;
110 int num = atoi(*str);
111
112 if (rc < 0) {
113 printf("%p", ptr);
114 return;
115 }
116
117 printf("[");
118 printf("%s", *(str + 1));
119 for (unsigned int i = 2; i <= (unsigned) num; i++) {
120 # if ! VERBOSE
121 if (i > 4) {
122 printf(", ...");
123 break;
124 }
125 # endif
126 printf(", ");
127 printf("%s", *(str + i));
128 }
129 printf("]");
130 }
131
132 int
main(int argc,char ** argv)133 main(int argc, char **argv)
134 {
135 unsigned long num_skip;
136 long inject_retval;
137 bool locked = false;
138
139 if (argc == 1)
140 return 0;
141
142 if (argc < 3)
143 error_msg_and_fail("Usage: %s NUM_SKIP INJECT_RETVAL", argv[0]);
144
145 num_skip = strtoul(argv[1], NULL, 0);
146 inject_retval = strtol(argv[2], NULL, 0);
147
148 if (inject_retval < 0)
149 error_msg_and_fail("Expected non-negative INJECT_RETVAL, "
150 "but got %ld", inject_retval);
151
152 for (unsigned int i = 0; i < num_skip; i++) {
153 long rc = ioctl(-1, EVIOCGID, NULL);
154 printf("ioctl(-1, EVIOCGID, NULL) = %s%s\n",
155 sprintrc(rc),
156 rc == inject_retval ? " (INJECTED)" : "");
157
158 if (rc != inject_retval)
159 continue;
160
161 locked = true;
162 break;
163 }
164
165 if (!locked)
166 error_msg_and_fail("Hasn't locked on ioctl(-1"
167 ", EVIOCGID, NULL) returning %lu",
168 inject_retval);
169
170 TAIL_ALLOC_OBJECT_CONST_PTR(struct input_id, id);
171 TAIL_ALLOC_OBJECT_CONST_PTR(struct input_absinfo, absinfo);
172 TAIL_ALLOC_OBJECT_CONST_PTR(int, bad_addr_slot);
173 # ifdef EVIOCGMTSLOTS
174 int mtslots[] = { ABS_MT_SLOT, 1, 3 };
175 /* we use the second element to indicate the number of values */
176 /* mtslots_str[1] is "2" so the number of values is 2 */
177 const char *mtslots_str[] = { "ABS_MT_SLOT", "2", "1", "3" };
178
179 /* invalid flag */
180 int invalid_mtslot[] = { -1, 1 };
181 char invalid_str[4096];
182 snprintf(invalid_str, sizeof(invalid_str), "%#x /* ABS_MT_??? */", invalid_mtslot[0]);
183 const char *invalid_mtslot_str[] = { invalid_str, "1", "1" };
184 # endif
185
186 /* set more than 4 bits */
187 unsigned long ev_more[] = { 1 << EV_ABS | 1 << EV_MSC | 1 << EV_LED | 1 << EV_SND | 1 << EV_PWR };
188 /* we use the first element to indicate the number of set bits */
189 /* ev_more_str[0] is "5" so the number of set bits is 5 */
190 const char *ev_more_str[] = { "5", "EV_ABS", "EV_MSC", "EV_LED", "EV_SND", "EV_PWR" };
191
192 /* set less than 4 bits */
193 unsigned long ev_less[] = { 1 << EV_ABS | 1 << EV_MSC | 1 << EV_LED };
194 const char *ev_less_str[] = { "3", "EV_ABS", "EV_MSC", "EV_LED" };
195
196 /* set zero bit */
197 unsigned long ev_zero[] = { 0x0 };
198 const char *ev_zero_str[] = { "0", " 0 " };
199
200 /* KEY_MAX is 0x2ff which is greater than retval * 8 */
201 unsigned long key[] = { 1 << KEY_1 | 1 << KEY_2, 0 };
202 const char *key_str[] = { "2", "KEY_1", "KEY_2" };
203
204 struct {
205 struct evdev_check check;
206 void *ptr;
207 } a[] = {
208 { { ARG_STR(EVIOCGID), id, print_input_id }, NULL },
209 { { ARG_STR(EVIOCGABS(ABS_X)), absinfo, print_input_absinfo }, NULL },
210 { { ARG_STR(EVIOCGABS(ABS_Y)), absinfo, print_input_absinfo }, NULL },
211 { { ARG_STR(EVIOCGABS(ABS_Y)), absinfo, print_input_absinfo }, NULL },
212 { { ARG_STR(EVIOCGBIT(0, 0)), ev_more, print_getbit }, &ev_more_str },
213 { { ARG_STR(EVIOCGBIT(0, 0)), ev_less, print_getbit }, &ev_less_str },
214 { { ARG_STR(EVIOCGBIT(0, 0)), ev_zero, print_getbit }, &ev_zero_str },
215 { { ARG_STR(EVIOCGBIT(EV_KEY, 0)), key, print_getbit }, &key_str},
216 # ifdef EVIOCGMTSLOTS
217 { { ARG_STR(EVIOCGMTSLOTS(12)), mtslots, print_mtslots }, &mtslots_str },
218 { { ARG_STR(EVIOCGMTSLOTS(8)), invalid_mtslot, print_mtslots }, &invalid_mtslot_str }
219 # endif
220 };
221 for (unsigned int i = 0; i < ARRAY_SIZE(a); i++) {
222 test_evdev(&a[i].check, a[i].ptr);
223 }
224
225 puts("+++ exited with 0 +++");
226 return 0;
227 }
228 #else
229
230 SKIP_MAIN_UNDEFINED("HAVE_LINUX_INPUT_H")
231
232 #endif
233