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