Contents of /alx-src/tags/kernel26-2.6.12-alx-r9/drivers/char/vt_ioctl.c
Parent Directory | Revision Log
Revision 630 -
(show annotations)
(download)
Wed Mar 4 11:03:09 2009 UTC (15 years, 3 months ago) by niro
File MIME type: text/plain
File size: 28735 byte(s)
Wed Mar 4 11:03:09 2009 UTC (15 years, 3 months ago) by niro
File MIME type: text/plain
File size: 28735 byte(s)
Tag kernel26-2.6.12-alx-r9
1 | /* |
2 | * linux/drivers/char/vt_ioctl.c |
3 | * |
4 | * Copyright (C) 1992 obz under the linux copyright |
5 | * |
6 | * Dynamic diacritical handling - aeb@cwi.nl - Dec 1993 |
7 | * Dynamic keymap and string allocation - aeb@cwi.nl - May 1994 |
8 | * Restrict VT switching via ioctl() - grif@cs.ucr.edu - Dec 1995 |
9 | * Some code moved for less code duplication - Andi Kleen - Mar 1997 |
10 | * Check put/get_user, cleanups - acme@conectiva.com.br - Jun 2001 |
11 | */ |
12 | |
13 | #include <linux/config.h> |
14 | #include <linux/types.h> |
15 | #include <linux/errno.h> |
16 | #include <linux/sched.h> |
17 | #include <linux/tty.h> |
18 | #include <linux/timer.h> |
19 | #include <linux/kernel.h> |
20 | #include <linux/kd.h> |
21 | #include <linux/vt.h> |
22 | #include <linux/string.h> |
23 | #include <linux/slab.h> |
24 | #include <linux/major.h> |
25 | #include <linux/fs.h> |
26 | #include <linux/console.h> |
27 | #include <linux/signal.h> |
28 | |
29 | #include <asm/io.h> |
30 | #include <asm/uaccess.h> |
31 | |
32 | #include <linux/kbd_kern.h> |
33 | #include <linux/vt_kern.h> |
34 | #include <linux/kbd_diacr.h> |
35 | #include <linux/selection.h> |
36 | |
37 | static char vt_dont_switch; |
38 | extern struct tty_driver *console_driver; |
39 | |
40 | #define VT_IS_IN_USE(i) (console_driver->ttys[i] && console_driver->ttys[i]->count) |
41 | #define VT_BUSY(i) (VT_IS_IN_USE(i) || i == fg_console || vc_cons[i].d == sel_cons) |
42 | |
43 | /* |
44 | * Console (vt and kd) routines, as defined by USL SVR4 manual, and by |
45 | * experimentation and study of X386 SYSV handling. |
46 | * |
47 | * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and |
48 | * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console, |
49 | * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will |
50 | * always treat our set of vt as numbered 1..MAX_NR_CONSOLES (corresponding to |
51 | * ttys 0..MAX_NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using |
52 | * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing |
53 | * to the current console is done by the main ioctl code. |
54 | */ |
55 | |
56 | #ifdef CONFIG_X86 |
57 | #include <linux/syscalls.h> |
58 | #endif |
59 | |
60 | static void complete_change_console(struct vc_data *vc); |
61 | |
62 | /* |
63 | * these are the valid i/o ports we're allowed to change. they map all the |
64 | * video ports |
65 | */ |
66 | #define GPFIRST 0x3b4 |
67 | #define GPLAST 0x3df |
68 | #define GPNUM (GPLAST - GPFIRST + 1) |
69 | |
70 | #define i (tmp.kb_index) |
71 | #define s (tmp.kb_table) |
72 | #define v (tmp.kb_value) |
73 | static inline int |
74 | do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_struct *kbd) |
75 | { |
76 | struct kbentry tmp; |
77 | ushort *key_map, val, ov; |
78 | |
79 | if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry))) |
80 | return -EFAULT; |
81 | |
82 | switch (cmd) { |
83 | case KDGKBENT: |
84 | key_map = key_maps[s]; |
85 | if (key_map) { |
86 | val = U(key_map[i]); |
87 | if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) |
88 | val = K_HOLE; |
89 | } else |
90 | val = (i ? K_HOLE : K_NOSUCHMAP); |
91 | return put_user(val, &user_kbe->kb_value); |
92 | case KDSKBENT: |
93 | if (!perm) |
94 | return -EPERM; |
95 | if (!i && v == K_NOSUCHMAP) { |
96 | /* disallocate map */ |
97 | key_map = key_maps[s]; |
98 | if (s && key_map) { |
99 | key_maps[s] = NULL; |
100 | if (key_map[0] == U(K_ALLOCATED)) { |
101 | kfree(key_map); |
102 | keymap_count--; |
103 | } |
104 | } |
105 | break; |
106 | } |
107 | |
108 | if (KTYP(v) < NR_TYPES) { |
109 | if (KVAL(v) > max_vals[KTYP(v)]) |
110 | return -EINVAL; |
111 | } else |
112 | if (kbd->kbdmode != VC_UNICODE) |
113 | return -EINVAL; |
114 | |
115 | /* ++Geert: non-PC keyboards may generate keycode zero */ |
116 | #if !defined(__mc68000__) && !defined(__powerpc__) |
117 | /* assignment to entry 0 only tests validity of args */ |
118 | if (!i) |
119 | break; |
120 | #endif |
121 | |
122 | if (!(key_map = key_maps[s])) { |
123 | int j; |
124 | |
125 | if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && |
126 | !capable(CAP_SYS_RESOURCE)) |
127 | return -EPERM; |
128 | |
129 | key_map = (ushort *) kmalloc(sizeof(plain_map), |
130 | GFP_KERNEL); |
131 | if (!key_map) |
132 | return -ENOMEM; |
133 | key_maps[s] = key_map; |
134 | key_map[0] = U(K_ALLOCATED); |
135 | for (j = 1; j < NR_KEYS; j++) |
136 | key_map[j] = U(K_HOLE); |
137 | keymap_count++; |
138 | } |
139 | ov = U(key_map[i]); |
140 | if (v == ov) |
141 | break; /* nothing to do */ |
142 | /* |
143 | * Attention Key. |
144 | */ |
145 | if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) |
146 | return -EPERM; |
147 | key_map[i] = U(v); |
148 | if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT)) |
149 | compute_shiftstate(); |
150 | break; |
151 | } |
152 | return 0; |
153 | } |
154 | #undef i |
155 | #undef s |
156 | #undef v |
157 | |
158 | static inline int |
159 | do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, int perm) |
160 | { |
161 | struct kbkeycode tmp; |
162 | int kc = 0; |
163 | |
164 | if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode))) |
165 | return -EFAULT; |
166 | switch (cmd) { |
167 | case KDGETKEYCODE: |
168 | kc = getkeycode(tmp.scancode); |
169 | if (kc >= 0) |
170 | kc = put_user(kc, &user_kbkc->keycode); |
171 | break; |
172 | case KDSETKEYCODE: |
173 | if (!perm) |
174 | return -EPERM; |
175 | kc = setkeycode(tmp.scancode, tmp.keycode); |
176 | break; |
177 | } |
178 | return kc; |
179 | } |
180 | |
181 | static inline int |
182 | do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) |
183 | { |
184 | struct kbsentry *kbs; |
185 | char *p; |
186 | u_char *q; |
187 | u_char __user *up; |
188 | int sz; |
189 | int delta; |
190 | char *first_free, *fj, *fnw; |
191 | int i, j, k; |
192 | int ret; |
193 | |
194 | kbs = kmalloc(sizeof(*kbs), GFP_KERNEL); |
195 | if (!kbs) { |
196 | ret = -ENOMEM; |
197 | goto reterr; |
198 | } |
199 | |
200 | /* we mostly copy too much here (512bytes), but who cares ;) */ |
201 | if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) { |
202 | ret = -EFAULT; |
203 | goto reterr; |
204 | } |
205 | kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0'; |
206 | i = kbs->kb_func; |
207 | |
208 | switch (cmd) { |
209 | case KDGKBSENT: |
210 | sz = sizeof(kbs->kb_string) - 1; /* sz should have been |
211 | a struct member */ |
212 | up = user_kdgkb->kb_string; |
213 | p = func_table[i]; |
214 | if(p) |
215 | for ( ; *p && sz; p++, sz--) |
216 | if (put_user(*p, up++)) { |
217 | ret = -EFAULT; |
218 | goto reterr; |
219 | } |
220 | if (put_user('\0', up)) { |
221 | ret = -EFAULT; |
222 | goto reterr; |
223 | } |
224 | kfree(kbs); |
225 | return ((p && *p) ? -EOVERFLOW : 0); |
226 | case KDSKBSENT: |
227 | if (!perm) { |
228 | ret = -EPERM; |
229 | goto reterr; |
230 | } |
231 | |
232 | q = func_table[i]; |
233 | first_free = funcbufptr + (funcbufsize - funcbufleft); |
234 | for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) |
235 | ; |
236 | if (j < MAX_NR_FUNC) |
237 | fj = func_table[j]; |
238 | else |
239 | fj = first_free; |
240 | |
241 | delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string); |
242 | if (delta <= funcbufleft) { /* it fits in current buf */ |
243 | if (j < MAX_NR_FUNC) { |
244 | memmove(fj + delta, fj, first_free - fj); |
245 | for (k = j; k < MAX_NR_FUNC; k++) |
246 | if (func_table[k]) |
247 | func_table[k] += delta; |
248 | } |
249 | if (!q) |
250 | func_table[i] = fj; |
251 | funcbufleft -= delta; |
252 | } else { /* allocate a larger buffer */ |
253 | sz = 256; |
254 | while (sz < funcbufsize - funcbufleft + delta) |
255 | sz <<= 1; |
256 | fnw = (char *) kmalloc(sz, GFP_KERNEL); |
257 | if(!fnw) { |
258 | ret = -ENOMEM; |
259 | goto reterr; |
260 | } |
261 | |
262 | if (!q) |
263 | func_table[i] = fj; |
264 | if (fj > funcbufptr) |
265 | memmove(fnw, funcbufptr, fj - funcbufptr); |
266 | for (k = 0; k < j; k++) |
267 | if (func_table[k]) |
268 | func_table[k] = fnw + (func_table[k] - funcbufptr); |
269 | |
270 | if (first_free > fj) { |
271 | memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj); |
272 | for (k = j; k < MAX_NR_FUNC; k++) |
273 | if (func_table[k]) |
274 | func_table[k] = fnw + (func_table[k] - funcbufptr) + delta; |
275 | } |
276 | if (funcbufptr != func_buf) |
277 | kfree(funcbufptr); |
278 | funcbufptr = fnw; |
279 | funcbufleft = funcbufleft - delta + sz - funcbufsize; |
280 | funcbufsize = sz; |
281 | } |
282 | strcpy(func_table[i], kbs->kb_string); |
283 | break; |
284 | } |
285 | ret = 0; |
286 | reterr: |
287 | kfree(kbs); |
288 | return ret; |
289 | } |
290 | |
291 | static inline int |
292 | do_fontx_ioctl(int cmd, struct consolefontdesc __user *user_cfd, int perm, struct console_font_op *op) |
293 | { |
294 | struct consolefontdesc cfdarg; |
295 | int i; |
296 | |
297 | if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc))) |
298 | return -EFAULT; |
299 | |
300 | switch (cmd) { |
301 | case PIO_FONTX: |
302 | if (!perm) |
303 | return -EPERM; |
304 | op->op = KD_FONT_OP_SET; |
305 | op->flags = KD_FONT_FLAG_OLD; |
306 | op->width = 8; |
307 | op->height = cfdarg.charheight; |
308 | op->charcount = cfdarg.charcount; |
309 | op->data = cfdarg.chardata; |
310 | return con_font_op(vc_cons[fg_console].d, op); |
311 | case GIO_FONTX: { |
312 | op->op = KD_FONT_OP_GET; |
313 | op->flags = KD_FONT_FLAG_OLD; |
314 | op->width = 8; |
315 | op->height = cfdarg.charheight; |
316 | op->charcount = cfdarg.charcount; |
317 | op->data = cfdarg.chardata; |
318 | i = con_font_op(vc_cons[fg_console].d, op); |
319 | if (i) |
320 | return i; |
321 | cfdarg.charheight = op->height; |
322 | cfdarg.charcount = op->charcount; |
323 | if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc))) |
324 | return -EFAULT; |
325 | return 0; |
326 | } |
327 | } |
328 | return -EINVAL; |
329 | } |
330 | |
331 | static inline int |
332 | do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_data *vc) |
333 | { |
334 | struct unimapdesc tmp; |
335 | |
336 | if (copy_from_user(&tmp, user_ud, sizeof tmp)) |
337 | return -EFAULT; |
338 | if (tmp.entries) |
339 | if (!access_ok(VERIFY_WRITE, tmp.entries, |
340 | tmp.entry_ct*sizeof(struct unipair))) |
341 | return -EFAULT; |
342 | switch (cmd) { |
343 | case PIO_UNIMAP: |
344 | if (!perm) |
345 | return -EPERM; |
346 | return con_set_unimap(vc, tmp.entry_ct, tmp.entries); |
347 | case GIO_UNIMAP: |
348 | if (!perm && fg_console != vc->vc_num) |
349 | return -EPERM; |
350 | return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries); |
351 | } |
352 | return 0; |
353 | } |
354 | |
355 | /* |
356 | * We handle the console-specific ioctl's here. We allow the |
357 | * capability to modify any console, not just the fg_console. |
358 | */ |
359 | int vt_ioctl(struct tty_struct *tty, struct file * file, |
360 | unsigned int cmd, unsigned long arg) |
361 | { |
362 | struct vc_data *vc = (struct vc_data *)tty->driver_data; |
363 | struct console_font_op op; /* used in multiple places here */ |
364 | struct kbd_struct * kbd; |
365 | unsigned int console; |
366 | unsigned char ucval; |
367 | void __user *up = (void __user *)arg; |
368 | int i, perm; |
369 | |
370 | console = vc->vc_num; |
371 | |
372 | if (!vc_cons_allocated(console)) /* impossible? */ |
373 | return -ENOIOCTLCMD; |
374 | |
375 | /* |
376 | * To have permissions to do most of the vt ioctls, we either have |
377 | * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG. |
378 | */ |
379 | perm = 0; |
380 | if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG)) |
381 | perm = 1; |
382 | |
383 | kbd = kbd_table + console; |
384 | switch (cmd) { |
385 | case KIOCSOUND: |
386 | if (!perm) |
387 | return -EPERM; |
388 | if (arg) |
389 | arg = 1193182 / arg; |
390 | kd_mksound(arg, 0); |
391 | return 0; |
392 | |
393 | case KDMKTONE: |
394 | if (!perm) |
395 | return -EPERM; |
396 | { |
397 | unsigned int ticks, count; |
398 | |
399 | /* |
400 | * Generate the tone for the appropriate number of ticks. |
401 | * If the time is zero, turn off sound ourselves. |
402 | */ |
403 | ticks = HZ * ((arg >> 16) & 0xffff) / 1000; |
404 | count = ticks ? (arg & 0xffff) : 0; |
405 | if (count) |
406 | count = 1193182 / count; |
407 | kd_mksound(count, ticks); |
408 | return 0; |
409 | } |
410 | |
411 | case KDGKBTYPE: |
412 | /* |
413 | * this is naive. |
414 | */ |
415 | ucval = KB_101; |
416 | goto setchar; |
417 | |
418 | /* |
419 | * These cannot be implemented on any machine that implements |
420 | * ioperm() in user level (such as Alpha PCs) or not at all. |
421 | * |
422 | * XXX: you should never use these, just call ioperm directly.. |
423 | */ |
424 | #ifdef CONFIG_X86 |
425 | case KDADDIO: |
426 | case KDDELIO: |
427 | /* |
428 | * KDADDIO and KDDELIO may be able to add ports beyond what |
429 | * we reject here, but to be safe... |
430 | */ |
431 | if (arg < GPFIRST || arg > GPLAST) |
432 | return -EINVAL; |
433 | return sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0; |
434 | |
435 | case KDENABIO: |
436 | case KDDISABIO: |
437 | return sys_ioperm(GPFIRST, GPNUM, |
438 | (cmd == KDENABIO)) ? -ENXIO : 0; |
439 | #endif |
440 | |
441 | /* Linux m68k/i386 interface for setting the keyboard delay/repeat rate */ |
442 | |
443 | case KDKBDREP: |
444 | { |
445 | struct kbd_repeat kbrep; |
446 | int err; |
447 | |
448 | if (!capable(CAP_SYS_TTY_CONFIG)) |
449 | return -EPERM; |
450 | |
451 | if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) |
452 | return -EFAULT; |
453 | err = kbd_rate(&kbrep); |
454 | if (err) |
455 | return err; |
456 | if (copy_to_user(up, &kbrep, sizeof(struct kbd_repeat))) |
457 | return -EFAULT; |
458 | return 0; |
459 | } |
460 | |
461 | case KDSETMODE: |
462 | /* |
463 | * currently, setting the mode from KD_TEXT to KD_GRAPHICS |
464 | * doesn't do a whole lot. i'm not sure if it should do any |
465 | * restoration of modes or what... |
466 | * |
467 | * XXX It should at least call into the driver, fbdev's definitely |
468 | * need to restore their engine state. --BenH |
469 | */ |
470 | if (!perm) |
471 | return -EPERM; |
472 | switch (arg) { |
473 | case KD_GRAPHICS: |
474 | break; |
475 | case KD_TEXT0: |
476 | case KD_TEXT1: |
477 | arg = KD_TEXT; |
478 | case KD_TEXT: |
479 | break; |
480 | default: |
481 | return -EINVAL; |
482 | } |
483 | if (vc->vc_mode == (unsigned char) arg) |
484 | return 0; |
485 | vc->vc_mode = (unsigned char) arg; |
486 | if (console != fg_console) |
487 | return 0; |
488 | /* |
489 | * explicitly blank/unblank the screen if switching modes |
490 | */ |
491 | acquire_console_sem(); |
492 | if (arg == KD_TEXT) |
493 | do_unblank_screen(1); |
494 | else |
495 | do_blank_screen(1); |
496 | release_console_sem(); |
497 | return 0; |
498 | |
499 | case KDGETMODE: |
500 | ucval = vc->vc_mode; |
501 | goto setint; |
502 | |
503 | case KDMAPDISP: |
504 | case KDUNMAPDISP: |
505 | /* |
506 | * these work like a combination of mmap and KDENABIO. |
507 | * this could be easily finished. |
508 | */ |
509 | return -EINVAL; |
510 | |
511 | case KDSKBMODE: |
512 | if (!perm) |
513 | return -EPERM; |
514 | switch(arg) { |
515 | case K_RAW: |
516 | kbd->kbdmode = VC_RAW; |
517 | break; |
518 | case K_MEDIUMRAW: |
519 | kbd->kbdmode = VC_MEDIUMRAW; |
520 | break; |
521 | case K_XLATE: |
522 | kbd->kbdmode = VC_XLATE; |
523 | compute_shiftstate(); |
524 | break; |
525 | case K_UNICODE: |
526 | kbd->kbdmode = VC_UNICODE; |
527 | compute_shiftstate(); |
528 | break; |
529 | default: |
530 | return -EINVAL; |
531 | } |
532 | tty_ldisc_flush(tty); |
533 | return 0; |
534 | |
535 | case KDGKBMODE: |
536 | ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW : |
537 | (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW : |
538 | (kbd->kbdmode == VC_UNICODE) ? K_UNICODE : |
539 | K_XLATE); |
540 | goto setint; |
541 | |
542 | /* this could be folded into KDSKBMODE, but for compatibility |
543 | reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */ |
544 | case KDSKBMETA: |
545 | switch(arg) { |
546 | case K_METABIT: |
547 | clr_vc_kbd_mode(kbd, VC_META); |
548 | break; |
549 | case K_ESCPREFIX: |
550 | set_vc_kbd_mode(kbd, VC_META); |
551 | break; |
552 | default: |
553 | return -EINVAL; |
554 | } |
555 | return 0; |
556 | |
557 | case KDGKBMETA: |
558 | ucval = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT); |
559 | setint: |
560 | return put_user(ucval, (int __user *)arg); |
561 | |
562 | case KDGETKEYCODE: |
563 | case KDSETKEYCODE: |
564 | if(!capable(CAP_SYS_TTY_CONFIG)) |
565 | perm=0; |
566 | return do_kbkeycode_ioctl(cmd, up, perm); |
567 | |
568 | case KDGKBENT: |
569 | case KDSKBENT: |
570 | return do_kdsk_ioctl(cmd, up, perm, kbd); |
571 | |
572 | case KDGKBSENT: |
573 | case KDSKBSENT: |
574 | return do_kdgkb_ioctl(cmd, up, perm); |
575 | |
576 | case KDGKBDIACR: |
577 | { |
578 | struct kbdiacrs __user *a = up; |
579 | |
580 | if (put_user(accent_table_size, &a->kb_cnt)) |
581 | return -EFAULT; |
582 | if (copy_to_user(a->kbdiacr, accent_table, accent_table_size*sizeof(struct kbdiacr))) |
583 | return -EFAULT; |
584 | return 0; |
585 | } |
586 | |
587 | case KDSKBDIACR: |
588 | { |
589 | struct kbdiacrs __user *a = up; |
590 | unsigned int ct; |
591 | |
592 | if (!perm) |
593 | return -EPERM; |
594 | if (get_user(ct,&a->kb_cnt)) |
595 | return -EFAULT; |
596 | if (ct >= MAX_DIACR) |
597 | return -EINVAL; |
598 | accent_table_size = ct; |
599 | if (copy_from_user(accent_table, a->kbdiacr, ct*sizeof(struct kbdiacr))) |
600 | return -EFAULT; |
601 | return 0; |
602 | } |
603 | |
604 | /* the ioctls below read/set the flags usually shown in the leds */ |
605 | /* don't use them - they will go away without warning */ |
606 | case KDGKBLED: |
607 | ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4); |
608 | goto setchar; |
609 | |
610 | case KDSKBLED: |
611 | if (!perm) |
612 | return -EPERM; |
613 | if (arg & ~0x77) |
614 | return -EINVAL; |
615 | kbd->ledflagstate = (arg & 7); |
616 | kbd->default_ledflagstate = ((arg >> 4) & 7); |
617 | set_leds(); |
618 | return 0; |
619 | |
620 | /* the ioctls below only set the lights, not the functions */ |
621 | /* for those, see KDGKBLED and KDSKBLED above */ |
622 | case KDGETLED: |
623 | ucval = getledstate(); |
624 | setchar: |
625 | return put_user(ucval, (char __user *)arg); |
626 | |
627 | case KDSETLED: |
628 | if (!perm) |
629 | return -EPERM; |
630 | setledstate(kbd, arg); |
631 | return 0; |
632 | |
633 | /* |
634 | * A process can indicate its willingness to accept signals |
635 | * generated by pressing an appropriate key combination. |
636 | * Thus, one can have a daemon that e.g. spawns a new console |
637 | * upon a keypress and then changes to it. |
638 | * See also the kbrequest field of inittab(5). |
639 | */ |
640 | case KDSIGACCEPT: |
641 | { |
642 | extern int spawnpid, spawnsig; |
643 | if (!perm || !capable(CAP_KILL)) |
644 | return -EPERM; |
645 | if (!valid_signal(arg) || arg < 1 || arg == SIGKILL) |
646 | return -EINVAL; |
647 | spawnpid = current->pid; |
648 | spawnsig = arg; |
649 | return 0; |
650 | } |
651 | |
652 | case VT_SETMODE: |
653 | { |
654 | struct vt_mode tmp; |
655 | |
656 | if (!perm) |
657 | return -EPERM; |
658 | if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) |
659 | return -EFAULT; |
660 | if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) |
661 | return -EINVAL; |
662 | acquire_console_sem(); |
663 | vc->vt_mode = tmp; |
664 | /* the frsig is ignored, so we set it to 0 */ |
665 | vc->vt_mode.frsig = 0; |
666 | vc->vt_pid = current->pid; |
667 | /* no switch is required -- saw@shade.msu.ru */ |
668 | vc->vt_newvt = -1; |
669 | release_console_sem(); |
670 | return 0; |
671 | } |
672 | |
673 | case VT_GETMODE: |
674 | { |
675 | struct vt_mode tmp; |
676 | int rc; |
677 | |
678 | acquire_console_sem(); |
679 | memcpy(&tmp, &vc->vt_mode, sizeof(struct vt_mode)); |
680 | release_console_sem(); |
681 | |
682 | rc = copy_to_user(up, &tmp, sizeof(struct vt_mode)); |
683 | return rc ? -EFAULT : 0; |
684 | } |
685 | |
686 | /* |
687 | * Returns global vt state. Note that VT 0 is always open, since |
688 | * it's an alias for the current VT, and people can't use it here. |
689 | * We cannot return state for more than 16 VTs, since v_state is short. |
690 | */ |
691 | case VT_GETSTATE: |
692 | { |
693 | struct vt_stat __user *vtstat = up; |
694 | unsigned short state, mask; |
695 | |
696 | if (put_user(fg_console + 1, &vtstat->v_active)) |
697 | return -EFAULT; |
698 | state = 1; /* /dev/tty0 is always open */ |
699 | for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1) |
700 | if (VT_IS_IN_USE(i)) |
701 | state |= mask; |
702 | return put_user(state, &vtstat->v_state); |
703 | } |
704 | |
705 | /* |
706 | * Returns the first available (non-opened) console. |
707 | */ |
708 | case VT_OPENQRY: |
709 | for (i = 0; i < MAX_NR_CONSOLES; ++i) |
710 | if (! VT_IS_IN_USE(i)) |
711 | break; |
712 | ucval = i < MAX_NR_CONSOLES ? (i+1) : -1; |
713 | goto setint; |
714 | |
715 | /* |
716 | * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num, |
717 | * with num >= 1 (switches to vt 0, our console, are not allowed, just |
718 | * to preserve sanity). |
719 | */ |
720 | case VT_ACTIVATE: |
721 | if (!perm) |
722 | return -EPERM; |
723 | if (arg == 0 || arg > MAX_NR_CONSOLES) |
724 | return -ENXIO; |
725 | arg--; |
726 | acquire_console_sem(); |
727 | i = vc_allocate(arg); |
728 | release_console_sem(); |
729 | if (i) |
730 | return i; |
731 | set_console(arg); |
732 | return 0; |
733 | |
734 | /* |
735 | * wait until the specified VT has been activated |
736 | */ |
737 | case VT_WAITACTIVE: |
738 | if (!perm) |
739 | return -EPERM; |
740 | if (arg == 0 || arg > MAX_NR_CONSOLES) |
741 | return -ENXIO; |
742 | return vt_waitactive(arg-1); |
743 | |
744 | /* |
745 | * If a vt is under process control, the kernel will not switch to it |
746 | * immediately, but postpone the operation until the process calls this |
747 | * ioctl, allowing the switch to complete. |
748 | * |
749 | * According to the X sources this is the behavior: |
750 | * 0: pending switch-from not OK |
751 | * 1: pending switch-from OK |
752 | * 2: completed switch-to OK |
753 | */ |
754 | case VT_RELDISP: |
755 | if (!perm) |
756 | return -EPERM; |
757 | if (vc->vt_mode.mode != VT_PROCESS) |
758 | return -EINVAL; |
759 | |
760 | /* |
761 | * Switching-from response |
762 | */ |
763 | if (vc->vt_newvt >= 0) { |
764 | if (arg == 0) |
765 | /* |
766 | * Switch disallowed, so forget we were trying |
767 | * to do it. |
768 | */ |
769 | vc->vt_newvt = -1; |
770 | |
771 | else { |
772 | /* |
773 | * The current vt has been released, so |
774 | * complete the switch. |
775 | */ |
776 | int newvt; |
777 | acquire_console_sem(); |
778 | newvt = vc->vt_newvt; |
779 | vc->vt_newvt = -1; |
780 | i = vc_allocate(newvt); |
781 | if (i) { |
782 | release_console_sem(); |
783 | return i; |
784 | } |
785 | /* |
786 | * When we actually do the console switch, |
787 | * make sure we are atomic with respect to |
788 | * other console switches.. |
789 | */ |
790 | complete_change_console(vc_cons[newvt].d); |
791 | release_console_sem(); |
792 | } |
793 | } |
794 | |
795 | /* |
796 | * Switched-to response |
797 | */ |
798 | else |
799 | { |
800 | /* |
801 | * If it's just an ACK, ignore it |
802 | */ |
803 | if (arg != VT_ACKACQ) |
804 | return -EINVAL; |
805 | } |
806 | |
807 | return 0; |
808 | |
809 | /* |
810 | * Disallocate memory associated to VT (but leave VT1) |
811 | */ |
812 | case VT_DISALLOCATE: |
813 | if (arg > MAX_NR_CONSOLES) |
814 | return -ENXIO; |
815 | if (arg == 0) { |
816 | /* disallocate all unused consoles, but leave 0 */ |
817 | acquire_console_sem(); |
818 | for (i=1; i<MAX_NR_CONSOLES; i++) |
819 | if (! VT_BUSY(i)) |
820 | vc_disallocate(i); |
821 | release_console_sem(); |
822 | } else { |
823 | /* disallocate a single console, if possible */ |
824 | arg--; |
825 | if (VT_BUSY(arg)) |
826 | return -EBUSY; |
827 | if (arg) { /* leave 0 */ |
828 | acquire_console_sem(); |
829 | vc_disallocate(arg); |
830 | release_console_sem(); |
831 | } |
832 | } |
833 | return 0; |
834 | |
835 | case VT_RESIZE: |
836 | { |
837 | struct vt_sizes __user *vtsizes = up; |
838 | ushort ll,cc; |
839 | if (!perm) |
840 | return -EPERM; |
841 | if (get_user(ll, &vtsizes->v_rows) || |
842 | get_user(cc, &vtsizes->v_cols)) |
843 | return -EFAULT; |
844 | for (i = 0; i < MAX_NR_CONSOLES; i++) { |
845 | acquire_console_sem(); |
846 | vc_resize(vc_cons[i].d, cc, ll); |
847 | release_console_sem(); |
848 | } |
849 | return 0; |
850 | } |
851 | |
852 | case VT_RESIZEX: |
853 | { |
854 | struct vt_consize __user *vtconsize = up; |
855 | ushort ll,cc,vlin,clin,vcol,ccol; |
856 | if (!perm) |
857 | return -EPERM; |
858 | if (!access_ok(VERIFY_READ, vtconsize, |
859 | sizeof(struct vt_consize))) |
860 | return -EFAULT; |
861 | __get_user(ll, &vtconsize->v_rows); |
862 | __get_user(cc, &vtconsize->v_cols); |
863 | __get_user(vlin, &vtconsize->v_vlin); |
864 | __get_user(clin, &vtconsize->v_clin); |
865 | __get_user(vcol, &vtconsize->v_vcol); |
866 | __get_user(ccol, &vtconsize->v_ccol); |
867 | vlin = vlin ? vlin : vc->vc_scan_lines; |
868 | if (clin) { |
869 | if (ll) { |
870 | if (ll != vlin/clin) |
871 | return -EINVAL; /* Parameters don't add up */ |
872 | } else |
873 | ll = vlin/clin; |
874 | } |
875 | if (vcol && ccol) { |
876 | if (cc) { |
877 | if (cc != vcol/ccol) |
878 | return -EINVAL; |
879 | } else |
880 | cc = vcol/ccol; |
881 | } |
882 | |
883 | if (clin > 32) |
884 | return -EINVAL; |
885 | |
886 | for (i = 0; i < MAX_NR_CONSOLES; i++) { |
887 | if (!vc_cons[i].d) |
888 | continue; |
889 | acquire_console_sem(); |
890 | if (vlin) |
891 | vc_cons[i].d->vc_scan_lines = vlin; |
892 | if (clin) |
893 | vc_cons[i].d->vc_font.height = clin; |
894 | vc_resize(vc_cons[i].d, cc, ll); |
895 | release_console_sem(); |
896 | } |
897 | return 0; |
898 | } |
899 | |
900 | case PIO_FONT: { |
901 | if (!perm) |
902 | return -EPERM; |
903 | op.op = KD_FONT_OP_SET; |
904 | op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */ |
905 | op.width = 8; |
906 | op.height = 0; |
907 | op.charcount = 256; |
908 | op.data = up; |
909 | return con_font_op(vc_cons[fg_console].d, &op); |
910 | } |
911 | |
912 | case GIO_FONT: { |
913 | op.op = KD_FONT_OP_GET; |
914 | op.flags = KD_FONT_FLAG_OLD; |
915 | op.width = 8; |
916 | op.height = 32; |
917 | op.charcount = 256; |
918 | op.data = up; |
919 | return con_font_op(vc_cons[fg_console].d, &op); |
920 | } |
921 | |
922 | case PIO_CMAP: |
923 | if (!perm) |
924 | return -EPERM; |
925 | return con_set_cmap(up); |
926 | |
927 | case GIO_CMAP: |
928 | return con_get_cmap(up); |
929 | |
930 | case PIO_FONTX: |
931 | case GIO_FONTX: |
932 | return do_fontx_ioctl(cmd, up, perm, &op); |
933 | |
934 | case PIO_FONTRESET: |
935 | { |
936 | if (!perm) |
937 | return -EPERM; |
938 | |
939 | #ifdef BROKEN_GRAPHICS_PROGRAMS |
940 | /* With BROKEN_GRAPHICS_PROGRAMS defined, the default |
941 | font is not saved. */ |
942 | return -ENOSYS; |
943 | #else |
944 | { |
945 | op.op = KD_FONT_OP_SET_DEFAULT; |
946 | op.data = NULL; |
947 | i = con_font_op(vc_cons[fg_console].d, &op); |
948 | if (i) |
949 | return i; |
950 | con_set_default_unimap(vc_cons[fg_console].d); |
951 | return 0; |
952 | } |
953 | #endif |
954 | } |
955 | |
956 | case KDFONTOP: { |
957 | if (copy_from_user(&op, up, sizeof(op))) |
958 | return -EFAULT; |
959 | if (!perm && op.op != KD_FONT_OP_GET) |
960 | return -EPERM; |
961 | i = con_font_op(vc, &op); |
962 | if (i) return i; |
963 | if (copy_to_user(up, &op, sizeof(op))) |
964 | return -EFAULT; |
965 | return 0; |
966 | } |
967 | |
968 | case PIO_SCRNMAP: |
969 | if (!perm) |
970 | return -EPERM; |
971 | return con_set_trans_old(up); |
972 | |
973 | case GIO_SCRNMAP: |
974 | return con_get_trans_old(up); |
975 | |
976 | case PIO_UNISCRNMAP: |
977 | if (!perm) |
978 | return -EPERM; |
979 | return con_set_trans_new(up); |
980 | |
981 | case GIO_UNISCRNMAP: |
982 | return con_get_trans_new(up); |
983 | |
984 | case PIO_UNIMAPCLR: |
985 | { struct unimapinit ui; |
986 | if (!perm) |
987 | return -EPERM; |
988 | i = copy_from_user(&ui, up, sizeof(struct unimapinit)); |
989 | if (i) return -EFAULT; |
990 | con_clear_unimap(vc, &ui); |
991 | return 0; |
992 | } |
993 | |
994 | case PIO_UNIMAP: |
995 | case GIO_UNIMAP: |
996 | return do_unimap_ioctl(cmd, up, perm, vc); |
997 | |
998 | case VT_LOCKSWITCH: |
999 | if (!capable(CAP_SYS_TTY_CONFIG)) |
1000 | return -EPERM; |
1001 | vt_dont_switch = 1; |
1002 | return 0; |
1003 | case VT_UNLOCKSWITCH: |
1004 | if (!capable(CAP_SYS_TTY_CONFIG)) |
1005 | return -EPERM; |
1006 | vt_dont_switch = 0; |
1007 | return 0; |
1008 | default: |
1009 | return -ENOIOCTLCMD; |
1010 | } |
1011 | } |
1012 | |
1013 | /* |
1014 | * Sometimes we want to wait until a particular VT has been activated. We |
1015 | * do it in a very simple manner. Everybody waits on a single queue and |
1016 | * get woken up at once. Those that are satisfied go on with their business, |
1017 | * while those not ready go back to sleep. Seems overkill to add a wait |
1018 | * to each vt just for this - usually this does nothing! |
1019 | */ |
1020 | static DECLARE_WAIT_QUEUE_HEAD(vt_activate_queue); |
1021 | |
1022 | /* |
1023 | * Sleeps until a vt is activated, or the task is interrupted. Returns |
1024 | * 0 if activation, -EINTR if interrupted. |
1025 | */ |
1026 | int vt_waitactive(int vt) |
1027 | { |
1028 | int retval; |
1029 | DECLARE_WAITQUEUE(wait, current); |
1030 | |
1031 | add_wait_queue(&vt_activate_queue, &wait); |
1032 | for (;;) { |
1033 | set_current_state(TASK_INTERRUPTIBLE); |
1034 | retval = 0; |
1035 | if (vt == fg_console) |
1036 | break; |
1037 | retval = -EINTR; |
1038 | if (signal_pending(current)) |
1039 | break; |
1040 | schedule(); |
1041 | } |
1042 | remove_wait_queue(&vt_activate_queue, &wait); |
1043 | current->state = TASK_RUNNING; |
1044 | return retval; |
1045 | } |
1046 | |
1047 | #define vt_wake_waitactive() wake_up(&vt_activate_queue) |
1048 | |
1049 | void reset_vc(struct vc_data *vc) |
1050 | { |
1051 | vc->vc_mode = KD_TEXT; |
1052 | kbd_table[vc->vc_num].kbdmode = VC_XLATE; |
1053 | vc->vt_mode.mode = VT_AUTO; |
1054 | vc->vt_mode.waitv = 0; |
1055 | vc->vt_mode.relsig = 0; |
1056 | vc->vt_mode.acqsig = 0; |
1057 | vc->vt_mode.frsig = 0; |
1058 | vc->vt_pid = -1; |
1059 | vc->vt_newvt = -1; |
1060 | if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */ |
1061 | reset_palette(vc); |
1062 | } |
1063 | |
1064 | /* |
1065 | * Performs the back end of a vt switch |
1066 | */ |
1067 | static void complete_change_console(struct vc_data *vc) |
1068 | { |
1069 | unsigned char old_vc_mode; |
1070 | |
1071 | last_console = fg_console; |
1072 | |
1073 | /* |
1074 | * If we're switching, we could be going from KD_GRAPHICS to |
1075 | * KD_TEXT mode or vice versa, which means we need to blank or |
1076 | * unblank the screen later. |
1077 | */ |
1078 | old_vc_mode = vc_cons[fg_console].d->vc_mode; |
1079 | switch_screen(vc); |
1080 | |
1081 | /* |
1082 | * This can't appear below a successful kill_proc(). If it did, |
1083 | * then the *blank_screen operation could occur while X, having |
1084 | * received acqsig, is waking up on another processor. This |
1085 | * condition can lead to overlapping accesses to the VGA range |
1086 | * and the framebuffer (causing system lockups). |
1087 | * |
1088 | * To account for this we duplicate this code below only if the |
1089 | * controlling process is gone and we've called reset_vc. |
1090 | */ |
1091 | if (old_vc_mode != vc->vc_mode) { |
1092 | if (vc->vc_mode == KD_TEXT) |
1093 | do_unblank_screen(1); |
1094 | else |
1095 | do_blank_screen(1); |
1096 | } |
1097 | |
1098 | /* |
1099 | * If this new console is under process control, send it a signal |
1100 | * telling it that it has acquired. Also check if it has died and |
1101 | * clean up (similar to logic employed in change_console()) |
1102 | */ |
1103 | if (vc->vt_mode.mode == VT_PROCESS) { |
1104 | /* |
1105 | * Send the signal as privileged - kill_proc() will |
1106 | * tell us if the process has gone or something else |
1107 | * is awry |
1108 | */ |
1109 | if (kill_proc(vc->vt_pid, vc->vt_mode.acqsig, 1) != 0) { |
1110 | /* |
1111 | * The controlling process has died, so we revert back to |
1112 | * normal operation. In this case, we'll also change back |
1113 | * to KD_TEXT mode. I'm not sure if this is strictly correct |
1114 | * but it saves the agony when the X server dies and the screen |
1115 | * remains blanked due to KD_GRAPHICS! It would be nice to do |
1116 | * this outside of VT_PROCESS but there is no single process |
1117 | * to account for and tracking tty count may be undesirable. |
1118 | */ |
1119 | reset_vc(vc); |
1120 | |
1121 | if (old_vc_mode != vc->vc_mode) { |
1122 | if (vc->vc_mode == KD_TEXT) |
1123 | do_unblank_screen(1); |
1124 | else |
1125 | do_blank_screen(1); |
1126 | } |
1127 | } |
1128 | } |
1129 | |
1130 | /* |
1131 | * Wake anyone waiting for their VT to activate |
1132 | */ |
1133 | vt_wake_waitactive(); |
1134 | return; |
1135 | } |
1136 | |
1137 | /* |
1138 | * Performs the front-end of a vt switch |
1139 | */ |
1140 | void change_console(struct vc_data *new_vc) |
1141 | { |
1142 | struct vc_data *vc; |
1143 | |
1144 | if (!new_vc || new_vc->vc_num == fg_console || vt_dont_switch) |
1145 | return; |
1146 | |
1147 | /* |
1148 | * If this vt is in process mode, then we need to handshake with |
1149 | * that process before switching. Essentially, we store where that |
1150 | * vt wants to switch to and wait for it to tell us when it's done |
1151 | * (via VT_RELDISP ioctl). |
1152 | * |
1153 | * We also check to see if the controlling process still exists. |
1154 | * If it doesn't, we reset this vt to auto mode and continue. |
1155 | * This is a cheap way to track process control. The worst thing |
1156 | * that can happen is: we send a signal to a process, it dies, and |
1157 | * the switch gets "lost" waiting for a response; hopefully, the |
1158 | * user will try again, we'll detect the process is gone (unless |
1159 | * the user waits just the right amount of time :-) and revert the |
1160 | * vt to auto control. |
1161 | */ |
1162 | vc = vc_cons[fg_console].d; |
1163 | if (vc->vt_mode.mode == VT_PROCESS) { |
1164 | /* |
1165 | * Send the signal as privileged - kill_proc() will |
1166 | * tell us if the process has gone or something else |
1167 | * is awry |
1168 | */ |
1169 | if (kill_proc(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) { |
1170 | /* |
1171 | * It worked. Mark the vt to switch to and |
1172 | * return. The process needs to send us a |
1173 | * VT_RELDISP ioctl to complete the switch. |
1174 | */ |
1175 | vc->vt_newvt = new_vc->vc_num; |
1176 | return; |
1177 | } |
1178 | |
1179 | /* |
1180 | * The controlling process has died, so we revert back to |
1181 | * normal operation. In this case, we'll also change back |
1182 | * to KD_TEXT mode. I'm not sure if this is strictly correct |
1183 | * but it saves the agony when the X server dies and the screen |
1184 | * remains blanked due to KD_GRAPHICS! It would be nice to do |
1185 | * this outside of VT_PROCESS but there is no single process |
1186 | * to account for and tracking tty count may be undesirable. |
1187 | */ |
1188 | reset_vc(vc); |
1189 | |
1190 | /* |
1191 | * Fall through to normal (VT_AUTO) handling of the switch... |
1192 | */ |
1193 | } |
1194 | |
1195 | /* |
1196 | * Ignore all switches in KD_GRAPHICS+VT_AUTO mode |
1197 | */ |
1198 | if (vc->vc_mode == KD_GRAPHICS) |
1199 | return; |
1200 | |
1201 | complete_change_console(new_vc); |
1202 | } |