📄 tty_io.c
字号:
if (retval) return retval; ch = get_user((char *) arg); tty->ldisc.receive_buf(tty, &ch, &mbz, 1); return 0; case TIOCGWINSZ: retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof (struct winsize)); if (retval) return retval; memcpy_tofs((struct winsize *) arg, &tty->winsize, sizeof (struct winsize)); return 0; case TIOCSWINSZ: retval = verify_area(VERIFY_READ, (void *) arg, sizeof (struct winsize)); if (retval) return retval; memcpy_fromfs(&tmp_ws, (struct winsize *) arg, sizeof (struct winsize)); if (memcmp(&tmp_ws, &tty->winsize, sizeof(struct winsize))) { if (tty->pgrp > 0) kill_pg(tty->pgrp, SIGWINCH, 1); if ((real_tty->pgrp != tty->pgrp) && (real_tty->pgrp > 0)) kill_pg(real_tty->pgrp, SIGWINCH, 1); } tty->winsize = tmp_ws; real_tty->winsize = tmp_ws; return 0; case TIOCCONS: if (tty->driver.type == TTY_DRIVER_TYPE_CONSOLE) { if (!suser()) return -EPERM; redirect = NULL; return 0; } if (redirect) return -EBUSY; redirect = real_tty; return 0; case FIONBIO: retval = verify_area(VERIFY_READ, (void *) arg, sizeof(int)); if (retval) return retval; arg = get_user((unsigned int *) arg); if (arg) file->f_flags |= O_NONBLOCK; else file->f_flags &= ~O_NONBLOCK; return 0; case TIOCEXCL: set_bit(TTY_EXCLUSIVE, &tty->flags); return 0; case TIOCNXCL: clear_bit(TTY_EXCLUSIVE, &tty->flags); return 0; case TIOCNOTTY: if (current->tty != tty) return -ENOTTY; if (current->leader) disassociate_ctty(0); current->tty = NULL; return 0; case TIOCSCTTY: if (current->leader && (current->session == tty->session)) return 0; /* * The process must be a session leader and * not have a controlling tty already. */ if (!current->leader || current->tty) return -EPERM; if (tty->session > 0) { /* * This tty is already the controlling * tty for another session group! */ if ((arg == 1) && suser()) { /* * Steal it away */ struct task_struct *p; for_each_task(p) if (p->tty == tty) p->tty = NULL; } else return -EPERM; } current->tty = tty; current->tty_old_pgrp = 0; tty->session = current->session; tty->pgrp = current->pgrp; return 0; case TIOCGPGRP: /* * (tty == real_tty) is a cheap way of * testing if the tty is NOT a master pty. */ if (tty == real_tty && current->tty != real_tty) return -ENOTTY; retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof (pid_t)); if (retval) return retval; put_user(real_tty->pgrp, (pid_t *) arg); return 0; case TIOCSPGRP: retval = tty_check_change(real_tty); if (retval == -EIO) return -ENOTTY; if (retval) return retval; if (!current->tty || (current->tty != real_tty) || (real_tty->session != current->session)) return -ENOTTY; pgrp = get_user((pid_t *) arg); if (pgrp < 0) return -EINVAL; if (session_of_pgrp(pgrp) != current->session) return -EPERM; real_tty->pgrp = pgrp; return 0; case TIOCGETD: retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof (int)); if (retval) return retval; put_user(tty->ldisc.num, (int *) arg); return 0; case TIOCSETD: retval = tty_check_change(tty); if (retval) return retval; retval = verify_area(VERIFY_READ, (void *) arg, sizeof (int)); if (retval) return retval; arg = get_user((int *) arg); return tty_set_ldisc(tty, arg); case TIOCLINUX: if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE) return -EINVAL; if (current->tty != tty && !suser()) return -EPERM; retval = verify_area(VERIFY_READ, (void *) arg, 1); if (retval) return retval; switch (retval = get_user((char *)arg)) { case 0: case 8: case 9: printk("TIOCLINUX (0/8/9) ioctl is gone - use /dev/vcs\n"); return -EINVAL;#if 0 case 1: printk("Deprecated TIOCLINUX (1) ioctl\n"); return do_get_ps_info(arg);#endif case 2: return set_selection(arg, tty, 1); case 3: return paste_selection(tty); case 4: do_unblank_screen(); return 0; case 5: return sel_loadlut(arg); case 6: /* * Make it possible to react to Shift+Mousebutton. * Note that 'shift_state' is an undocumented * kernel-internal variable; programs not closely * related to the kernel should not use this. */ retval = verify_area(VERIFY_WRITE, (void *) arg, 1); if (retval) return retval; put_user(shift_state,(char *) arg); return 0; case 7: retval = verify_area(VERIFY_WRITE, (void *) arg, 1); if (retval) return retval; put_user(mouse_reporting(),(char *) arg); return 0; case 10: set_vesa_blanking(arg); return 0; case 11: /* set kmsg redirect */ if (!suser()) return -EPERM; retval = verify_area(VERIFY_READ, (void *) arg+1, 1); if (retval) return retval; kmsg_redirect = get_user((char *)arg+1); return 0; case 12: /* get fg_console */ return fg_console; default: return -EINVAL; } case TIOCTTYGSTRUCT: retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct tty_struct)); if (retval) return retval; memcpy_tofs((struct tty_struct *) arg, tty, sizeof(struct tty_struct)); return 0; default: if (tty->driver.ioctl) { retval = (tty->driver.ioctl)(tty, file, cmd, arg); if (retval != -ENOIOCTLCMD) return retval; } if (tty->ldisc.ioctl) { retval = (tty->ldisc.ioctl)(tty, file, cmd, arg); if (retval != -ENOIOCTLCMD) return retval; } return -EINVAL; }}/* * This implements the "Secure Attention Key" --- the idea is to * prevent trojan horses by killing all processes associated with this * tty when the user hits the "Secure Attention Key". Required for * super-paranoid applications --- see the Orange Book for more details. * * This code could be nicer; ideally it should send a HUP, wait a few * seconds, then send a INT, and then a KILL signal. But you then * have to coordinate with the init process, since all processes associated * with the current tty must be dead before the new getty is allowed * to spawn. */void do_SAK( struct tty_struct *tty){#ifdef TTY_SOFT_SAK tty_hangup(tty);#else struct task_struct **p; int session; int i; struct file *filp; if (!tty) return; session = tty->session; if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); if (tty->driver.flush_buffer) tty->driver.flush_buffer(tty); for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) { if (!(*p)) continue; if (((*p)->tty == tty) || ((session > 0) && ((*p)->session == session))) send_sig(SIGKILL, *p, 1); else if ((*p)->files) { for (i=0; i < NR_OPEN; i++) { filp = (*p)->files->fd[i]; if (filp && (filp->f_op == &tty_fops) && (filp->private_data == tty)) { send_sig(SIGKILL, *p, 1); break; } } } }#endif}/* * This routine is called out of the software interrupt to flush data * from the flip buffer to the line discipline. */static void flush_to_ldisc(void *private_){ struct tty_struct *tty = (struct tty_struct *) private_; unsigned char *cp; char *fp; int count; if (tty->flip.buf_num) { cp = tty->flip.char_buf + TTY_FLIPBUF_SIZE; fp = tty->flip.flag_buf + TTY_FLIPBUF_SIZE; tty->flip.buf_num = 0; cli(); tty->flip.char_buf_ptr = tty->flip.char_buf; tty->flip.flag_buf_ptr = tty->flip.flag_buf; } else { cp = tty->flip.char_buf; fp = tty->flip.flag_buf; tty->flip.buf_num = 1; cli(); tty->flip.char_buf_ptr = tty->flip.char_buf + TTY_FLIPBUF_SIZE; tty->flip.flag_buf_ptr = tty->flip.flag_buf + TTY_FLIPBUF_SIZE; } count = tty->flip.count; tty->flip.count = 0; sti(); #if 0 if (count > tty->max_flip_cnt) tty->max_flip_cnt = count;#endif tty->ldisc.receive_buf(tty, cp, fp, count);}/* * This subroutine initializes a tty structure. */static void initialize_tty_struct(struct tty_struct *tty){ memset(tty, 0, sizeof(struct tty_struct)); tty->magic = TTY_MAGIC; tty->ldisc = ldiscs[N_TTY]; tty->pgrp = -1; tty->flip.char_buf_ptr = tty->flip.char_buf; tty->flip.flag_buf_ptr = tty->flip.flag_buf; tty->flip.tqueue.routine = flush_to_ldisc; tty->flip.tqueue.data = tty;}/* * The default put_char routine if the driver did not define one. */void tty_default_put_char(struct tty_struct *tty, unsigned char ch){ tty->driver.write(tty, 0, &ch, 1);}/* * Called by a tty driver to register itself. */int tty_register_driver(struct tty_driver *driver){ int error; if (driver->flags & TTY_DRIVER_INSTALLED) return 0; error = register_chrdev(driver->major, driver->name, &tty_fops); if (error < 0) return error; else if(driver->major == 0) driver->major = error; if (!driver->put_char) driver->put_char = tty_default_put_char; driver->prev = 0; driver->next = tty_drivers; if (tty_drivers) tty_drivers->prev = driver; tty_drivers = driver; return error;}/* * Called by a tty driver to unregister itself. */int tty_unregister_driver(struct tty_driver *driver){ int retval; struct tty_driver *p; int found = 0; const char *othername = NULL; if (*driver->refcount) return -EBUSY; for (p = tty_drivers; p; p = p->next) { if (p == driver) found++; else if (p->major == driver->major) othername = p->name; } if (!found) return -ENOENT; if (othername == NULL) { retval = unregister_chrdev(driver->major, driver->name); if (retval) return retval; } else register_chrdev(driver->major, othername, &tty_fops); if (driver->prev) driver->prev->next = driver->next; else tty_drivers = driver->next; if (driver->next) driver->next->prev = driver->prev; return 0;}/* * Initialize the console device. This is called *early*, so * we can't necessarily depend on lots of kernel help here. * Just do some early initializations, and do the complex setup * later. */long console_init(long kmem_start, long kmem_end){ /* Setup the default TTY line discipline. */ memset(ldiscs, 0, sizeof(ldiscs)); (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY); /* * Set up the standard termios. Individual tty drivers may * deviate from this; this is used as a template. */ memset(&tty_std_termios, 0, sizeof(struct termios)); memcpy(tty_std_termios.c_cc, INIT_C_CC, NCCS); tty_std_termios.c_iflag = ICRNL | IXON; tty_std_termios.c_oflag = OPOST | ONLCR; tty_std_termios.c_cflag = B38400 | CS8 | CREAD | HUPCL; tty_std_termios.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN; /* * set up the console device so that later boot sequences can * inform about problems etc.. */ return con_init(kmem_start);}static struct tty_driver dev_tty_driver, dev_console_driver;/* * Ok, now we can initialize the rest of the tty devices and can count * on memory allocations, interrupts etc.. */int tty_init(void){ if (sizeof(struct tty_struct) > PAGE_SIZE) panic("size of tty structure > PAGE_SIZE!"); /* * dev_tty_driver and dev_console_driver are actually magic * devices which get redirected at open time. Nevertheless, * we register them so that register_chrdev is called * appropriately. */ memset(&dev_tty_driver, 0, sizeof(struct tty_driver)); dev_tty_driver.magic = TTY_DRIVER_MAGIC; dev_tty_driver.name = "tty"; dev_tty_driver.name_base = 0; dev_tty_driver.major = TTY_MAJOR; dev_tty_driver.minor_start = 0; dev_tty_driver.num = 1; if (tty_register_driver(&dev_tty_driver)) panic("Couldn't register /dev/tty driver\n"); dev_console_driver = dev_tty_driver; dev_console_driver.name = "console"; dev_console_driver.major = TTYAUX_MAJOR; if (tty_register_driver(&dev_console_driver)) panic("Couldn't register /dev/console driver\n"); kbd_init();#ifdef CONFIG_SERIAL rs_init();#endif#ifdef CONFIG_SCC scc_init();#endif#ifdef CONFIG_CYCLADES cy_init();#endif#ifdef CONFIG_STALLION stl_init();#endif#ifdef CONFIG_ISTALLION stli_init();#endif#ifdef CONFIG_DIGI pcxe_init();#endif#ifdef CONFIG_RISCOM8 riscom8_init();#endif#ifdef CONFIG_BAYCOM baycom_init();#endif#ifdef CONFIG_SPECIALIX specialix_init();#endif pty_init(); vcs_init(); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -