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