📄 vt.c
字号:
/* * To have permissions to do most of the vt ioctls, we either have * to be the owner of the tty, or super-user. */ perm = 0; if (current->tty == tty || suser()) perm = 1; kbd = kbd_table + console; switch (cmd) { case KIOCSOUND: if (!perm) return -EPERM; if (arg) arg = 1193180 / arg; kd_mksound(arg, 0); return 0; case KDMKTONE: if (!perm) return -EPERM; { unsigned int ticks, count; /* * Generate the tone for the appropriate number of ticks. * If the time is zero, turn off sound ourselves. */ ticks = HZ * ((arg >> 16) & 0xffff) / 1000; count = ticks ? (arg & 0xffff) : 0; if (count) count = 1193180 / count; kd_mksound(count, ticks); return 0; } case KDGKBTYPE: /* * this is naive. */ ucval = keyboard_type; goto setchar;#ifndef __alpha__ /* * These cannot be implemented on any machine that implements * ioperm() in user level (such as Alpha PCs). */ case KDADDIO: case KDDELIO: /* * KDADDIO and KDDELIO may be able to add ports beyond what * 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 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... */ 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 (vt_cons[console]->vc_mode == (unsigned char) arg) return 0; vt_cons[console]->vc_mode = (unsigned char) arg; if (console != fg_console) return 0; /* * explicitly blank/unblank the screen if switching modes */ if (arg == KD_TEXT) unblank_screen(); else do_blank_screen(1); return 0; case KDGETMODE: ucval = vt_cons[console]->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; } if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(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 *)arg); case KDGETKEYCODE: case KDSETKEYCODE: return do_kbkeycode_ioctl(cmd, (struct kbkeycode *)arg, perm); case KDGKBENT: case KDSKBENT: return do_kdsk_ioctl(cmd, (struct kbentry *)arg, perm, kbd); case KDGKBSENT: case KDSKBSENT: return do_kdgkb_ioctl(cmd, (struct kbsentry *)arg, perm); case KDGKBDIACR: { struct kbdiacrs *a = (struct kbdiacrs *)arg; if (put_user(accent_table_size, &a->kb_cnt)) return -EFAULT; if (copy_to_user(a->kbdiacr, accent_table, accent_table_size*sizeof(struct kbdiacr))) return -EFAULT; return 0; } case KDSKBDIACR: { struct kbdiacrs *a = (struct kbdiacrs *)arg; 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->kbdiacr, ct*sizeof(struct kbdiacr))) 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*)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. * Probably init should be changed to do this (and have a * field ks (`keyboard signal') in inittab describing the * desired action), so that the number of background daemons * does not increase. */ case KDSIGACCEPT: { extern int spawnpid, spawnsig; if (!perm) return -EPERM; if (arg < 1 || arg > _NSIG || arg == SIGKILL) return -EINVAL; spawnpid = current->pid; spawnsig = arg; return 0; } case VT_SETMODE: { struct vt_mode tmp; if (!perm) return -EPERM; if (copy_from_user(&tmp, (void*)arg, sizeof(struct vt_mode))) return -EFAULT; if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) return -EINVAL; vt_cons[console]->vt_mode = tmp; /* the frsig is ignored, so we set it to 0 */ vt_cons[console]->vt_mode.frsig = 0; vt_cons[console]->vt_pid = current->pid; /* no switch is required -- saw@shade.msu.ru */ vt_cons[console]->vt_newvt = -1; return 0; } case VT_GETMODE: return copy_to_user((void*)arg, &(vt_cons[console]->vt_mode), sizeof(struct vt_mode)) ? -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 *vtstat = (struct vt_stat *)arg; unsigned short state, mask; i = verify_area(VERIFY_WRITE,(void *)vtstat, sizeof(struct vt_stat)); if (i) return i; put_user(fg_console + 1, &vtstat->v_active); 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--; i = vc_allocate(arg); 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 (vt_cons[console]->vt_mode.mode != VT_PROCESS) return -EINVAL; /* * Switching-from response */ if (vt_cons[console]->vt_newvt >= 0) { if (arg == 0) /* * Switch disallowed, so forget we were trying * to do it. */ vt_cons[console]->vt_newvt = -1; else { /* * The current vt has been released, so * complete the switch. */ int newvt = vt_cons[console]->vt_newvt; vt_cons[console]->vt_newvt = -1; i = vc_allocate(newvt); if (i) return i; /* * When we actually do the console switch, * make sure we are atomic with respect to * other console switches.. */ start_bh_atomic(); complete_change_console(newvt); end_bh_atomic(); } } /* * Switched-to response */ else { /* * If it's just an ACK, ignore it */ if (arg != VT_ACKACQ) return -EINVAL; } return 0; /* * Disallocate memory associated to VT (but leave VT1) */ case VT_DISALLOCATE: if (arg > MAX_NR_CONSOLES) return -ENXIO; if (arg == 0) { /* disallocate all unused consoles, but leave 0 */ for (i=1; i<MAX_NR_CONSOLES; i++) if (! VT_BUSY(i)) vc_disallocate(i); } else { /* disallocate a single console, if possible */ arg--; if (VT_BUSY(arg)) return -EBUSY; if (arg) /* leave 0 */ vc_disallocate(arg); } return 0; case VT_RESIZE: { struct vt_sizes *vtsizes = (struct vt_sizes *) arg; ushort ll,cc; if (!perm) return -EPERM; i = verify_area(VERIFY_READ, (void *)vtsizes, sizeof(struct vt_sizes)); if (i)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -