This source file includes following definitions.
- flush
- flush_input
- flush_output
- wait_until_sent
- do_get_ps_info
- unset_locked_termios
- get_termios
- check_change
- set_termios
- get_termio
- set_termio
- get_lcktrmios
- set_lcktrmios
- set_window_size
- get_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
21 #include <asm/io.h>
22 #include <asm/bitops.h>
23 #include <asm/segment.h>
24 #include <asm/system.h>
25
26 #undef DEBUG
27 #ifdef DEBUG
28 # define PRINTK(x) printk (x)
29 #else
30 # define PRINTK(x)
31 #endif
32
33 extern int session_of_pgrp(int pgrp);
34 extern int do_screendump(int arg);
35 extern int kill_pg(int pgrp, int sig, int priv);
36
37 #ifdef CONFIG_SELECTION
38 extern int set_selection(const int arg);
39 extern int paste_selection(struct tty_struct *tty);
40 #endif
41
42 static int tty_set_ldisc(struct tty_struct *tty, int ldisc);
43
44 static void flush(struct tty_queue * queue)
45 {
46 if (queue) {
47 cli();
48 queue->head = queue->tail;
49 sti();
50 wake_up_interruptible(&queue->proc_list);
51 }
52 }
53
54 void flush_input(struct tty_struct * tty)
55 {
56 tty->ctrl_status |= TIOCPKT_FLUSHREAD;
57 if (tty->link)
58 wake_up_interruptible(&tty->link->except_q);
59 flush(&tty->read_q);
60 wake_up_interruptible(&tty->read_q.proc_list);
61 flush(&tty->secondary);
62 tty->secondary.data = 0;
63
64 if ((tty = tty->link) != NULL) {
65 flush(&tty->write_q);
66 wake_up_interruptible(&tty->write_q.proc_list);
67 }
68 }
69
70 void flush_output(struct tty_struct * tty)
71 {
72 tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
73 if (tty->link)
74 wake_up_interruptible(&tty->link->except_q);
75 flush(&tty->write_q);
76 wake_up_interruptible(&tty->write_q.proc_list);
77 if ((tty = tty->link) != NULL) {
78 flush(&tty->read_q);
79 wake_up_interruptible(&tty->read_q.proc_list);
80 flush(&tty->secondary);
81 tty->secondary.data = 0;
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 static int get_termios(struct tty_struct * tty, struct termios * termios)
160 {
161 int i;
162
163 i = verify_area(VERIFY_WRITE, termios, sizeof (*termios));
164 if (i)
165 return i;
166 for (i=0 ; i< (sizeof (*termios)) ; i++)
167 put_fs_byte( ((char *)tty->termios)[i] , i+(char *)termios );
168 return 0;
169 }
170
171 static int check_change(struct tty_struct * tty, int channel)
172 {
173
174
175
176 if (current->tty != channel)
177 return 0;
178 if (tty->pgrp <= 0 || tty->pgrp == current->pgrp)
179 return 0;
180 if (is_orphaned_pgrp(current->pgrp))
181 return -EIO;
182 if (is_ignored(SIGTTOU))
183 return 0;
184 (void) kill_pg(current->pgrp,SIGTTOU,1);
185 return -ERESTARTSYS;
186 }
187
188 static int set_termios(struct tty_struct * tty, struct termios * termios,
189 int channel)
190 {
191 int i, old_flow, new_flow;
192 struct termios old_termios = *tty->termios;
193
194 i = check_change(tty, channel);
195 if (i)
196 return i;
197 for (i=0 ; i< (sizeof (*termios)) ; i++)
198 ((char *)tty->termios)[i]=get_fs_byte(i+(char *)termios);
199
200
201
202 old_flow = (old_termios.c_iflag & IXON) &&
203 (old_termios.c_cc[VSTOP] == '\023') &&
204 (old_termios.c_cc[VSTART] == '\021');
205
206 new_flow = (tty->termios->c_iflag & IXON) &&
207 (tty->termios->c_cc[VSTOP] == '\023') &&
208 (tty->termios->c_cc[VSTART] == '\021');
209
210 if (old_flow != new_flow) {
211 tty->ctrl_status &= ~(TIOCPKT_DOSTOP|TIOCPKT_NOSTOP);
212 if (new_flow)
213 tty->ctrl_status |= TIOCPKT_DOSTOP;
214 else
215 tty->ctrl_status |= TIOCPKT_NOSTOP;
216 if (tty->link)
217 wake_up_interruptible(&tty->link->except_q);
218 }
219
220 #if 0
221
222
223
224
225
226 if (IS_A_PTY_MASTER(channel)) tty->termios->c_lflag &= ~ECHO;
227 #endif
228
229 unset_locked_termios(tty->termios, &old_termios,
230 termios_locked[tty->line]);
231
232 #if 0
233 retval = tty_set_ldisc(tty, tty->termios->c_line);
234 if (retval)
235 return retval;
236 #endif
237
238 if (tty->set_termios)
239 (*tty->set_termios)(tty, &old_termios);
240
241 return 0;
242 }
243
244 static int get_termio(struct tty_struct * tty, struct termio * termio)
245 {
246 int i;
247 struct termio tmp_termio;
248
249 i = verify_area(VERIFY_WRITE, termio, sizeof (*termio));
250 if (i)
251 return i;
252 tmp_termio.c_iflag = tty->termios->c_iflag;
253 tmp_termio.c_oflag = tty->termios->c_oflag;
254 tmp_termio.c_cflag = tty->termios->c_cflag;
255 tmp_termio.c_lflag = tty->termios->c_lflag;
256 tmp_termio.c_line = tty->termios->c_line;
257 for(i=0 ; i < NCC ; i++)
258 tmp_termio.c_cc[i] = tty->termios->c_cc[i];
259 for (i=0 ; i< (sizeof (*termio)) ; i++)
260 put_fs_byte( ((char *)&tmp_termio)[i] , i+(char *)termio );
261 return 0;
262 }
263
264 static int set_termio(struct tty_struct * tty, struct termio * termio,
265 int channel)
266 {
267 int i, old_flow, new_flow;
268 struct termio tmp_termio;
269 struct termios old_termios = *tty->termios;
270
271 #define SET_LOW_BITS(x,y) ((x) = (0xffff0000 & (x)) | (y))
272
273 i = check_change(tty, channel);
274 if (i)
275 return i;
276 memcpy_fromfs(&tmp_termio, termio, sizeof(*termio));
277
278 SET_LOW_BITS(tty->termios->c_iflag, tmp_termio.c_iflag);
279 SET_LOW_BITS(tty->termios->c_oflag, tmp_termio.c_oflag);
280 SET_LOW_BITS(tty->termios->c_cflag, tmp_termio.c_cflag);
281 SET_LOW_BITS(tty->termios->c_lflag, tmp_termio.c_lflag);
282 memcpy(tty->termios->c_cc, tmp_termio.c_cc, NCC);
283
284
285
286 old_flow = (old_termios.c_iflag & IXON) &&
287 (old_termios.c_cc[VSTOP] == '\023') &&
288 (old_termios.c_cc[VSTART] == '\021');
289
290 new_flow = (tty->termios->c_iflag & IXON) &&
291 (tty->termios->c_cc[VSTOP] == '\023') &&
292 (tty->termios->c_cc[VSTART] == '\021');
293
294 if (old_flow != new_flow) {
295 tty->ctrl_status &= ~(TIOCPKT_DOSTOP|TIOCPKT_NOSTOP);
296 if (new_flow)
297 tty->ctrl_status |= TIOCPKT_DOSTOP;
298 else
299 tty->ctrl_status |= TIOCPKT_NOSTOP;
300 if (tty->link)
301 wake_up_interruptible(&tty->link->except_q);
302 }
303
304 unset_locked_termios(tty->termios, &old_termios,
305 termios_locked[tty->line]);
306
307 #if 0
308 retval = tty_set_ldisc(tty, tmp_termio.c_line);
309 if (retval)
310 return retval;
311 #endif
312
313 if (tty->set_termios)
314 (*tty->set_termios)(tty, &old_termios);
315
316 return 0;
317 }
318
319 static int get_lcktrmios(struct tty_struct * tty, struct termios * termios,
320 int channel)
321 {
322 int i;
323
324 i = verify_area(VERIFY_WRITE, termios, sizeof (*termios));
325 if (i)
326 return i;
327 for (i=0 ; i< (sizeof (*termios)) ; i++)
328 put_fs_byte( ((char *)termios_locked[channel])[i],
329 i+(char *)termios);
330 return 0;
331 }
332
333 static int set_lcktrmios(struct tty_struct * tty, struct termios * termios,
334 int channel)
335 {
336 int i;
337
338 if (!suser())
339 return -EPERM;
340 for (i=0 ; i< (sizeof (*termios)) ; i++)
341 ((char *)termios_locked[channel])[i] =
342 get_fs_byte(i+(char *)termios);
343
344 return 0;
345 }
346
347 static int set_window_size(struct tty_struct * tty, struct winsize * ws)
348 {
349 int i,changed;
350 char c, * tmp;
351
352 if (!ws)
353 return -EINVAL;
354 tmp = (char *) &tty->winsize;
355 changed = 0;
356 for (i = 0; i < sizeof (*ws) ; i++,tmp++) {
357 c = get_fs_byte(i + (char *) ws);
358 if (c == *tmp)
359 continue;
360 changed = 1;
361 *tmp = c;
362 }
363 if (changed)
364 kill_pg(tty->pgrp, SIGWINCH, 1);
365 return 0;
366 }
367
368 static int get_window_size(struct tty_struct * tty, struct winsize * ws)
369 {
370 int i;
371 char * tmp;
372
373 if (!ws)
374 return -EINVAL;
375 i = verify_area(VERIFY_WRITE, ws, sizeof (*ws));
376 if (i)
377 return i;
378 tmp = (char *) ws;
379 for (i = 0; i < sizeof (struct winsize) ; i++,tmp++)
380 put_fs_byte(((char *) &tty->winsize)[i], tmp);
381 return 0;
382 }
383
384
385 static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
386 {
387 if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS) ||
388 !(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED))
389 return -EINVAL;
390
391 if (tty->disc == ldisc)
392 return 0;
393
394
395 wait_until_sent(tty);
396 flush_input(tty);
397 if (ldiscs[tty->disc].close)
398 ldiscs[tty->disc].close(tty);
399
400
401 tty->disc = ldisc;
402 tty->termios->c_line = ldisc;
403 if (ldiscs[tty->disc].open)
404 return(ldiscs[tty->disc].open(tty));
405 else
406 return 0;
407 }
408
409 static int inq_canon(struct tty_struct * tty)
410 {
411 int nr, head, tail;
412
413 if (!tty->secondary.data)
414 return 0;
415 head = tty->secondary.head;
416 tail = tty->secondary.tail;
417 nr = (head - tail) & (TTY_BUF_SIZE-1);
418
419 if (EOF_CHAR(tty) == __DISABLED_CHAR)
420 return nr;
421 while (head != tail) {
422 if (tty->secondary.buf[tail] == EOF_CHAR(tty))
423 nr--;
424 INC(tail);
425 }
426 return nr;
427 }
428
429 int tty_ioctl(struct inode * inode, struct file * file,
430 unsigned int cmd, unsigned long arg)
431 {
432 struct tty_struct * tty;
433 struct tty_struct * other_tty;
434 struct tty_struct * termios_tty;
435 int pgrp;
436 int dev;
437 int termios_dev;
438 int retval;
439
440 if (MAJOR(file->f_rdev) != TTY_MAJOR) {
441 printk("tty_ioctl: tty pseudo-major != TTY_MAJOR\n");
442 return -EINVAL;
443 }
444 dev = MINOR(file->f_rdev);
445 tty = TTY_TABLE(dev);
446 if (!tty)
447 return -EINVAL;
448 if (IS_A_PTY(dev))
449 other_tty = tty_table[PTY_OTHER(dev)];
450 else
451 other_tty = NULL;
452 termios_tty = tty;
453 termios_dev = dev;
454 if (IS_A_PTY_MASTER(dev)) {
455 termios_tty = other_tty;
456 termios_dev = PTY_OTHER(dev);
457 }
458 switch (cmd) {
459 case TCGETS:
460 return get_termios(termios_tty,(struct termios *) arg);
461 case TCSETSF:
462 flush_input(tty);
463
464 case TCSETSW:
465 wait_until_sent(tty);
466
467 case TCSETS:
468 return set_termios(termios_tty,(struct termios *) arg, termios_dev);
469 case TCGETA:
470 return get_termio(termios_tty,(struct termio *) arg);
471 case TCSETAF:
472 flush_input(tty);
473
474 case TCSETAW:
475 wait_until_sent(tty);
476 case TCSETA:
477 return set_termio(termios_tty,(struct termio *) arg, termios_dev);
478 case TCXONC:
479 switch (arg) {
480 case TCOOFF:
481 tty->stopped = 1;
482 if (tty->stop)
483 (tty->stop)(tty);
484 TTY_WRITE_FLUSH(tty);
485 return 0;
486 case TCOON:
487 tty->stopped = 0;
488 if (tty->start)
489 (tty->start)(tty);
490 TTY_WRITE_FLUSH(tty);
491 return 0;
492 case TCIOFF:
493 if (STOP_CHAR(tty))
494 put_tty_queue(STOP_CHAR(tty),
495 &tty->write_q);
496 return 0;
497 case TCION:
498 if (START_CHAR(tty))
499 put_tty_queue(START_CHAR(tty),
500 &tty->write_q);
501 return 0;
502 }
503 return -EINVAL;
504 case TCFLSH:
505 if (arg==0)
506 flush_input(tty);
507 else if (arg==1)
508 flush_output(tty);
509 else if (arg==2) {
510 flush_input(tty);
511 flush_output(tty);
512 } else
513 return -EINVAL;
514 return 0;
515 case TIOCEXCL:
516 set_bit(TTY_EXCLUSIVE, &tty->flags);
517 return 0;
518 case TIOCNXCL:
519 clear_bit(TTY_EXCLUSIVE, &tty->flags);
520 return 0;
521 case TIOCSCTTY:
522 if (current->leader &&
523 (current->session == tty->session))
524 return 0;
525
526
527
528
529 if (!current->leader || (current->tty >= 0))
530 return -EPERM;
531 if (tty->session > 0) {
532
533
534
535
536 if ((arg == 1) && suser()) {
537
538
539
540 struct task_struct *p;
541
542 for_each_task(p)
543 if (p->tty == dev)
544 p->tty = -1;
545 } else
546 return -EPERM;
547 }
548 current->tty = dev;
549 tty->session = current->session;
550 tty->pgrp = current->pgrp;
551 return 0;
552 case TIOCGPGRP:
553 retval = verify_area(VERIFY_WRITE, (void *) arg,4);
554 if (!retval)
555 put_fs_long(termios_tty->pgrp,(unsigned long *) arg);
556 return retval;
557 case TIOCSPGRP:
558 if ((current->tty < 0) ||
559 (current->tty != termios_dev) ||
560 (termios_tty->session != current->session))
561 return -ENOTTY;
562 pgrp=get_fs_long((unsigned long *) arg);
563 if (pgrp < 0)
564 return -EINVAL;
565 if (session_of_pgrp(pgrp) != current->session)
566 return -EPERM;
567 termios_tty->pgrp = pgrp;
568 return 0;
569 case TIOCOUTQ:
570 retval = verify_area(VERIFY_WRITE, (void *) arg,4);
571 if (!retval)
572 put_fs_long(CHARS(&tty->write_q),
573 (unsigned long *) arg);
574 return retval;
575 case TIOCINQ:
576 retval = verify_area(VERIFY_WRITE, (void *) arg,4);
577 if (retval)
578 return retval;
579 if (L_CANON(tty))
580 put_fs_long(inq_canon(tty),
581 (unsigned long *) arg);
582 else
583 put_fs_long(CHARS(&tty->secondary),
584 (unsigned long *) arg);
585 return 0;
586 case TIOCSTI:
587 put_tty_queue(get_fs_byte((char *) arg), &tty->read_q);
588 return 0;
589 case TIOCGWINSZ:
590 return get_window_size(tty,(struct winsize *) arg);
591 case TIOCSWINSZ:
592 if (IS_A_PTY_MASTER(dev))
593 set_window_size(other_tty,(struct winsize *) arg);
594 return set_window_size(tty,(struct winsize *) arg);
595 case TIOCGSOFTCAR:
596 return -EINVAL;
597 case TIOCSSOFTCAR:
598 return -EINVAL;
599 case TIOCLINUX:
600 switch (get_fs_byte((char *)arg))
601 {
602 case 0:
603 return do_screendump(arg);
604 case 1:
605 return do_get_ps_info(arg);
606 #ifdef CONFIG_SELECTION
607 case 2:
608 return set_selection(arg);
609 case 3:
610 return paste_selection(tty);
611 #endif
612 default:
613 return -EINVAL;
614 }
615 case TIOCCONS:
616 if (IS_A_CONSOLE(dev)) {
617 if (!suser())
618 return -EPERM;
619 redirect = NULL;
620 return 0;
621 }
622 if (redirect)
623 return -EBUSY;
624 if (!suser())
625 return -EPERM;
626 if (IS_A_PTY_MASTER(dev))
627 redirect = other_tty;
628 else if (IS_A_PTY_SLAVE(dev))
629 redirect = tty;
630 else
631 return -EINVAL;
632 return 0;
633 case FIONBIO:
634 arg = get_fs_long((unsigned long *) arg);
635 if (arg)
636 file->f_flags |= O_NONBLOCK;
637 else
638 file->f_flags &= ~O_NONBLOCK;
639 return 0;
640 case TIOCNOTTY:
641 if (MINOR(file->f_rdev) != current->tty)
642 return -EINVAL;
643 if (current->leader)
644 disassociate_ctty(0);
645 current->tty = -1;
646 return 0;
647 case TIOCGETD:
648 retval = verify_area(VERIFY_WRITE, (void *) arg,4);
649 if (!retval)
650 put_fs_long(tty->disc, (unsigned long *) arg);
651 return retval;
652 case TIOCSETD:
653 arg = get_fs_long((unsigned long *) arg);
654 return tty_set_ldisc(tty, arg);
655 case TIOCGLCKTRMIOS:
656 arg = get_fs_long((unsigned long *) arg);
657 return get_lcktrmios(tty, (struct termios *) arg,
658 termios_dev);
659 case TIOCSLCKTRMIOS:
660 arg = get_fs_long((unsigned long *) arg);
661 return set_lcktrmios(tty, (struct termios *) arg,
662 termios_dev);
663 case TIOCPKT:
664 if (!IS_A_PTY_MASTER(dev))
665 return -EINVAL;
666 retval = verify_area(VERIFY_READ,
667 (unsigned long *)arg, sizeof (unsigned long));
668 if (retval)
669 return retval;
670 tty->packet = (get_fs_long ((unsigned long *)arg) != 0);
671 return 0;
672 case TCSBRK: case TCSBRKP:
673 wait_until_sent(tty);
674 if (!tty->ioctl)
675 return 0;
676 tty->ioctl(tty, file, cmd, arg);
677 return 0;
678 default:
679 if (tty->ioctl) {
680 retval = (tty->ioctl)(tty, file, cmd, arg);
681 if (retval != -EINVAL)
682 return retval;
683 }
684 if (ldiscs[tty->disc].ioctl) {
685 retval = (ldiscs[tty->disc].ioctl)
686 (tty, file, cmd, arg);
687 return retval;
688 }
689 return -EINVAL;
690 }
691 }