vt_ioctl.c
来自「linux 内核源代码」· C语言 代码 · 共 1,305 行 · 第 1/3 页
C
1,305 行
* we reject here, but to be safe... */ if (arg < GPFIRST || arg > GPLAST) return -EINVAL; return sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0; case KDENABIO: case KDDISABIO: return sys_ioperm(GPFIRST, GPNUM, (cmd == KDENABIO)) ? -ENXIO : 0;#endif /* Linux m68k/i386 interface for setting the keyboard delay/repeat rate */ case KDKBDREP: { struct kbd_repeat kbrep; int err; if (!capable(CAP_SYS_TTY_CONFIG)) return -EPERM; if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) return -EFAULT; err = kbd_rate(&kbrep); if (err) return err; if (copy_to_user(up, &kbrep, sizeof(struct kbd_repeat))) return -EFAULT; return 0; } case KDSETMODE: /* * currently, setting the mode from KD_TEXT to KD_GRAPHICS * doesn't do a whole lot. i'm not sure if it should do any * restoration of modes or what... * * XXX It should at least call into the driver, fbdev's definitely * need to restore their engine state. --BenH */ if (!perm) return -EPERM; switch (arg) { case KD_GRAPHICS: break; case KD_TEXT0: case KD_TEXT1: arg = KD_TEXT; case KD_TEXT: break; default: return -EINVAL; } if (vc->vc_mode == (unsigned char) arg) return 0; vc->vc_mode = (unsigned char) arg; if (console != fg_console) return 0; /* * explicitly blank/unblank the screen if switching modes */ acquire_console_sem(); if (arg == KD_TEXT) do_unblank_screen(1); else do_blank_screen(1); release_console_sem(); return 0; case KDGETMODE: ucval = vc->vc_mode; goto setint; case KDMAPDISP: case KDUNMAPDISP: /* * these work like a combination of mmap and KDENABIO. * this could be easily finished. */ return -EINVAL; case KDSKBMODE: if (!perm) return -EPERM; switch(arg) { case K_RAW: kbd->kbdmode = VC_RAW; break; case K_MEDIUMRAW: kbd->kbdmode = VC_MEDIUMRAW; break; case K_XLATE: kbd->kbdmode = VC_XLATE; compute_shiftstate(); break; case K_UNICODE: kbd->kbdmode = VC_UNICODE; compute_shiftstate(); break; default: return -EINVAL; } tty_ldisc_flush(tty); return 0; case KDGKBMODE: ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW : (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW : (kbd->kbdmode == VC_UNICODE) ? K_UNICODE : K_XLATE); goto setint; /* this could be folded into KDSKBMODE, but for compatibility reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */ case KDSKBMETA: switch(arg) { case K_METABIT: clr_vc_kbd_mode(kbd, VC_META); break; case K_ESCPREFIX: set_vc_kbd_mode(kbd, VC_META); break; default: return -EINVAL; } return 0; case KDGKBMETA: ucval = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT); setint: return put_user(ucval, (int __user *)arg); case KDGETKEYCODE: case KDSETKEYCODE: if(!capable(CAP_SYS_TTY_CONFIG)) perm=0; return do_kbkeycode_ioctl(cmd, up, perm); case KDGKBENT: case KDSKBENT: return do_kdsk_ioctl(cmd, up, perm, kbd); case KDGKBSENT: case KDSKBSENT: return do_kdgkb_ioctl(cmd, up, perm); case KDGKBDIACR: { struct kbdiacrs __user *a = up; struct kbdiacr diacr; int i; if (put_user(accent_table_size, &a->kb_cnt)) return -EFAULT; for (i = 0; i < accent_table_size; i++) { diacr.diacr = conv_uni_to_8bit(accent_table[i].diacr); diacr.base = conv_uni_to_8bit(accent_table[i].base); diacr.result = conv_uni_to_8bit(accent_table[i].result); if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) return -EFAULT; } return 0; } case KDGKBDIACRUC: { struct kbdiacrsuc __user *a = up; if (put_user(accent_table_size, &a->kb_cnt)) return -EFAULT; if (copy_to_user(a->kbdiacruc, accent_table, accent_table_size*sizeof(struct kbdiacruc))) return -EFAULT; return 0; } case KDSKBDIACR: { struct kbdiacrs __user *a = up; struct kbdiacr diacr; unsigned int ct; int i; if (!perm) return -EPERM; if (get_user(ct,&a->kb_cnt)) return -EFAULT; if (ct >= MAX_DIACR) return -EINVAL; accent_table_size = ct; for (i = 0; i < ct; i++) { if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) return -EFAULT; accent_table[i].diacr = conv_8bit_to_uni(diacr.diacr); accent_table[i].base = conv_8bit_to_uni(diacr.base); accent_table[i].result = conv_8bit_to_uni(diacr.result); } return 0; } case KDSKBDIACRUC: { struct kbdiacrsuc __user *a = up; unsigned int ct; if (!perm) return -EPERM; if (get_user(ct,&a->kb_cnt)) return -EFAULT; if (ct >= MAX_DIACR) return -EINVAL; accent_table_size = ct; if (copy_from_user(accent_table, a->kbdiacruc, ct*sizeof(struct kbdiacruc))) return -EFAULT; return 0; } /* the ioctls below read/set the flags usually shown in the leds */ /* don't use them - they will go away without warning */ case KDGKBLED: ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4); goto setchar; case KDSKBLED: if (!perm) return -EPERM; if (arg & ~0x77) return -EINVAL; kbd->ledflagstate = (arg & 7); kbd->default_ledflagstate = ((arg >> 4) & 7); set_leds(); return 0; /* the ioctls below only set the lights, not the functions */ /* for those, see KDGKBLED and KDSKBLED above */ case KDGETLED: ucval = getledstate(); setchar: return put_user(ucval, (char __user *)arg); case KDSETLED: if (!perm) return -EPERM; setledstate(kbd, arg); return 0; /* * A process can indicate its willingness to accept signals * generated by pressing an appropriate key combination. * Thus, one can have a daemon that e.g. spawns a new console * upon a keypress and then changes to it. * See also the kbrequest field of inittab(5). */ case KDSIGACCEPT: { if (!perm || !capable(CAP_KILL)) return -EPERM; if (!valid_signal(arg) || arg < 1 || arg == SIGKILL) return -EINVAL; spin_lock_irq(&vt_spawn_con.lock); put_pid(vt_spawn_con.pid); vt_spawn_con.pid = get_pid(task_pid(current)); vt_spawn_con.sig = arg; spin_unlock_irq(&vt_spawn_con.lock); return 0; } case VT_SETMODE: { struct vt_mode tmp; if (!perm) return -EPERM; if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) return -EFAULT; if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) return -EINVAL; acquire_console_sem(); vc->vt_mode = tmp; /* the frsig is ignored, so we set it to 0 */ vc->vt_mode.frsig = 0; put_pid(vc->vt_pid); vc->vt_pid = get_pid(task_pid(current)); /* no switch is required -- saw@shade.msu.ru */ vc->vt_newvt = -1; release_console_sem(); return 0; } case VT_GETMODE: { struct vt_mode tmp; int rc; acquire_console_sem(); memcpy(&tmp, &vc->vt_mode, sizeof(struct vt_mode)); release_console_sem(); rc = copy_to_user(up, &tmp, sizeof(struct vt_mode)); return rc ? -EFAULT : 0; } /* * Returns global vt state. Note that VT 0 is always open, since * it's an alias for the current VT, and people can't use it here. * We cannot return state for more than 16 VTs, since v_state is short. */ case VT_GETSTATE: { struct vt_stat __user *vtstat = up; unsigned short state, mask; if (put_user(fg_console + 1, &vtstat->v_active)) return -EFAULT; state = 1; /* /dev/tty0 is always open */ for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1) if (VT_IS_IN_USE(i)) state |= mask; return put_user(state, &vtstat->v_state); } /* * Returns the first available (non-opened) console. */ case VT_OPENQRY: for (i = 0; i < MAX_NR_CONSOLES; ++i) if (! VT_IS_IN_USE(i)) break; ucval = i < MAX_NR_CONSOLES ? (i+1) : -1; goto setint; /* * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num, * with num >= 1 (switches to vt 0, our console, are not allowed, just * to preserve sanity). */ case VT_ACTIVATE: if (!perm) return -EPERM; if (arg == 0 || arg > MAX_NR_CONSOLES) return -ENXIO; arg--; acquire_console_sem(); i = vc_allocate(arg); release_console_sem(); if (i) return i; set_console(arg); return 0; /* * wait until the specified VT has been activated */ case VT_WAITACTIVE: if (!perm) return -EPERM; if (arg == 0 || arg > MAX_NR_CONSOLES) return -ENXIO; return vt_waitactive(arg-1); /* * If a vt is under process control, the kernel will not switch to it * immediately, but postpone the operation until the process calls this * ioctl, allowing the switch to complete. * * According to the X sources this is the behavior: * 0: pending switch-from not OK * 1: pending switch-from OK * 2: completed switch-to OK */ case VT_RELDISP: if (!perm) return -EPERM; if (vc->vt_mode.mode != VT_PROCESS) return -EINVAL; /* * Switching-from response */ acquire_console_sem(); if (vc->vt_newvt >= 0) { if (arg == 0) /* * Switch disallowed, so forget we were trying * to do it. */ vc->vt_newvt = -1; else { /* * The current vt has been released, so * complete the switch. */ int newvt; newvt = vc->vt_newvt; vc->vt_newvt = -1; i = vc_allocate(newvt); if (i) { release_console_sem(); return i; } /* * When we actually do the console switch, * make sure we are atomic with respect to * other console switches.. */ complete_change_console(vc_cons[newvt].d); } } /* * Switched-to response */ else { /* * If it's just an ACK, ignore it */ if (arg != VT_ACKACQ) { release_console_sem(); return -EINVAL; } } release_console_sem(); return 0; /* * Disallocate memory associated to VT (but leave VT1) */ case VT_DISALLOCATE: if (arg > MAX_NR_CONSOLES) return -ENXIO; if (arg == 0) { /* deallocate all unused consoles, but leave 0 */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?