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