diff --git a/sys/dev/evdev/cdev.c b/sys/dev/evdev/cdev.c --- a/sys/dev/evdev/cdev.c +++ b/sys/dev/evdev/cdev.c @@ -78,7 +78,8 @@ static int evdev_kqread(struct knote *kn, long hint); static void evdev_kqdetach(struct knote *kn); static void evdev_dtor(void *); -static int evdev_ioctl_eviocgbit(struct evdev_dev *, int, int, caddr_t); +static int evdev_ioctl_eviocgbit(struct evdev_dev *, int, int, caddr_t, + struct thread *); static void evdev_client_filter_queue(struct evdev_client *, uint16_t); static struct cdevsw evdev_cdevsw = { @@ -576,29 +577,38 @@ /* evdev variable-length ioctls handling */ switch (IOCBASECMD(cmd)) { case EVIOCGNAME(0): - strlcpy(data, evdev->ev_name, len); + /* Linux evdev does not terminate truncated strings with 0 */ + limit = MIN(strlen(evdev->ev_name) + 1, len); + memcpy(data, evdev->ev_name, limit); + td->td_retval[0] = limit; return (0); case EVIOCGPHYS(0): if (evdev->ev_shortname[0] == 0) return (ENOENT); - strlcpy(data, evdev->ev_shortname, len); + limit = MIN(strlen(evdev->ev_shortname) + 1, len); + memcpy(data, evdev->ev_shortname, limit); + td->td_retval[0] = limit; return (0); case EVIOCGUNIQ(0): if (evdev->ev_serial[0] == 0) return (ENOENT); - strlcpy(data, evdev->ev_serial, len); + limit = MIN(strlen(evdev->ev_serial) + 1, len); + memcpy(data, evdev->ev_serial, limit); + td->td_retval[0] = limit; return (0); case EVIOCGPROP(0): limit = MIN(len, bitstr_size(INPUT_PROP_CNT)); memcpy(data, evdev->ev_prop_flags, limit); + td->td_retval[0] = limit; return (0); case EVIOCGMTSLOTS(0): + /* EVIOCGMTSLOTS always returns 0 on success */ if (evdev->ev_mt == NULL) return (EINVAL); if (len < sizeof(uint32_t)) @@ -620,6 +630,7 @@ evdev_client_filter_queue(client, EV_KEY); memcpy(data, evdev->ev_key_states, limit); EVDEV_UNLOCK(evdev); + td->td_retval[0] = limit; return (0); case EVIOCGLED(0): @@ -628,6 +639,7 @@ evdev_client_filter_queue(client, EV_LED); memcpy(data, evdev->ev_led_states, limit); EVDEV_UNLOCK(evdev); + td->td_retval[0] = limit; return (0); case EVIOCGSND(0): @@ -636,6 +648,7 @@ evdev_client_filter_queue(client, EV_SND); memcpy(data, evdev->ev_snd_states, limit); EVDEV_UNLOCK(evdev); + td->td_retval[0] = limit; return (0); case EVIOCGSW(0): @@ -644,20 +657,22 @@ evdev_client_filter_queue(client, EV_SW); memcpy(data, evdev->ev_sw_states, limit); EVDEV_UNLOCK(evdev); + td->td_retval[0] = limit; return (0); case EVIOCGBIT(0, 0) ... EVIOCGBIT(EV_MAX, 0): type_num = IOCBASECMD(cmd) - EVIOCGBIT(0, 0); debugf(client, "EVIOCGBIT(%d): data=%p, len=%d", type_num, data, len); - return (evdev_ioctl_eviocgbit(evdev, type_num, len, data)); + return (evdev_ioctl_eviocgbit(evdev, type_num, len, data, td)); } return (EINVAL); } static int -evdev_ioctl_eviocgbit(struct evdev_dev *evdev, int type, int len, caddr_t data) +evdev_ioctl_eviocgbit(struct evdev_dev *evdev, int type, int len, caddr_t data, + struct thread *td) { unsigned long *bitmap; int limit; @@ -701,6 +716,7 @@ * just fake it returning only zeros. */ bzero(data, len); + td->td_retval[0] = len; return (0); default: return (ENOTTY); @@ -715,6 +731,7 @@ limit = bitstr_size(limit); len = MIN(limit, len); memcpy(data, bitmap, len); + td->td_retval[0] = len; return (0); }