vt: keyboard, extract vt_kdgkbent and vt_kdskbent

Split vt_do_kdsk_ioctl into three functions:
* getter (KDGKBENT/vt_kdgkbent)
* setter (KDSKBENT/vt_kdskbent)
* switch-case helper (vt_do_kdsk_ioctl)

This eliminates the need of ugly one-letter macros as we use parameters
now:
* i aka tmp.kb_index -> idx
* s aka tmp.kb_table -> map
* v aka tmp.kb_value -> val

Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Link: https://lore.kernel.org/r/20201029113222.32640-6-jslaby@suse.cz
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Jiri Slaby 2020-10-29 12:32:11 +01:00 committed by Greg Kroah-Hartman
parent e27979dace
commit fe6416e126

View file

@ -1897,19 +1897,111 @@ int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc,
return kc;
}
#define i (tmp.kb_index)
#define s (tmp.kb_table)
#define v (tmp.kb_value)
static unsigned short vt_kdgkbent(unsigned char kbdmode, unsigned char idx,
unsigned char map)
{
unsigned short *key_map, val;
unsigned long flags;
/* Ensure another thread doesn't free it under us */
spin_lock_irqsave(&kbd_event_lock, flags);
key_map = key_maps[map];
if (key_map) {
val = U(key_map[idx]);
if (kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
val = K_HOLE;
} else
val = idx ? K_HOLE : K_NOSUCHMAP;
spin_unlock_irqrestore(&kbd_event_lock, flags);
return val;
}
static int vt_kdskbent(unsigned char kbdmode, unsigned char idx,
unsigned char map, unsigned short val)
{
unsigned long flags;
unsigned short *key_map, *new_map, oldval;
if (!idx && val == K_NOSUCHMAP) {
spin_lock_irqsave(&kbd_event_lock, flags);
/* deallocate map */
key_map = key_maps[map];
if (map && key_map) {
key_maps[map] = NULL;
if (key_map[0] == U(K_ALLOCATED)) {
kfree(key_map);
keymap_count--;
}
}
spin_unlock_irqrestore(&kbd_event_lock, flags);
return 0;
}
if (KTYP(val) < NR_TYPES) {
if (KVAL(val) > max_vals[KTYP(val)])
return -EINVAL;
} else if (kbdmode != VC_UNICODE)
return -EINVAL;
/* ++Geert: non-PC keyboards may generate keycode zero */
#if !defined(__mc68000__) && !defined(__powerpc__)
/* assignment to entry 0 only tests validity of args */
if (!idx)
return 0;
#endif
new_map = kmalloc(sizeof(plain_map), GFP_KERNEL);
if (!new_map)
return -ENOMEM;
spin_lock_irqsave(&kbd_event_lock, flags);
key_map = key_maps[map];
if (key_map == NULL) {
int j;
if (keymap_count >= MAX_NR_OF_USER_KEYMAPS &&
!capable(CAP_SYS_RESOURCE)) {
spin_unlock_irqrestore(&kbd_event_lock, flags);
kfree(new_map);
return -EPERM;
}
key_maps[map] = new_map;
key_map = new_map;
key_map[0] = U(K_ALLOCATED);
for (j = 1; j < NR_KEYS; j++)
key_map[j] = U(K_HOLE);
keymap_count++;
} else
kfree(new_map);
oldval = U(key_map[idx]);
if (val == oldval)
goto out;
/* Attention Key */
if ((oldval == K_SAK || val == K_SAK) && !capable(CAP_SYS_ADMIN)) {
spin_unlock_irqrestore(&kbd_event_lock, flags);
return -EPERM;
}
key_map[idx] = U(val);
if (!map && (KTYP(oldval) == KT_SHIFT || KTYP(val) == KT_SHIFT))
do_compute_shiftstate();
out:
spin_unlock_irqrestore(&kbd_event_lock, flags);
return 0;
}
int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm,
int console)
{
struct kbd_struct *kb = kbd_table + console;
struct kbentry tmp;
ushort *key_map, *new_map, val, ov;
unsigned long flags;
struct kbentry kbe;
if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
if (copy_from_user(&kbe, user_kbe, sizeof(struct kbentry)))
return -EFAULT;
if (!capable(CAP_SYS_TTY_CONFIG))
@ -1917,94 +2009,17 @@ int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm,
switch (cmd) {
case KDGKBENT:
/* Ensure another thread doesn't free it under us */
spin_lock_irqsave(&kbd_event_lock, flags);
key_map = key_maps[s];
if (key_map) {
val = U(key_map[i]);
if (kb->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
val = K_HOLE;
} else
val = (i ? K_HOLE : K_NOSUCHMAP);
spin_unlock_irqrestore(&kbd_event_lock, flags);
return put_user(val, &user_kbe->kb_value);
return put_user(vt_kdgkbent(kb->kbdmode, kbe.kb_index,
kbe.kb_table),
&user_kbe->kb_value);
case KDSKBENT:
if (!perm)
return -EPERM;
if (!i && v == K_NOSUCHMAP) {
spin_lock_irqsave(&kbd_event_lock, flags);
/* deallocate map */
key_map = key_maps[s];
if (s && key_map) {
key_maps[s] = NULL;
if (key_map[0] == U(K_ALLOCATED)) {
kfree(key_map);
keymap_count--;
}
}
spin_unlock_irqrestore(&kbd_event_lock, flags);
break;
}
if (KTYP(v) < NR_TYPES) {
if (KVAL(v) > max_vals[KTYP(v)])
return -EINVAL;
} else
if (kb->kbdmode != VC_UNICODE)
return -EINVAL;
/* ++Geert: non-PC keyboards may generate keycode zero */
#if !defined(__mc68000__) && !defined(__powerpc__)
/* assignment to entry 0 only tests validity of args */
if (!i)
break;
#endif
new_map = kmalloc(sizeof(plain_map), GFP_KERNEL);
if (!new_map)
return -ENOMEM;
spin_lock_irqsave(&kbd_event_lock, flags);
key_map = key_maps[s];
if (key_map == NULL) {
int j;
if (keymap_count >= MAX_NR_OF_USER_KEYMAPS &&
!capable(CAP_SYS_RESOURCE)) {
spin_unlock_irqrestore(&kbd_event_lock, flags);
kfree(new_map);
return -EPERM;
}
key_maps[s] = new_map;
key_map = new_map;
key_map[0] = U(K_ALLOCATED);
for (j = 1; j < NR_KEYS; j++)
key_map[j] = U(K_HOLE);
keymap_count++;
} else
kfree(new_map);
ov = U(key_map[i]);
if (v == ov)
goto out;
/*
* Attention Key.
*/
if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) {
spin_unlock_irqrestore(&kbd_event_lock, flags);
return -EPERM;
}
key_map[i] = U(v);
if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
do_compute_shiftstate();
out:
spin_unlock_irqrestore(&kbd_event_lock, flags);
break;
return vt_kdskbent(kb->kbdmode, kbe.kb_index, kbe.kb_table,
kbe.kb_value);
}
return 0;
}
#undef i
#undef s
#undef v
/* FIXME: This one needs untangling */
int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)