root/kernel/chr_drv/tty_ioctl.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. flush
  2. flush_input
  3. flush_output
  4. wait_until_sent
  5. do_get_ps_info
  6. get_termios
  7. set_termios
  8. get_termio
  9. set_termio
  10. set_window_size
  11. get_window_size
  12. tty_ioctl

   1 /*
   2  *  linux/kernel/chr_drv/tty_ioctl.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  */
   6 
   7 #include <linux/types.h>
   8 #include <linux/termios.h>
   9 #include <linux/errno.h>
  10 #include <linux/sched.h>
  11 #include <linux/kernel.h>
  12 #include <linux/tty.h>
  13 #include <linux/fcntl.h>
  14 
  15 #include <asm/io.h>
  16 #include <asm/segment.h>
  17 #include <asm/system.h>
  18 
  19 extern int session_of_pgrp(int pgrp);
  20 extern int do_screendump(int arg);
  21 extern int kill_pg(int pgrp, int sig, int priv);
  22 extern int vt_ioctl(struct tty_struct *tty, int dev, int cmd, int arg);
  23 
  24 static void flush(struct tty_queue * queue)
     /* [previous][next][first][last][top][bottom][index][help] */
  25 {
  26         if (queue) {
  27                 cli();
  28                 queue->head = queue->tail;
  29                 sti();
  30                 wake_up(&queue->proc_list);
  31         }
  32 }
  33 
  34 void flush_input(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
  35 {
  36         if (tty->read_q) {
  37                 flush(tty->read_q);
  38                 wake_up(&tty->read_q->proc_list);
  39         }
  40         if (tty->secondary) {
  41                 flush(tty->secondary);
  42                 tty->secondary->data = 0;
  43         }
  44         if ((tty = tty->link) && tty->write_q) {
  45                 flush(tty->write_q);
  46                 wake_up(&tty->write_q->proc_list);
  47         }
  48 }
  49 
  50 void flush_output(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
  51 {
  52         if (tty->write_q) {
  53                 flush(tty->write_q);
  54                 wake_up(&tty->write_q->proc_list);
  55         }
  56         if (tty = tty->link) {
  57                 if (tty->read_q) {
  58                         flush(tty->read_q);
  59                         wake_up(&tty->read_q->proc_list);
  60                 }
  61                 if (tty->secondary) {
  62                         flush(tty->secondary);
  63                         tty->secondary->data = 0;
  64                 }
  65         }
  66 }
  67 
  68 void wait_until_sent(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
  69 {
  70         while (!(current->signal & ~current->blocked) && !EMPTY(tty->write_q)) {
  71                 TTY_WRITE_FLUSH(tty);
  72                 current->counter = 0;
  73                 cli();
  74                 if (EMPTY(tty->write_q))
  75                         break;
  76                 else
  77                         interruptible_sleep_on(&tty->write_q->proc_list);
  78                 sti();
  79         }
  80         sti();
  81 }
  82 
  83 static int do_get_ps_info(int arg)
     /* [previous][next][first][last][top][bottom][index][help] */
  84 {
  85         struct tstruct {
  86                 int flag;
  87                 int present[NR_TASKS];
  88                 struct task_struct tasks[NR_TASKS];
  89         };
  90         struct tstruct *ts = (struct tstruct *)arg;
  91         struct task_struct **p;
  92         char *c, *d;
  93         int i, n = 0;
  94         
  95         verify_area((void *)arg, sizeof(struct tstruct));
  96                 
  97         for (p = &FIRST_TASK ; p <= &LAST_TASK ; p++, n++)
  98                 if (*p)
  99                 {
 100                         c = (char *)(*p);
 101                         d = (char *)(ts->tasks+n);
 102                         for (i=0 ; i<sizeof(struct task_struct) ; i++)
 103                                 put_fs_byte(*c++, d++);
 104                         put_fs_long(1, (unsigned long *)(ts->present+n));
 105                 }
 106                 else    
 107                         put_fs_long(0, (unsigned long *)(ts->present+n));
 108         return(0);                      
 109 }
 110 
 111 static int get_termios(struct tty_struct * tty, struct termios * termios)
     /* [previous][next][first][last][top][bottom][index][help] */
 112 {
 113         int i;
 114 
 115         verify_area(termios, sizeof (*termios));
 116         for (i=0 ; i< (sizeof (*termios)) ; i++)
 117                 put_fs_byte( ((char *)&tty->termios)[i] , i+(char *)termios );
 118         return 0;
 119 }
 120 
 121 static int set_termios(struct tty_struct * tty, struct termios * termios,
     /* [previous][next][first][last][top][bottom][index][help] */
 122                         int channel)
 123 {
 124         int i;
 125         unsigned short old_cflag = tty->termios.c_cflag;
 126 
 127         /* If we try to set the state of terminal and we're not in the
 128            foreground, send a SIGTTOU.  If the signal is blocked or
 129            ignored, go ahead and perform the operation.  POSIX 7.2) */
 130         if ((current->tty == channel) &&
 131              (tty->pgrp != current->pgrp)) {
 132                 if (is_orphaned_pgrp(current->pgrp))
 133                         return -EIO;
 134                 if (!is_ignored(SIGTTOU))
 135                         return tty_signal(SIGTTOU, tty);
 136         }
 137         for (i=0 ; i< (sizeof (*termios)) ; i++)
 138                 ((char *)&tty->termios)[i]=get_fs_byte(i+(char *)termios);
 139         if (IS_A_SERIAL(channel) && tty->termios.c_cflag != old_cflag)
 140                 change_speed(channel-64);
 141         return 0;
 142 }
 143 
 144 static int get_termio(struct tty_struct * tty, struct termio * termio)
     /* [previous][next][first][last][top][bottom][index][help] */
 145 {
 146         int i;
 147         struct termio tmp_termio;
 148 
 149         verify_area(termio, sizeof (*termio));
 150         tmp_termio.c_iflag = tty->termios.c_iflag;
 151         tmp_termio.c_oflag = tty->termios.c_oflag;
 152         tmp_termio.c_cflag = tty->termios.c_cflag;
 153         tmp_termio.c_lflag = tty->termios.c_lflag;
 154         tmp_termio.c_line = tty->termios.c_line;
 155         for(i=0 ; i < NCC ; i++)
 156                 tmp_termio.c_cc[i] = tty->termios.c_cc[i];
 157         for (i=0 ; i< (sizeof (*termio)) ; i++)
 158                 put_fs_byte( ((char *)&tmp_termio)[i] , i+(char *)termio );
 159         return 0;
 160 }
 161 
 162 /*
 163  * This only works as the 386 is low-byte-first
 164  */
 165 static int set_termio(struct tty_struct * tty, struct termio * termio,
     /* [previous][next][first][last][top][bottom][index][help] */
 166                         int channel)
 167 {
 168         int i;
 169         struct termio tmp_termio;
 170         unsigned short old_cflag = tty->termios.c_cflag;
 171 
 172         if ((current->tty == channel) &&
 173             (tty->pgrp > 0) &&
 174             (tty->pgrp != current->pgrp)) {
 175                 if (is_orphaned_pgrp(current->pgrp))
 176                         return -EIO;
 177                 if (!is_ignored(SIGTTOU))
 178                         return tty_signal(SIGTTOU, tty);
 179         }
 180         for (i=0 ; i< (sizeof (*termio)) ; i++)
 181                 ((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio);
 182         *(unsigned short *)&tty->termios.c_iflag = tmp_termio.c_iflag;
 183         *(unsigned short *)&tty->termios.c_oflag = tmp_termio.c_oflag;
 184         *(unsigned short *)&tty->termios.c_cflag = tmp_termio.c_cflag;
 185         *(unsigned short *)&tty->termios.c_lflag = tmp_termio.c_lflag;
 186         tty->termios.c_line = tmp_termio.c_line;
 187         for(i=0 ; i < NCC ; i++)
 188                 tty->termios.c_cc[i] = tmp_termio.c_cc[i];
 189         if (IS_A_SERIAL(channel) && tty->termios.c_cflag != old_cflag)
 190                 change_speed(channel-64);
 191         return 0;
 192 }
 193 
 194 static int set_window_size(struct tty_struct * tty, struct winsize * ws)
     /* [previous][next][first][last][top][bottom][index][help] */
 195 {
 196         int i,changed;
 197         char c, * tmp;
 198 
 199         if (!ws)
 200                 return -EINVAL;
 201         tmp = (char *) &tty->winsize;
 202         changed = 0;
 203         for (i = 0; i < sizeof (*ws) ; i++,tmp++) {
 204                 c = get_fs_byte(i + (char *) ws);
 205                 if (c == *tmp)
 206                         continue;
 207                 changed = 1;
 208                 *tmp = c;
 209         }
 210         if (changed)
 211                 kill_pg(tty->pgrp, SIGWINCH, 1);
 212         return 0;
 213 }
 214 
 215 static int get_window_size(struct tty_struct * tty, struct winsize * ws)
     /* [previous][next][first][last][top][bottom][index][help] */
 216 {
 217         int i;
 218         char * tmp;
 219 
 220         if (!ws)
 221                 return -EINVAL;
 222         verify_area(ws, sizeof (*ws));
 223         tmp = (char *) ws;
 224         for (i = 0; i < sizeof (struct winsize) ; i++,tmp++)
 225                 put_fs_byte(((char *) &tty->winsize)[i], tmp);
 226         return 0;
 227 }
 228 
 229 int tty_ioctl(struct inode * inode, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
 230         unsigned int cmd, unsigned int arg)
 231 {
 232         struct tty_struct * tty;
 233         struct tty_struct * other_tty;
 234         int pgrp;
 235         int dev;
 236 
 237         if (MAJOR(file->f_rdev) != 4) {
 238                 printk("tty_ioctl: tty pseudo-major != 4\n");
 239                 return -EINVAL;
 240         }
 241         dev = MINOR(file->f_rdev);
 242         tty = tty_table + (dev ? ((dev < 64)? dev-1:dev) : fg_console);
 243 
 244         if (IS_A_PTY(dev))
 245                 other_tty = tty_table + PTY_OTHER(dev);
 246         else
 247                 other_tty = NULL;
 248                 
 249         if (!(tty->write_q && tty->read_q && tty->secondary && tty->write))
 250                 return -EINVAL;
 251         switch (cmd) {
 252                 case TCGETS:
 253                         return get_termios(tty,(struct termios *) arg);
 254                 case TCSETSF:
 255                         flush_input(tty);
 256                 /* fallthrough */
 257                 case TCSETSW:
 258                         wait_until_sent(tty);
 259                 /* fallthrough */
 260                 case TCSETS:
 261                         return set_termios(tty,(struct termios *) arg, dev);
 262                 case TCGETA:
 263                         return get_termio(tty,(struct termio *) arg);
 264                 case TCSETAF:
 265                         flush_input(tty);
 266                 /* fallthrough */
 267                 case TCSETAW:
 268                         wait_until_sent(tty); /* fallthrough */
 269                 case TCSETA:
 270                         return set_termio(tty,(struct termio *) arg, dev);
 271                 case TCSBRK:
 272                         if (!IS_A_SERIAL(dev))
 273                                 return -EINVAL;
 274                         wait_until_sent(tty);
 275                         if (!arg)
 276                                 send_break(dev-64);
 277                         return 0;
 278                 case TCXONC:
 279                         switch (arg) {
 280                         case TCOOFF:
 281                                 tty->stopped = 1;
 282                                 TTY_WRITE_FLUSH(tty);
 283                                 return 0;
 284                         case TCOON:
 285                                 tty->stopped = 0;
 286                                 TTY_WRITE_FLUSH(tty);
 287                                 return 0;
 288                         case TCIOFF:
 289                                 if (STOP_CHAR(tty))
 290                                         put_tty_queue(STOP_CHAR(tty),tty->write_q);
 291                                 return 0;
 292                         case TCION:
 293                                 if (START_CHAR(tty))
 294                                         put_tty_queue(START_CHAR(tty),tty->write_q);
 295                                 return 0;
 296                         }
 297                         return -EINVAL; /* not implemented */
 298                 case TCFLSH:
 299                         if (arg==0)
 300                                 flush_input(tty);
 301                         else if (arg==1)
 302                                 flush_output(tty);
 303                         else if (arg==2) {
 304                                 flush_input(tty);
 305                                 flush_output(tty);
 306                         } else
 307                                 return -EINVAL;
 308                         return 0;
 309                 case TIOCEXCL:
 310                         return -EINVAL; /* not implemented */
 311                 case TIOCNXCL:
 312                         return -EINVAL; /* not implemented */
 313                 case TIOCSCTTY:
 314                         return -EINVAL; /* set controlling term NI */
 315                 case TIOCGPGRP:
 316                         verify_area((void *) arg,4);
 317                         put_fs_long(tty->pgrp,(unsigned long *) arg);
 318                         return 0;
 319                 case TIOCSPGRP:
 320                         if ((current->tty < 0) ||
 321                             (current->tty != dev) ||
 322                             (tty->session != current->session))
 323                                 return -ENOTTY;
 324                         pgrp=get_fs_long((unsigned long *) arg);
 325                         if (pgrp < 0)
 326                                 return -EINVAL;
 327                         if (session_of_pgrp(pgrp) != current->session)
 328                                 return -EPERM;
 329                         tty->pgrp = pgrp;                       
 330                         return 0;
 331                 case TIOCOUTQ:
 332                         verify_area((void *) arg,4);
 333                         put_fs_long(CHARS(tty->write_q),(unsigned long *) arg);
 334                         return 0;
 335                 case TIOCINQ:
 336                         verify_area((void *) arg,4);
 337                         if (L_CANON(tty) && !tty->secondary->data)
 338                                 put_fs_long(0, (unsigned long *) arg);
 339                         else
 340                                 put_fs_long(CHARS(tty->secondary),
 341                                         (unsigned long *) arg);
 342                         return 0;
 343                 case TIOCSTI:
 344                         return -EINVAL; /* not implemented */
 345                 case TIOCGWINSZ:
 346                         return get_window_size(tty,(struct winsize *) arg);
 347                 case TIOCSWINSZ:
 348                         if (IS_A_PTY_MASTER(dev))
 349                                 set_window_size(other_tty,(struct winsize *) arg);
 350                         return set_window_size(tty,(struct winsize *) arg);
 351                 case TIOCMGET:
 352                         return -EINVAL; /* not implemented */
 353                 case TIOCMBIS:
 354                         return -EINVAL; /* not implemented */
 355                 case TIOCMBIC:
 356                         return -EINVAL; /* not implemented */
 357                 case TIOCMSET:
 358                         return -EINVAL; /* not implemented */
 359                 case TIOCGSOFTCAR:
 360                         return -EINVAL; /* not implemented */
 361                 case TIOCSSOFTCAR:
 362                         return -EINVAL; /* not implemented */
 363                 case TIOCLINUX:
 364                         switch (get_fs_byte((char *)arg))
 365                         {
 366                                 case 0: 
 367                                         return do_screendump(arg);
 368                                 case 1: 
 369                                         return do_get_ps_info(arg);
 370                                 default: 
 371                                         return -EINVAL;
 372                         }
 373                 case TIOCCONS:
 374                         if (!IS_A_PTY(dev))
 375                                 return -EINVAL;
 376                         if (redirect)
 377                                 return -EBUSY;
 378                         if (!suser())
 379                                 return -EPERM;
 380                         if (IS_A_PTY_MASTER(dev))
 381                                 redirect = other_tty;
 382                         else
 383                                 redirect = tty;
 384                         return 0;
 385                 case TIOCGSERIAL:
 386                         if (!IS_A_SERIAL(dev))
 387                                 return -EINVAL;
 388                         verify_area((void *) arg,sizeof(struct serial_struct));
 389                         return get_serial_info(dev-64,(struct serial_struct *) arg);
 390                 case TIOCSSERIAL:
 391                         if (!IS_A_SERIAL(dev))
 392                                 return -EINVAL;
 393                         return set_serial_info(dev-64,(struct serial_struct *) arg);
 394                 case FIONBIO:
 395                         if (arg)
 396                                 file->f_flags |= O_NONBLOCK;
 397                         else
 398                                 file->f_flags &= ~O_NONBLOCK;
 399                         return 0;
 400                 case TIOCNOTTY:
 401                         if (MINOR(file->f_rdev) != current->tty)
 402                                 return -EINVAL;
 403                         current->tty = -1;
 404                         if (current->leader) {
 405                                 if (tty->pgrp > 0)
 406                                         kill_pg(tty->pgrp, SIGHUP, 0);
 407                                 tty->pgrp = -1;
 408                                 tty->session = 0;
 409                         }
 410                         return 0;
 411                 default:
 412                         return vt_ioctl(tty, dev, cmd, arg);
 413         }
 414 }

/* [previous][next][first][last][top][bottom][index][help] */