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 + -
显示快捷键?