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