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