This source file includes following definitions.
- flush
- flush_input
- flush_output
- wait_until_sent
- do_get_ps_info
- get_termios
- check_change
- set_termios
- get_termio
- set_termio
- 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 void flush(struct tty_queue * queue)
41 {
42 if (queue) {
43 cli();
44 queue->head = queue->tail;
45 sti();
46 wake_up_interruptible(&queue->proc_list);
47 }
48 }
49
50 void flush_input(struct tty_struct * tty)
51 {
52 tty->status_changed = 1;
53 tty->ctrl_status |= TIOCPKT_FLUSHREAD;
54 flush(&tty->read_q);
55 wake_up_interruptible(&tty->read_q.proc_list);
56 flush(&tty->secondary);
57 tty->secondary.data = 0;
58
59 if ((tty = tty->link) != NULL) {
60 flush(&tty->write_q);
61 wake_up_interruptible(&tty->write_q.proc_list);
62 }
63 }
64
65 void flush_output(struct tty_struct * tty)
66 {
67 tty->status_changed = 1;
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 int get_termios(struct tty_struct * tty, struct termios * termios)
131 {
132 int i;
133
134 i = verify_area(VERIFY_WRITE, termios, sizeof (*termios));
135 if (i)
136 return i;
137 for (i=0 ; i< (sizeof (*termios)) ; i++)
138 put_fs_byte( ((char *)tty->termios)[i] , i+(char *)termios );
139 return 0;
140 }
141
142 static int check_change(struct tty_struct * tty, int channel)
143 {
144
145
146
147 if (current->tty != channel)
148 return 0;
149 if (tty->pgrp <= 0 || tty->pgrp == current->pgrp)
150 return 0;
151 if (is_orphaned_pgrp(current->pgrp))
152 return -EIO;
153 if (is_ignored(SIGTTOU))
154 return 0;
155 (void) kill_pg(current->pgrp,SIGTTOU,1);
156 return -ERESTARTSYS;
157 }
158
159 static int set_termios(struct tty_struct * tty, struct termios * termios,
160 int channel)
161 {
162 int i;
163 struct termios old_termios = *tty->termios;
164
165 i = check_change(tty, channel);
166 if (i)
167 return i;
168 for (i=0 ; i< (sizeof (*termios)) ; i++)
169 ((char *)tty->termios)[i]=get_fs_byte(i+(char *)termios);
170
171
172
173
174 if (IS_A_PTY_MASTER(channel)) tty->termios->c_lflag &= ~ECHO;
175
176 if (tty->set_termios)
177 (*tty->set_termios)(tty, &old_termios);
178
179 return 0;
180 }
181
182 static int get_termio(struct tty_struct * tty, struct termio * termio)
183 {
184 int i;
185 struct termio tmp_termio;
186
187 i = verify_area(VERIFY_WRITE, termio, sizeof (*termio));
188 if (i)
189 return i;
190 tmp_termio.c_iflag = tty->termios->c_iflag;
191 tmp_termio.c_oflag = tty->termios->c_oflag;
192 tmp_termio.c_cflag = tty->termios->c_cflag;
193 tmp_termio.c_lflag = tty->termios->c_lflag;
194 tmp_termio.c_line = tty->termios->c_line;
195 for(i=0 ; i < NCC ; i++)
196 tmp_termio.c_cc[i] = tty->termios->c_cc[i];
197 for (i=0 ; i< (sizeof (*termio)) ; i++)
198 put_fs_byte( ((char *)&tmp_termio)[i] , i+(char *)termio );
199 return 0;
200 }
201
202
203
204
205 static int set_termio(struct tty_struct * tty, struct termio * termio,
206 int channel)
207 {
208 int i;
209 struct termio tmp_termio;
210 struct termios old_termios = *tty->termios;
211
212 i = check_change(tty, channel);
213 if (i)
214 return i;
215 for (i=0 ; i< (sizeof (*termio)) ; i++)
216 ((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio);
217
218
219 if ((tmp_termio.c_iflag & IXON) &&
220 !(tty->termios->c_iflag & IXON))
221 {
222 tty->status_changed = 1;
223 tty->ctrl_status |= TIOCPKT_DOSTOP;
224 }
225
226 if ((tty->termios->c_iflag & IXON) &&
227 !(tmp_termio.c_iflag & IXON))
228 {
229 tty->status_changed = 1;
230 tty->ctrl_status |= TIOCPKT_NOSTOP;
231 }
232
233 *(unsigned short *)&tty->termios->c_iflag = tmp_termio.c_iflag;
234 *(unsigned short *)&tty->termios->c_oflag = tmp_termio.c_oflag;
235 *(unsigned short *)&tty->termios->c_cflag = tmp_termio.c_cflag;
236 *(unsigned short *)&tty->termios->c_lflag = tmp_termio.c_lflag;
237 tty->termios->c_line = tmp_termio.c_line;
238 for(i=0 ; i < NCC ; i++)
239 tty->termios->c_cc[i] = tmp_termio.c_cc[i];
240
241 if (tty->set_termios)
242 (*tty->set_termios)(tty, &old_termios);
243
244 return 0;
245 }
246
247 static int set_window_size(struct tty_struct * tty, struct winsize * ws)
248 {
249 int i,changed;
250 char c, * tmp;
251
252 if (!ws)
253 return -EINVAL;
254 tmp = (char *) &tty->winsize;
255 changed = 0;
256 for (i = 0; i < sizeof (*ws) ; i++,tmp++) {
257 c = get_fs_byte(i + (char *) ws);
258 if (c == *tmp)
259 continue;
260 changed = 1;
261 *tmp = c;
262 }
263 if (changed)
264 kill_pg(tty->pgrp, SIGWINCH, 1);
265 return 0;
266 }
267
268 static int get_window_size(struct tty_struct * tty, struct winsize * ws)
269 {
270 int i;
271 char * tmp;
272
273 if (!ws)
274 return -EINVAL;
275 i = verify_area(VERIFY_WRITE, ws, sizeof (*ws));
276 if (i)
277 return i;
278 tmp = (char *) ws;
279 for (i = 0; i < sizeof (struct winsize) ; i++,tmp++)
280 put_fs_byte(((char *) &tty->winsize)[i], tmp);
281 return 0;
282 }
283
284
285 static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
286 {
287 if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS) ||
288 !(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED))
289 return -EINVAL;
290
291 if (tty->disc == ldisc)
292 return 0;
293
294
295 wait_until_sent(tty);
296 flush_input(tty);
297 if (ldiscs[tty->disc].close)
298 ldiscs[tty->disc].close(tty);
299
300
301 tty->disc = ldisc;
302 if (ldiscs[tty->disc].open)
303 return(ldiscs[tty->disc].open(tty));
304 else
305 return 0;
306 }
307
308
309 int tty_ioctl(struct inode * inode, struct file * file,
310 unsigned int cmd, unsigned long arg)
311 {
312 struct tty_struct * tty;
313 struct tty_struct * other_tty;
314 struct tty_struct * termios_tty;
315 int pgrp;
316 int dev;
317 int termios_dev;
318 int retval;
319
320 if (MAJOR(file->f_rdev) != 4) {
321 printk("tty_ioctl: tty pseudo-major != 4\n");
322 return -EINVAL;
323 }
324 dev = MINOR(file->f_rdev);
325 tty = TTY_TABLE(dev);
326 if (!tty)
327 return -EINVAL;
328 if (IS_A_PTY(dev))
329 other_tty = tty_table[PTY_OTHER(dev)];
330 else
331 other_tty = NULL;
332 termios_tty = tty;
333 termios_dev = dev;
334 if (IS_A_PTY_MASTER(dev)) {
335 termios_tty = other_tty;
336 termios_dev = PTY_OTHER(dev);
337 }
338 switch (cmd) {
339 case TCGETS:
340 return get_termios(termios_tty,(struct termios *) arg);
341 case TCSETSF:
342 flush_input(tty);
343
344 case TCSETSW:
345 wait_until_sent(tty);
346
347 case TCSETS:
348 return set_termios(termios_tty,(struct termios *) arg, termios_dev);
349 case TCGETA:
350 return get_termio(termios_tty,(struct termio *) arg);
351 case TCSETAF:
352 flush_input(tty);
353
354 case TCSETAW:
355 wait_until_sent(tty);
356 case TCSETA:
357 return set_termio(termios_tty,(struct termio *) arg, termios_dev);
358 case TCXONC:
359 switch (arg) {
360 case TCOOFF:
361 tty->stopped = 1;
362 TTY_WRITE_FLUSH(tty);
363 return 0;
364 case TCOON:
365 tty->stopped = 0;
366 TTY_WRITE_FLUSH(tty);
367 return 0;
368 case TCIOFF:
369 if (STOP_CHAR(tty))
370 put_tty_queue(STOP_CHAR(tty),
371 &tty->write_q);
372 return 0;
373 case TCION:
374 if (START_CHAR(tty))
375 put_tty_queue(START_CHAR(tty),
376 &tty->write_q);
377 return 0;
378 }
379 return -EINVAL;
380 case TCFLSH:
381 if (arg==0)
382 flush_input(tty);
383 else if (arg==1)
384 flush_output(tty);
385 else if (arg==2) {
386 flush_input(tty);
387 flush_output(tty);
388 } else
389 return -EINVAL;
390 return 0;
391 case TIOCEXCL:
392 return -EINVAL;
393 case TIOCNXCL:
394 return -EINVAL;
395 case TIOCSCTTY:
396 if ((current->leader && current->tty < 0 &&
397 tty->session == 0) ||
398 (arg == 1 && suser())) {
399 current->tty = dev;
400 tty->session = current->session;
401 tty->pgrp = current->pgrp;
402 return 0;
403 }
404 return -EPERM;
405 case TIOCGPGRP:
406 retval = verify_area(VERIFY_WRITE, (void *) arg,4);
407 if (!retval)
408 put_fs_long(termios_tty->pgrp,(unsigned long *) arg);
409 return retval;
410 case TIOCSPGRP:
411 if ((current->tty < 0) ||
412 (current->tty != termios_dev) ||
413 (termios_tty->session != current->session))
414 return -ENOTTY;
415 pgrp=get_fs_long((unsigned long *) arg);
416 if (pgrp < 0)
417 return -EINVAL;
418 if (session_of_pgrp(pgrp) != current->session)
419 return -EPERM;
420 termios_tty->pgrp = pgrp;
421 return 0;
422 case TIOCOUTQ:
423 retval = verify_area(VERIFY_WRITE, (void *) arg,4);
424 if (!retval)
425 put_fs_long(CHARS(&tty->write_q),
426 (unsigned long *) arg);
427 return retval;
428 case TIOCINQ:
429 retval = verify_area(VERIFY_WRITE, (void *) arg,4);
430 if (retval)
431 return retval;
432 if (L_CANON(tty) && !tty->secondary.data)
433 put_fs_long(0, (unsigned long *) arg);
434 else
435 put_fs_long(CHARS(&tty->secondary),
436 (unsigned long *) arg);
437 return 0;
438 case TIOCSTI:
439 return -EINVAL;
440 case TIOCGWINSZ:
441 return get_window_size(tty,(struct winsize *) arg);
442 case TIOCSWINSZ:
443 if (IS_A_PTY_MASTER(dev))
444 set_window_size(other_tty,(struct winsize *) arg);
445 return set_window_size(tty,(struct winsize *) arg);
446 case TIOCGSOFTCAR:
447 return -EINVAL;
448 case TIOCSSOFTCAR:
449 return -EINVAL;
450 case TIOCLINUX:
451 switch (get_fs_byte((char *)arg))
452 {
453 case 0:
454 return do_screendump(arg);
455 case 1:
456 return do_get_ps_info(arg);
457 #ifdef CONFIG_SELECTION
458 case 2:
459 return set_selection(arg);
460 case 3:
461 return paste_selection(tty);
462 #endif
463 default:
464 return -EINVAL;
465 }
466 case TIOCCONS:
467 if (IS_A_CONSOLE(dev)) {
468 if (!suser())
469 return -EPERM;
470 redirect = NULL;
471 return 0;
472 }
473 if (redirect)
474 return -EBUSY;
475 if (!suser())
476 return -EPERM;
477 if (IS_A_PTY_MASTER(dev))
478 redirect = other_tty;
479 else if (IS_A_PTY_SLAVE(dev))
480 redirect = tty;
481 else
482 return -EINVAL;
483 return 0;
484 case FIONBIO:
485 arg = get_fs_long((unsigned long *) arg);
486 if (arg)
487 file->f_flags |= O_NONBLOCK;
488 else
489 file->f_flags &= ~O_NONBLOCK;
490 return 0;
491 case TIOCNOTTY:
492 if (MINOR(file->f_rdev) != current->tty)
493 return -EINVAL;
494 current->tty = -1;
495 if (current->leader) {
496 if (tty->pgrp > 0)
497 kill_pg(tty->pgrp, SIGHUP, 0);
498 tty->pgrp = -1;
499 tty->session = 0;
500 }
501 return 0;
502 case TIOCGETD:
503 retval = verify_area(VERIFY_WRITE, (void *) arg,4);
504 if (!retval)
505 put_fs_long(tty->disc, (unsigned long *) arg);
506 return retval;
507 case TIOCSETD:
508 arg = get_fs_long((unsigned long *) arg);
509 return tty_set_ldisc(tty, arg);
510 case TIOCPKT:
511 {
512 int on;
513 if (!IS_A_PTY_MASTER(dev))
514 return -EINVAL;
515 retval = verify_area(VERIFY_READ, (unsigned long *)arg, sizeof (int));
516 if (retval)
517 return retval;
518 on=get_fs_long ((unsigned long *)arg);
519 if (on )
520 tty->packet = 1;
521 else
522 tty->packet = 0;
523 return (0);
524 }
525
526 default:
527 if (tty->ioctl) {
528 retval = (tty->ioctl)(tty, file, cmd, arg);
529 if (retval != -EINVAL)
530 return retval;
531 }
532 if (ldiscs[tty->disc].ioctl) {
533 retval = (ldiscs[tty->disc].ioctl)
534 (tty, file, cmd, arg);
535 return retval;
536 }
537 return -EINVAL;
538 }
539 }