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