root/drivers/char/tty_ioctl.c

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

DEFINITIONS

This source file includes following definitions.
  1. flush_input
  2. flush_output
  3. wait_until_sent
  4. do_get_ps_info
  5. unset_locked_termios
  6. check_change
  7. set_termios_2
  8. set_termios
  9. get_termio
  10. set_termio
  11. set_window_size
  12. tty_set_ldisc
  13. inq_canon
  14. tty_ioctl

   1 /*
   2  *  linux/kernel/drivers/char/tty_ioctl.c
   3  *
   4  *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
   5  *
   6  * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
   7  * which can be dynamically activated and de-activated by the line
   8  * discipline handling modules (like SLIP).
   9  */
  10 
  11 #include <linux/types.h>
  12 #include <linux/termios.h>
  13 #include <linux/errno.h>
  14 #include <linux/sched.h>
  15 #include <linux/config.h>
  16 #include <linux/kernel.h>
  17 #include <linux/major.h>
  18 #include <linux/tty.h>
  19 #include <linux/fcntl.h>
  20 #include <linux/string.h>
  21 
  22 #include <asm/io.h>
  23 #include <asm/bitops.h>
  24 #include <asm/segment.h>
  25 #include <asm/system.h>
  26 
  27 #undef  DEBUG
  28 #ifdef DEBUG
  29 # define        PRINTK(x)       printk (x)
  30 #else
  31 # define        PRINTK(x)       /**/
  32 #endif
  33 
  34 extern int session_of_pgrp(int pgrp);
  35 extern int do_screendump(int arg);
  36 extern int kill_pg(int pgrp, int sig, int priv);
  37 
  38 #ifdef CONFIG_SELECTION
  39 extern int set_selection(const int arg);
  40 extern int paste_selection(struct tty_struct *tty);
  41 #endif /* CONFIG_SELECTION */
  42 
  43 static int tty_set_ldisc(struct tty_struct *tty, int ldisc);
  44 
  45 void flush_input(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
  46 {
  47         cli();
  48         tty->read_q.head = tty->read_q.tail = 0;
  49         tty->secondary.head = tty->secondary.tail = 0;
  50         tty->canon_head = tty->canon_data = tty->erasing = 0;
  51         memset(&tty->readq_flags, 0, sizeof tty->readq_flags);
  52         memset(&tty->secondary_flags, 0, sizeof tty->secondary_flags);
  53         sti();
  54         if (!tty->link)
  55                 return;
  56         /* No cli() since ptys don't use interrupts. */
  57         tty->link->write_q.head = tty->link->write_q.tail = 0;
  58         wake_up_interruptible(&tty->link->write_q.proc_list);
  59         if (tty->link->packet) {
  60                 tty->ctrl_status |= TIOCPKT_FLUSHREAD;
  61                 wake_up_interruptible(&tty->link->secondary.proc_list);
  62         }
  63 }
  64 
  65 void flush_output(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
  66 {
  67         cli();
  68         tty->write_q.head = tty->write_q.tail = 0;
  69         sti();
  70         wake_up_interruptible(&tty->write_q.proc_list);
  71         if (!tty->link)
  72                 return;
  73         /* No cli() since ptys don't use interrupts. */
  74         tty->link->read_q.head = tty->link->read_q.tail = 0;
  75         tty->link->secondary.head = tty->link->secondary.tail = 0;
  76         tty->link->canon_head = tty->link->canon_data = tty->link->erasing = 0;
  77         memset(&tty->link->readq_flags, 0, sizeof tty->readq_flags);
  78         memset(&tty->link->secondary_flags, 0, sizeof tty->secondary_flags);
  79         if (tty->link->packet) {
  80                 tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
  81                 wake_up_interruptible(&tty->link->secondary.proc_list);
  82         }
  83 }
  84 
  85 void wait_until_sent(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
  86 {
  87         struct wait_queue wait = { current, NULL };
  88 
  89         TTY_WRITE_FLUSH(tty);
  90         if (EMPTY(&tty->write_q))
  91                 return;
  92         add_wait_queue(&tty->write_q.proc_list, &wait);
  93         current->counter = 0;   /* make us low-priority */
  94         while (1) {
  95                 current->state = TASK_INTERRUPTIBLE;
  96                 if (current->signal & ~current->blocked)
  97                         break;
  98                 TTY_WRITE_FLUSH(tty);
  99                 if (EMPTY(&tty->write_q))
 100                         break;
 101                 schedule();
 102         }
 103         current->state = TASK_RUNNING;
 104         remove_wait_queue(&tty->write_q.proc_list, &wait);
 105 }
 106 
 107 static int do_get_ps_info(int arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 108 {
 109         struct tstruct {
 110                 int flag;
 111                 int present[NR_TASKS];
 112                 struct task_struct tasks[NR_TASKS];
 113         };
 114         struct tstruct *ts = (struct tstruct *)arg;
 115         struct task_struct **p;
 116         char *c, *d;
 117         int i, n = 0;
 118         
 119         i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct tstruct));
 120         if (i)
 121                 return i;
 122         for (p = &FIRST_TASK ; p <= &LAST_TASK ; p++, n++)
 123                 if (*p)
 124                 {
 125                         c = (char *)(*p);
 126                         d = (char *)(ts->tasks+n);
 127                         for (i=0 ; i<sizeof(struct task_struct) ; i++)
 128                                 put_fs_byte(*c++, d++);
 129                         put_fs_long(1, (unsigned long *)(ts->present+n));
 130                 }
 131                 else    
 132                         put_fs_long(0, (unsigned long *)(ts->present+n));
 133         return(0);                      
 134 }
 135 
 136 static void unset_locked_termios(struct termios *termios,
     /* [previous][next][first][last][top][bottom][index][help] */
 137                                  struct termios *old,
 138                                  struct termios *locked)
 139 {
 140         int     i;
 141         
 142 #define NOSET_MASK(x,y,z) (x = ((x) & ~(z)) | ((y) & (z)))
 143 
 144         if (!locked) {
 145                 printk("Warning?!? termios_locked is NULL.\n");
 146                 return;
 147         }
 148 
 149         NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
 150         NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
 151         NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
 152         NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
 153         termios->c_line = locked->c_line ? old->c_line : termios->c_line;
 154         for (i=0; i < NCCS; i++)
 155                 termios->c_cc[i] = locked->c_cc[i] ?
 156                         old->c_cc[i] : termios->c_cc[i];
 157 }
 158 
 159 int check_change(struct tty_struct * tty, int channel)
     /* [previous][next][first][last][top][bottom][index][help] */
 160 {
 161         /* If we try to set the state of terminal and we're not in the
 162            foreground, send a SIGTTOU.  If the signal is blocked or
 163            ignored, go ahead and perform the operation.  POSIX 7.2) */
 164         if (current->tty != channel)
 165                 return 0;
 166         if (tty->pgrp <= 0) {
 167                 printk("check_change: tty->pgrp <= 0!\n");
 168                 return 0;
 169         }
 170         if (current->pgrp == tty->pgrp)
 171                 return 0;
 172         if (is_ignored(SIGTTOU))
 173                 return 0;
 174         if (is_orphaned_pgrp(current->pgrp))
 175                 return -EIO;
 176         (void) kill_pg(current->pgrp,SIGTTOU,1);
 177         return -ERESTARTSYS;
 178 }
 179 
 180 static int set_termios_2(struct tty_struct * tty, struct termios * termios)
     /* [previous][next][first][last][top][bottom][index][help] */
 181 {
 182         struct termios old_termios = *tty->termios;
 183         int canon_change;
 184 
 185         canon_change = (old_termios.c_lflag ^ termios->c_lflag) & ICANON;
 186         cli();
 187         *tty->termios = *termios;
 188         if (canon_change) {
 189                 memset(&tty->secondary_flags, 0, sizeof tty->secondary_flags);
 190                 tty->canon_head = tty->secondary.tail;
 191                 tty->canon_data = 0;
 192                 tty->erasing = 0;
 193         }
 194         sti();
 195         if (canon_change && !(tty->termios->c_lflag & ICANON) &&
 196             !EMPTY(&tty->secondary))
 197                 /* Get characters left over from canonical mode. */
 198                 wake_up_interruptible(&tty->secondary.proc_list);
 199 
 200         /* see if packet mode change of state */
 201 
 202         /* The BSD man page pty.4 says that TIOCPKT_NOSTOP should be sent
 203            if the new state differs from ^S/^Q, but that's a bad way of
 204            detecting a new flow control scheme.  Instead, a status byte
 205            is only sent if IXON has changed. */
 206         if (tty->link && tty->link->packet &&
 207             (old_termios.c_iflag ^ tty->termios->c_iflag) & IXON) {
 208                 tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
 209                 if (tty->termios->c_iflag & IXON)
 210                         tty->ctrl_status |= TIOCPKT_DOSTOP;
 211                 else
 212                         tty->ctrl_status |= TIOCPKT_NOSTOP;
 213                 wake_up_interruptible(&tty->link->secondary.proc_list);
 214         }
 215 
 216 #if 0
 217         /* puting mpty's into echo mode is very bad, and I think under
 218            some situations can cause the kernel to do nothing but
 219            copy characters back and forth. -RAB */
 220         /* This can no longer happen because a set_termios is redirected
 221            to the pty slave.  -- jrs */
 222         if (IS_A_PTY_MASTER(channel)) tty->termios->c_lflag &= ~ECHO;
 223 #endif
 224 
 225         unset_locked_termios(tty->termios, &old_termios,
 226                              termios_locked[tty->line]);
 227 
 228 #if 0
 229         retval = tty_set_ldisc(tty, tty->termios->c_line);
 230         if (retval)
 231                 return retval;
 232 #endif
 233 
 234         if (tty->set_termios)
 235                 (*tty->set_termios)(tty, &old_termios);
 236 
 237         return 0;
 238 }
 239 
 240 static int set_termios(struct tty_struct * tty, struct termios * termios,
     /* [previous][next][first][last][top][bottom][index][help] */
 241                        int channel)
 242 {
 243         struct termios tmp_termios;
 244 
 245         memcpy_fromfs(&tmp_termios, termios, sizeof (struct termios));
 246         return set_termios_2(tty, &tmp_termios);
 247 }
 248 
 249 static int get_termio(struct tty_struct * tty, struct termio * termio)
     /* [previous][next][first][last][top][bottom][index][help] */
 250 {
 251         int i;
 252         struct termio tmp_termio;
 253 
 254         i = verify_area(VERIFY_WRITE, termio, sizeof (struct termio));
 255         if (i)
 256                 return i;
 257         tmp_termio.c_iflag = tty->termios->c_iflag;
 258         tmp_termio.c_oflag = tty->termios->c_oflag;
 259         tmp_termio.c_cflag = tty->termios->c_cflag;
 260         tmp_termio.c_lflag = tty->termios->c_lflag;
 261         tmp_termio.c_line = tty->termios->c_line;
 262         for(i=0 ; i < NCC ; i++)
 263                 tmp_termio.c_cc[i] = tty->termios->c_cc[i];
 264         memcpy_tofs(termio, &tmp_termio, sizeof (struct termio));
 265         return 0;
 266 }
 267 
 268 static int set_termio(struct tty_struct * tty, struct termio * termio,
     /* [previous][next][first][last][top][bottom][index][help] */
 269                       int channel)
 270 {
 271         struct termio tmp_termio;
 272         struct termios tmp_termios;
 273 
 274         tmp_termios = *tty->termios;
 275         memcpy_fromfs(&tmp_termio, termio, sizeof (struct termio));
 276 
 277 #define SET_LOW_BITS(x,y)       ((x) = (0xffff0000 & (x)) | (y))
 278 
 279         SET_LOW_BITS(tmp_termios.c_iflag, tmp_termio.c_iflag);
 280         SET_LOW_BITS(tmp_termios.c_oflag, tmp_termio.c_oflag);
 281         SET_LOW_BITS(tmp_termios.c_cflag, tmp_termio.c_cflag);
 282         SET_LOW_BITS(tmp_termios.c_lflag, tmp_termio.c_lflag);
 283         memcpy(&tmp_termios.c_cc, &tmp_termio.c_cc, NCC);
 284 
 285 #undef SET_LOW_BITS
 286 
 287         return set_termios_2(tty, &tmp_termios);
 288 }
 289 
 290 static int set_window_size(struct tty_struct * tty, struct winsize * ws)
     /* [previous][next][first][last][top][bottom][index][help] */
 291 {
 292         struct winsize tmp_ws;
 293 
 294         memcpy_fromfs(&tmp_ws, ws, sizeof (struct winsize));
 295         if (memcmp(&tmp_ws, &tty->winsize, sizeof (struct winsize)) &&
 296             tty->pgrp > 0)
 297                 kill_pg(tty->pgrp, SIGWINCH, 1);
 298         tty->winsize = tmp_ws;
 299         return 0;
 300 }
 301 
 302 /* Set the discipline of a tty line. */
 303 static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
     /* [previous][next][first][last][top][bottom][index][help] */
 304 {
 305         if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS) ||
 306             !(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED))
 307                 return -EINVAL;
 308 
 309         if (tty->disc == ldisc)
 310                 return 0;       /* We are already in the desired discipline */
 311 
 312         /* Shutdown the current discipline. */
 313         wait_until_sent(tty);
 314         flush_input(tty);
 315         if (ldiscs[tty->disc].close)
 316                 ldiscs[tty->disc].close(tty);
 317 
 318         /* Now set up the new line discipline. */
 319         tty->disc = ldisc;
 320         tty->termios->c_line = ldisc;
 321         if (ldiscs[tty->disc].open)
 322                 return(ldiscs[tty->disc].open(tty));
 323         else
 324                 return 0;
 325 }
 326 
 327 static unsigned long inq_canon(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 328 {
 329         int nr, head, tail;
 330 
 331         if (!tty->canon_data)
 332                 return 0;
 333         head = tty->canon_head;
 334         tail = tty->secondary.tail;
 335         nr = (head - tail) & (TTY_BUF_SIZE-1);
 336         /* Skip EOF-chars.. */
 337         while (head != tail) {
 338                 if (test_bit(tail, &tty->secondary_flags) &&
 339                     tty->secondary.buf[tail] == __DISABLED_CHAR)
 340                         nr--;
 341                 INC(tail);
 342         }
 343         return nr;
 344 }
 345 
 346 int tty_ioctl(struct inode * inode, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
 347         unsigned int cmd, unsigned long arg)
 348 {
 349         struct tty_struct * tty;
 350         struct tty_struct * other_tty;
 351         struct tty_struct * termios_tty;
 352         pid_t pgrp;
 353         int dev;
 354         int termios_dev;
 355         int retval;
 356 
 357         if (MAJOR(file->f_rdev) != TTY_MAJOR) {
 358                 printk("tty_ioctl: tty pseudo-major != TTY_MAJOR\n");
 359                 return -EINVAL;
 360         }
 361         dev = MINOR(file->f_rdev);
 362         tty = TTY_TABLE(dev);
 363         if (!tty)
 364                 return -EINVAL;
 365         if (IS_A_PTY(dev))
 366                 other_tty = tty_table[PTY_OTHER(dev)];
 367         else
 368                 other_tty = NULL;
 369         if (IS_A_PTY_MASTER(dev)) {
 370                 termios_tty = other_tty;
 371                 termios_dev = PTY_OTHER(dev);
 372         } else {
 373                 termios_tty = tty;
 374                 termios_dev = dev;
 375         }
 376         switch (cmd) {
 377                 case TCGETS:
 378                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 379                                              sizeof (struct termios));
 380                         if (retval)
 381                                 return retval;
 382                         memcpy_tofs((struct termios *) arg,
 383                                     termios_tty->termios,
 384                                     sizeof (struct termios));
 385                         return 0;
 386                 case TCSETSF:
 387                 case TCSETSW:
 388                 case TCSETS:
 389                         retval = check_change(termios_tty, termios_dev);
 390                         if (retval)
 391                                 return retval;
 392                         if (cmd == TCSETSF || cmd == TCSETSW) {
 393                                 if (cmd == TCSETSF)
 394                                         flush_input(tty);
 395                                 wait_until_sent(tty);
 396                         }
 397                         return set_termios(termios_tty, (struct termios *) arg,
 398                                            termios_dev);
 399                 case TCGETA:
 400                         return get_termio(termios_tty,(struct termio *) arg);
 401                 case TCSETAF:
 402                 case TCSETAW:
 403                 case TCSETA:
 404                         retval = check_change(termios_tty, termios_dev);
 405                         if (retval)
 406                                 return retval;
 407                         if (cmd == TCSETAF || cmd == TCSETAW) {
 408                                 if (cmd == TCSETAF)
 409                                         flush_input(tty);
 410                                 wait_until_sent(tty);
 411                         }
 412                         return set_termio(termios_tty, (struct termio *) arg,
 413                                           termios_dev);
 414                 case TCXONC:
 415                         retval = check_change(tty, dev);
 416                         if (retval)
 417                                 return retval;
 418                         switch (arg) {
 419                         case TCOOFF:
 420                                 stop_tty(tty);
 421                                 break;
 422                         case TCOON:
 423                                 start_tty(tty);
 424                                 break;
 425                         case TCIOFF:
 426                                 if (STOP_CHAR(tty) != __DISABLED_CHAR)
 427                                         put_tty_queue(STOP_CHAR(tty),
 428                                                       &tty->write_q);
 429                                 break;
 430                         case TCION:
 431                                 if (START_CHAR(tty) != __DISABLED_CHAR)
 432                                         put_tty_queue(START_CHAR(tty),
 433                                                       &tty->write_q);
 434                                 break;
 435                         default:
 436                                 return -EINVAL;
 437                         }
 438                         return 0;
 439                 case TCFLSH:
 440                         retval = check_change(tty, dev);
 441                         if (retval)
 442                                 return retval;
 443                         switch (arg) {
 444                         case TCIFLUSH:
 445                                 flush_input(tty);
 446                                 break;
 447                         case TCIOFLUSH:
 448                                 flush_input(tty);
 449                                 /* fall through */
 450                         case TCOFLUSH:
 451                                 flush_output(tty);
 452                                 break;
 453                         default:
 454                                 return -EINVAL;
 455                         }
 456                         return 0;
 457                 case TIOCEXCL:
 458                         set_bit(TTY_EXCLUSIVE, &tty->flags);
 459                         return 0;
 460                 case TIOCNXCL:
 461                         clear_bit(TTY_EXCLUSIVE, &tty->flags);
 462                         return 0;
 463                 case TIOCSCTTY:
 464                         if (current->leader &&
 465                             (current->session == tty->session))
 466                                 return 0;
 467                         /*
 468                          * The process must be a session leader and
 469                          * not have a controlling tty already.
 470                          */
 471                         if (!current->leader || (current->tty >= 0))
 472                                 return -EPERM;
 473                         if (tty->session > 0) {
 474                                 /*
 475                                  * This tty is already the controlling
 476                                  * tty for another session group!
 477                                  */
 478                                 if ((arg == 1) && suser()) {
 479                                         /*
 480                                          * Steal it away
 481                                          */
 482                                         struct task_struct *p;
 483 
 484                                         for_each_task(p)
 485                                                 if (p->tty == dev)
 486                                                         p->tty = -1;
 487                                 } else
 488                                         return -EPERM;
 489                         }
 490                         current->tty = dev;
 491                         tty->session = current->session;
 492                         tty->pgrp = current->pgrp;
 493                         return 0;
 494                 case TIOCGPGRP:
 495                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 496                                              sizeof (pid_t));
 497                         if (retval)
 498                                 return retval;
 499                         put_fs_long(termios_tty->pgrp, (pid_t *) arg);
 500                         return 0;
 501                 case TIOCSPGRP:
 502                         retval = check_change(tty, dev);
 503                         if (retval)
 504                                 return retval;
 505                         if ((current->tty < 0) ||
 506                             (current->tty != termios_dev) ||
 507                             (termios_tty->session != current->session))
 508                                 return -ENOTTY;
 509                         pgrp = get_fs_long((pid_t *) arg);
 510                         if (pgrp < 0)
 511                                 return -EINVAL;
 512                         if (session_of_pgrp(pgrp) != current->session)
 513                                 return -EPERM;
 514                         termios_tty->pgrp = pgrp;                       
 515                         return 0;
 516                 case TIOCOUTQ:
 517                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 518                                              sizeof (unsigned long));
 519                         if (retval)
 520                                 return retval;
 521                         put_fs_long(CHARS(&tty->write_q),
 522                                     (unsigned long *) arg);
 523                         return 0;
 524                 case TIOCINQ:
 525                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 526                                              sizeof (unsigned long));
 527                         if (retval)
 528                                 return retval;
 529                         if (L_ICANON(tty))
 530                                 put_fs_long(inq_canon(tty),
 531                                         (unsigned long *) arg);
 532                         else
 533                                 put_fs_long(CHARS(&tty->secondary),
 534                                         (unsigned long *) arg);
 535                         return 0;
 536                 case TIOCSTI:
 537                         if ((current->tty != dev) && !suser())
 538                                 return -EACCES;
 539                         put_tty_queue(get_fs_byte((char *) arg), &tty->read_q);
 540                         TTY_READ_FLUSH(tty);
 541                         return 0;
 542                 case TIOCGWINSZ:
 543                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 544                                              sizeof (struct winsize));
 545                         if (retval)
 546                                 return retval;
 547                         memcpy_tofs((struct winsize *) arg, &tty->winsize,
 548                                     sizeof (struct winsize));
 549                         return 0;
 550                 case TIOCSWINSZ:
 551                         if (IS_A_PTY_MASTER(dev))
 552                                 set_window_size(other_tty,(struct winsize *) arg);
 553                         return set_window_size(tty,(struct winsize *) arg);
 554                 case TIOCLINUX:
 555                         switch (get_fs_byte((char *)arg))
 556                         {
 557                                 case 0: 
 558                                         return do_screendump(arg);
 559                                 case 1: 
 560                                         return do_get_ps_info(arg);
 561 #ifdef CONFIG_SELECTION
 562                                 case 2:
 563                                         return set_selection(arg);
 564                                 case 3:
 565                                         return paste_selection(tty);
 566 #endif /* CONFIG_SELECTION */
 567                                 default: 
 568                                         return -EINVAL;
 569                         }
 570                 case TIOCCONS:
 571                         if (IS_A_CONSOLE(dev)) {
 572                                 if (!suser())
 573                                         return -EPERM;
 574                                 redirect = NULL;
 575                                 return 0;
 576                         }
 577                         if (redirect)
 578                                 return -EBUSY;
 579                         if (!suser())
 580                                 return -EPERM;
 581                         if (IS_A_PTY_MASTER(dev))
 582                                 redirect = other_tty;
 583                         else if (IS_A_PTY_SLAVE(dev))
 584                                 redirect = tty;
 585                         else
 586                                 return -EINVAL;
 587                         return 0;
 588                 case FIONBIO:
 589                         arg = get_fs_long((unsigned long *) arg);
 590                         if (arg)
 591                                 file->f_flags |= O_NONBLOCK;
 592                         else
 593                                 file->f_flags &= ~O_NONBLOCK;
 594                         return 0;
 595                 case TIOCNOTTY:
 596                         if (MINOR(file->f_rdev) != current->tty)
 597                                 return -EINVAL;
 598                         if (current->leader)
 599                                 disassociate_ctty(0);
 600                         current->tty = -1;
 601                         return 0;
 602                 case TIOCGETD:
 603                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 604                                              sizeof (unsigned long));
 605                         if (retval)
 606                                 return retval;
 607                         put_fs_long(tty->disc, (unsigned long *) arg);
 608                         return 0;
 609                 case TIOCSETD:
 610                         retval = check_change(tty, dev);
 611                         if (retval)
 612                                 return retval;
 613                         arg = get_fs_long((unsigned long *) arg);
 614                         return tty_set_ldisc(tty, arg);
 615                 case TIOCGLCKTRMIOS:
 616                         arg = get_fs_long((unsigned long *) arg);
 617                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 618                                              sizeof (struct termios));
 619                         if (retval)
 620                                 return retval;
 621                         memcpy_tofs((struct termios *) arg,
 622                                     &termios_locked[termios_dev],
 623                                     sizeof (struct termios));
 624                         return 0;
 625                 case TIOCSLCKTRMIOS:
 626                         if (!suser())
 627                                 return -EPERM;
 628                         arg = get_fs_long((unsigned long *) arg);
 629                         memcpy_fromfs(&termios_locked[termios_dev],
 630                                       (struct termios *) arg,
 631                                       sizeof (struct termios));
 632                         return 0;
 633                 case TIOCPKT:
 634                         if (!IS_A_PTY_MASTER(dev))
 635                                 return -EINVAL;
 636                         retval = verify_area(VERIFY_READ, (void *) arg,
 637                                              sizeof (unsigned long));
 638                         if (retval)
 639                                 return retval;
 640                         if (get_fs_long(arg)) {
 641                                 if (!tty->packet) {
 642                                         tty->packet = 1;
 643                                         tty->ctrl_status = 0;
 644                                 }
 645                         } else
 646                                 tty->packet = 0;
 647                         return 0;
 648                 case TCSBRK: case TCSBRKP:
 649                         retval = check_change(tty, dev);
 650                         if (retval)
 651                                 return retval;
 652                         wait_until_sent(tty);
 653                         if (!tty->ioctl)
 654                                 return 0;
 655                         tty->ioctl(tty, file, cmd, arg);
 656                         return 0;
 657                 default:
 658                         if (tty->ioctl) {
 659                                 retval = (tty->ioctl)(tty, file, cmd, arg);
 660                                 if (retval != -EINVAL)
 661                                         return retval;
 662                         }
 663                         if (ldiscs[tty->disc].ioctl) {
 664                                 retval = (ldiscs[tty->disc].ioctl)
 665                                         (tty, file, cmd, arg);
 666                                 return retval;
 667                         }
 668                         return -EINVAL;
 669         }
 670 }

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