This source file includes following definitions.
- flush_input
- flush_output
- wait_until_sent
- do_get_ps_info
- unset_locked_termios
- check_change
- set_termios_2
- set_termios
- get_termio
- set_termio
- set_window_size
- tty_set_ldisc
- inq_canon
- tty_ioctl
1
2
3
4
5
6
7
8
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
42
43 static int tty_set_ldisc(struct tty_struct *tty, int ldisc);
44
45 void flush_input(struct tty_struct * tty)
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
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)
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
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, int timeout)
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;
94 if (timeout)
95 current->timeout = timeout + jiffies;
96 else
97 current->timeout = (unsigned) -1;
98 do {
99 current->state = TASK_INTERRUPTIBLE;
100 if (current->signal & ~current->blocked)
101 break;
102 TTY_WRITE_FLUSH(tty);
103 if (EMPTY(&tty->write_q))
104 break;
105 schedule();
106 } while (current->timeout);
107 current->state = TASK_RUNNING;
108 remove_wait_queue(&tty->write_q.proc_list, &wait);
109 }
110
111 static int do_get_ps_info(int arg)
112 {
113 struct tstruct {
114 int flag;
115 int present[NR_TASKS];
116 struct task_struct tasks[NR_TASKS];
117 };
118 struct tstruct *ts = (struct tstruct *)arg;
119 struct task_struct **p;
120 char *c, *d;
121 int i, n = 0;
122
123 i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct tstruct));
124 if (i)
125 return i;
126 for (p = &FIRST_TASK ; p <= &LAST_TASK ; p++, n++)
127 if (*p)
128 {
129 c = (char *)(*p);
130 d = (char *)(ts->tasks+n);
131 for (i=0 ; i<sizeof(struct task_struct) ; i++)
132 put_fs_byte(*c++, d++);
133 put_fs_long(1, (unsigned long *)(ts->present+n));
134 }
135 else
136 put_fs_long(0, (unsigned long *)(ts->present+n));
137 return(0);
138 }
139
140 static void unset_locked_termios(struct termios *termios,
141 struct termios *old,
142 struct termios *locked)
143 {
144 int i;
145
146 #define NOSET_MASK(x,y,z) (x = ((x) & ~(z)) | ((y) & (z)))
147
148 if (!locked) {
149 printk("Warning?!? termios_locked is NULL.\n");
150 return;
151 }
152
153 NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
154 NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
155 NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
156 NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
157 termios->c_line = locked->c_line ? old->c_line : termios->c_line;
158 for (i=0; i < NCCS; i++)
159 termios->c_cc[i] = locked->c_cc[i] ?
160 old->c_cc[i] : termios->c_cc[i];
161 }
162
163 int check_change(struct tty_struct * tty, int channel)
164 {
165
166
167
168 if (current->tty != channel)
169 return 0;
170 if (tty->pgrp <= 0) {
171 printk("check_change: tty->pgrp <= 0!\n");
172 return 0;
173 }
174 if (current->pgrp == tty->pgrp)
175 return 0;
176 if (is_ignored(SIGTTOU))
177 return 0;
178 if (is_orphaned_pgrp(current->pgrp))
179 return -EIO;
180 (void) kill_pg(current->pgrp,SIGTTOU,1);
181 return -ERESTARTSYS;
182 }
183
184 static int set_termios_2(struct tty_struct * tty, struct termios * termios)
185 {
186 struct termios old_termios = *tty->termios;
187 int canon_change;
188
189 canon_change = (old_termios.c_lflag ^ termios->c_lflag) & ICANON;
190 cli();
191 *tty->termios = *termios;
192 if (canon_change) {
193 memset(&tty->secondary_flags, 0, sizeof tty->secondary_flags);
194 tty->canon_head = tty->secondary.tail;
195 tty->canon_data = 0;
196 tty->erasing = 0;
197 }
198 sti();
199 if (canon_change && !L_ICANON(tty) && !EMPTY(&tty->secondary))
200
201 wake_up_interruptible(&tty->secondary.proc_list);
202
203
204
205 if (tty->link && tty->link->packet) {
206 int old_flow = ((old_termios.c_iflag & IXON) &&
207 (old_termios.c_cc[VSTOP] == '\023') &&
208 (old_termios.c_cc[VSTART] == '\021'));
209 int new_flow = (I_IXON(tty) &&
210 STOP_CHAR(tty) == '\023' &&
211 START_CHAR(tty) == '\021');
212 if (old_flow != new_flow) {
213 tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
214 if (new_flow)
215 tty->ctrl_status |= TIOCPKT_DOSTOP;
216 else
217 tty->ctrl_status |= TIOCPKT_NOSTOP;
218 wake_up_interruptible(&tty->link->secondary.proc_list);
219 }
220 }
221
222 unset_locked_termios(tty->termios, &old_termios,
223 termios_locked[tty->line]);
224
225 if (tty->set_termios)
226 (*tty->set_termios)(tty, &old_termios);
227
228 return 0;
229 }
230
231 static int set_termios(struct tty_struct * tty, struct termios * termios,
232 int channel)
233 {
234 struct termios tmp_termios;
235
236 memcpy_fromfs(&tmp_termios, termios, sizeof (struct termios));
237 return set_termios_2(tty, &tmp_termios);
238 }
239
240 static int get_termio(struct tty_struct * tty, struct termio * termio)
241 {
242 int i;
243 struct termio tmp_termio;
244
245 i = verify_area(VERIFY_WRITE, termio, sizeof (struct termio));
246 if (i)
247 return i;
248 tmp_termio.c_iflag = tty->termios->c_iflag;
249 tmp_termio.c_oflag = tty->termios->c_oflag;
250 tmp_termio.c_cflag = tty->termios->c_cflag;
251 tmp_termio.c_lflag = tty->termios->c_lflag;
252 tmp_termio.c_line = tty->termios->c_line;
253 for(i=0 ; i < NCC ; i++)
254 tmp_termio.c_cc[i] = tty->termios->c_cc[i];
255 memcpy_tofs(termio, &tmp_termio, sizeof (struct termio));
256 return 0;
257 }
258
259 static int set_termio(struct tty_struct * tty, struct termio * termio,
260 int channel)
261 {
262 struct termio tmp_termio;
263 struct termios tmp_termios;
264
265 tmp_termios = *tty->termios;
266 memcpy_fromfs(&tmp_termio, termio, sizeof (struct termio));
267
268 #define SET_LOW_BITS(x,y) ((x) = (0xffff0000 & (x)) | (y))
269
270 SET_LOW_BITS(tmp_termios.c_iflag, tmp_termio.c_iflag);
271 SET_LOW_BITS(tmp_termios.c_oflag, tmp_termio.c_oflag);
272 SET_LOW_BITS(tmp_termios.c_cflag, tmp_termio.c_cflag);
273 SET_LOW_BITS(tmp_termios.c_lflag, tmp_termio.c_lflag);
274 memcpy(&tmp_termios.c_cc, &tmp_termio.c_cc, NCC);
275
276 #undef SET_LOW_BITS
277
278 return set_termios_2(tty, &tmp_termios);
279 }
280
281 static int set_window_size(struct tty_struct * tty, struct winsize * ws)
282 {
283 struct winsize tmp_ws;
284
285 memcpy_fromfs(&tmp_ws, ws, sizeof (struct winsize));
286 if (memcmp(&tmp_ws, &tty->winsize, sizeof (struct winsize)) &&
287 tty->pgrp > 0)
288 kill_pg(tty->pgrp, SIGWINCH, 1);
289 tty->winsize = tmp_ws;
290 return 0;
291 }
292
293
294 static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
295 {
296 if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS) ||
297 !(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED))
298 return -EINVAL;
299
300 if (tty->disc == ldisc)
301 return 0;
302
303
304 wait_until_sent(tty, 0);
305 flush_input(tty);
306 if (ldiscs[tty->disc].close)
307 ldiscs[tty->disc].close(tty);
308
309
310 tty->disc = ldisc;
311 tty->termios->c_line = ldisc;
312 if (ldiscs[tty->disc].open)
313 return(ldiscs[tty->disc].open(tty));
314 else
315 return 0;
316 }
317
318 static unsigned long inq_canon(struct tty_struct * tty)
319 {
320 int nr, head, tail;
321
322 if (!tty->canon_data)
323 return 0;
324 head = tty->canon_head;
325 tail = tty->secondary.tail;
326 nr = (head - tail) & (TTY_BUF_SIZE-1);
327
328 while (head != tail) {
329 if (test_bit(tail, &tty->secondary_flags) &&
330 tty->secondary.buf[tail] == __DISABLED_CHAR)
331 nr--;
332 INC(tail);
333 }
334 return nr;
335 }
336
337 int tty_ioctl(struct inode * inode, struct file * file,
338 unsigned int cmd, unsigned long arg)
339 {
340 struct tty_struct * tty;
341 struct tty_struct * other_tty;
342 struct tty_struct * termios_tty;
343 pid_t pgrp;
344 int dev;
345 int termios_dev;
346 int retval;
347
348 if (MAJOR(file->f_rdev) != TTY_MAJOR) {
349 printk("tty_ioctl: tty pseudo-major != TTY_MAJOR\n");
350 return -EINVAL;
351 }
352 dev = MINOR(file->f_rdev);
353 tty = TTY_TABLE(dev);
354 if (!tty)
355 return -EINVAL;
356 if (IS_A_PTY(dev))
357 other_tty = tty_table[PTY_OTHER(dev)];
358 else
359 other_tty = NULL;
360 if (IS_A_PTY_MASTER(dev)) {
361 termios_tty = other_tty;
362 termios_dev = PTY_OTHER(dev);
363 } else {
364 termios_tty = tty;
365 termios_dev = dev;
366 }
367 switch (cmd) {
368 case TCGETS:
369 retval = verify_area(VERIFY_WRITE, (void *) arg,
370 sizeof (struct termios));
371 if (retval)
372 return retval;
373 memcpy_tofs((struct termios *) arg,
374 termios_tty->termios,
375 sizeof (struct termios));
376 return 0;
377 case TCSETSF:
378 case TCSETSW:
379 case TCSETS:
380 retval = check_change(termios_tty, termios_dev);
381 if (retval)
382 return retval;
383 if (cmd == TCSETSF || cmd == TCSETSW) {
384 if (cmd == TCSETSF)
385 flush_input(termios_tty);
386 wait_until_sent(termios_tty, 0);
387 }
388 return set_termios(termios_tty, (struct termios *) arg,
389 termios_dev);
390 case TCGETA:
391 return get_termio(termios_tty,(struct termio *) arg);
392 case TCSETAF:
393 case TCSETAW:
394 case TCSETA:
395 retval = check_change(termios_tty, termios_dev);
396 if (retval)
397 return retval;
398 if (cmd == TCSETAF || cmd == TCSETAW) {
399 if (cmd == TCSETAF)
400 flush_input(termios_tty);
401 wait_until_sent(termios_tty, 0);
402 }
403 return set_termio(termios_tty, (struct termio *) arg,
404 termios_dev);
405 case TCXONC:
406 retval = check_change(tty, dev);
407 if (retval)
408 return retval;
409 switch (arg) {
410 case TCOOFF:
411 stop_tty(tty);
412 break;
413 case TCOON:
414 start_tty(tty);
415 break;
416 case TCIOFF:
417 if (STOP_CHAR(tty) != __DISABLED_CHAR)
418 put_tty_queue(STOP_CHAR(tty),
419 &tty->write_q);
420 break;
421 case TCION:
422 if (START_CHAR(tty) != __DISABLED_CHAR)
423 put_tty_queue(START_CHAR(tty),
424 &tty->write_q);
425 break;
426 default:
427 return -EINVAL;
428 }
429 return 0;
430 case TCFLSH:
431 retval = check_change(tty, dev);
432 if (retval)
433 return retval;
434 switch (arg) {
435 case TCIFLUSH:
436 flush_input(tty);
437 break;
438 case TCIOFLUSH:
439 flush_input(tty);
440
441 case TCOFLUSH:
442 flush_output(tty);
443 break;
444 default:
445 return -EINVAL;
446 }
447 return 0;
448 case TIOCEXCL:
449 set_bit(TTY_EXCLUSIVE, &tty->flags);
450 return 0;
451 case TIOCNXCL:
452 clear_bit(TTY_EXCLUSIVE, &tty->flags);
453 return 0;
454 case TIOCSCTTY:
455 if (current->leader &&
456 (current->session == tty->session))
457 return 0;
458
459
460
461
462 if (!current->leader || (current->tty >= 0))
463 return -EPERM;
464 if (tty->session > 0) {
465
466
467
468
469 if ((arg == 1) && suser()) {
470
471
472
473 struct task_struct *p;
474
475 for_each_task(p)
476 if (p->tty == dev)
477 p->tty = -1;
478 } else
479 return -EPERM;
480 }
481 current->tty = dev;
482 tty->session = current->session;
483 tty->pgrp = current->pgrp;
484 return 0;
485 case TIOCGPGRP:
486 retval = verify_area(VERIFY_WRITE, (void *) arg,
487 sizeof (pid_t));
488 if (retval)
489 return retval;
490 if (current->tty != termios_dev)
491 return -ENOTTY;
492 put_fs_long(termios_tty->pgrp, (pid_t *) arg);
493 return 0;
494 case TIOCSPGRP:
495 retval = check_change(termios_tty, termios_dev);
496 if (retval)
497 return retval;
498 if ((current->tty < 0) ||
499 (current->tty != termios_dev) ||
500 (termios_tty->session != current->session))
501 return -ENOTTY;
502 pgrp = get_fs_long((pid_t *) arg);
503 if (pgrp < 0)
504 return -EINVAL;
505 if (session_of_pgrp(pgrp) != current->session)
506 return -EPERM;
507 termios_tty->pgrp = pgrp;
508 return 0;
509 case TIOCOUTQ:
510 retval = verify_area(VERIFY_WRITE, (void *) arg,
511 sizeof (unsigned long));
512 if (retval)
513 return retval;
514 put_fs_long(CHARS(&tty->write_q),
515 (unsigned long *) arg);
516 return 0;
517 case TIOCINQ:
518 retval = verify_area(VERIFY_WRITE, (void *) arg,
519 sizeof (unsigned long));
520 if (retval)
521 return retval;
522 if (L_ICANON(tty))
523 put_fs_long(inq_canon(tty),
524 (unsigned long *) arg);
525 else
526 put_fs_long(CHARS(&tty->secondary),
527 (unsigned long *) arg);
528 return 0;
529 case TIOCSTI:
530 if ((current->tty != dev) && !suser())
531 return -EPERM;
532 retval = verify_area(VERIFY_READ, (void *) arg, 1);
533 if (retval)
534 return retval;
535 put_tty_queue(get_fs_byte((char *) arg), &tty->read_q);
536 TTY_READ_FLUSH(tty);
537 return 0;
538 case TIOCGWINSZ:
539 retval = verify_area(VERIFY_WRITE, (void *) arg,
540 sizeof (struct winsize));
541 if (retval)
542 return retval;
543 memcpy_tofs((struct winsize *) arg, &tty->winsize,
544 sizeof (struct winsize));
545 return 0;
546 case TIOCSWINSZ:
547 if (IS_A_PTY_MASTER(dev))
548 set_window_size(other_tty,(struct winsize *) arg);
549 return set_window_size(tty,(struct winsize *) arg);
550 case TIOCLINUX:
551 switch (get_fs_byte((char *)arg))
552 {
553 case 0:
554 return do_screendump(arg);
555 case 1:
556 return do_get_ps_info(arg);
557 #ifdef CONFIG_SELECTION
558 case 2:
559 return set_selection(arg);
560 case 3:
561 return paste_selection(tty);
562 case 4:
563 unblank_screen();
564 return 0;
565 #endif
566 default:
567 return -EINVAL;
568 }
569 case TIOCCONS:
570 if (IS_A_CONSOLE(dev)) {
571 if (!suser())
572 return -EPERM;
573 redirect = NULL;
574 return 0;
575 }
576 if (redirect)
577 return -EBUSY;
578 if (!suser())
579 return -EPERM;
580 if (IS_A_PTY_MASTER(dev))
581 redirect = other_tty;
582 else if (IS_A_PTY_SLAVE(dev))
583 redirect = tty;
584 else
585 return -ENOTTY;
586 return 0;
587 case FIONBIO:
588 arg = get_fs_long((unsigned long *) arg);
589 if (arg)
590 file->f_flags |= O_NONBLOCK;
591 else
592 file->f_flags &= ~O_NONBLOCK;
593 return 0;
594 case TIOCNOTTY:
595 if (current->tty != dev)
596 return -ENOTTY;
597 if (current->leader)
598 disassociate_ctty(0);
599 current->tty = -1;
600 return 0;
601 case TIOCGETD:
602 retval = verify_area(VERIFY_WRITE, (void *) arg,
603 sizeof (unsigned long));
604 if (retval)
605 return retval;
606 put_fs_long(tty->disc, (unsigned long *) arg);
607 return 0;
608 case TIOCSETD:
609 retval = check_change(tty, dev);
610 if (retval)
611 return retval;
612 arg = get_fs_long((unsigned long *) arg);
613 return tty_set_ldisc(tty, arg);
614 case TIOCGLCKTRMIOS:
615 arg = get_fs_long((unsigned long *) arg);
616 retval = verify_area(VERIFY_WRITE, (void *) arg,
617 sizeof (struct termios));
618 if (retval)
619 return retval;
620 memcpy_tofs((struct termios *) arg,
621 &termios_locked[termios_dev],
622 sizeof (struct termios));
623 return 0;
624 case TIOCSLCKTRMIOS:
625 if (!suser())
626 return -EPERM;
627 arg = get_fs_long((unsigned long *) arg);
628 memcpy_fromfs(&termios_locked[termios_dev],
629 (struct termios *) arg,
630 sizeof (struct termios));
631 return 0;
632 case TIOCPKT:
633 if (!IS_A_PTY_MASTER(dev))
634 return -ENOTTY;
635 retval = verify_area(VERIFY_READ, (void *) arg,
636 sizeof (unsigned long));
637 if (retval)
638 return retval;
639 if (get_fs_long(arg)) {
640 if (!tty->packet) {
641 tty->packet = 1;
642 tty->link->ctrl_status = 0;
643 }
644 } else
645 tty->packet = 0;
646 return 0;
647 case TCSBRK: case TCSBRKP:
648 retval = check_change(tty, dev);
649 if (retval)
650 return retval;
651 wait_until_sent(tty, 0);
652 if (!tty->ioctl)
653 return 0;
654 tty->ioctl(tty, file, cmd, arg);
655 return 0;
656 default:
657 if (tty->ioctl) {
658 retval = (tty->ioctl)(tty, file, cmd, arg);
659 if (retval != -EINVAL)
660 return retval;
661 }
662 if (ldiscs[tty->disc].ioctl) {
663 retval = (ldiscs[tty->disc].ioctl)
664 (tty, file, cmd, arg);
665 return retval;
666 }
667 return -EINVAL;
668 }
669 }