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

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