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