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)
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 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)
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,
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)
160 {
161
162
163
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)
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
198 wake_up_interruptible(&tty->secondary.proc_list);
199
200
201
202
203
204
205
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
218
219
220
221
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,
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)
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,
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)
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
303 static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
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;
311
312
313 wait_until_sent(tty);
314 flush_input(tty);
315 if (ldiscs[tty->disc].close)
316 ldiscs[tty->disc].close(tty);
317
318
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)
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
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,
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
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
469
470
471 if (!current->leader || (current->tty >= 0))
472 return -EPERM;
473 if (tty->session > 0) {
474
475
476
477
478 if ((arg == 1) && suser()) {
479
480
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
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 }