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 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 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 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 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 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 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 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