OSDN Git Service

gas/opcodes: blackfin: move dsp mac func defines to common header
[pf3gnuchains/sourceware.git] / winsup / cygwin / fhandler_termios.cc
1 /* fhandler_termios.cc
2
3    Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009,
4    2010 Red Hat, Inc.
5
6 This file is part of Cygwin.
7
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
10 details. */
11
12 #include "winsup.h"
13 #include <stdlib.h>
14 #include <ctype.h>
15 #include "cygerrno.h"
16 #include "path.h"
17 #include "fhandler.h"
18 #include "sigproc.h"
19 #include "pinfo.h"
20 #include "tty.h"
21 #include "cygtls.h"
22
23 /* Common functions shared by tty/console */
24
25 void
26 fhandler_termios::tcinit (tty_min *this_tc, bool is_pty_master)
27 {
28   /* Initial termios values */
29
30   tc = this_tc;
31
32   if (is_pty_master || !tc->initialized ())
33     {
34       tc->ti.c_iflag = BRKINT | ICRNL | IXON;
35       tc->ti.c_oflag = OPOST | ONLCR;
36       tc->ti.c_cflag = B38400 | CS8 | CREAD;
37       tc->ti.c_lflag = ISIG | ICANON | ECHO | IEXTEN;
38
39       tc->ti.c_cc[VDISCARD]     = CFLUSH;
40       tc->ti.c_cc[VEOL]         = CEOL;
41       tc->ti.c_cc[VEOL2]        = CEOL2;
42       tc->ti.c_cc[VEOF]         = CEOF;
43       tc->ti.c_cc[VERASE]       = CERASE;
44       tc->ti.c_cc[VINTR]        = CINTR;
45       tc->ti.c_cc[VKILL]        = CKILL;
46       tc->ti.c_cc[VLNEXT]       = CLNEXT;
47       tc->ti.c_cc[VMIN]         = 1;
48       tc->ti.c_cc[VQUIT]        = CQUIT;
49       tc->ti.c_cc[VREPRINT]     = CRPRNT;
50       tc->ti.c_cc[VSTART]       = CSTART;
51       tc->ti.c_cc[VSTOP]        = CSTOP;
52       tc->ti.c_cc[VSUSP]        = CSUSP;
53       tc->ti.c_cc[VSWTC]        = CSWTCH;
54       tc->ti.c_cc[VTIME]        = 0;
55       tc->ti.c_cc[VWERASE]      = CWERASE;
56
57       tc->ti.c_ispeed = tc->ti.c_ospeed = B38400;
58       tc->pgid = is_pty_master ? 0 : myself->pgid;
59       tc->initialized (true);
60     }
61 }
62
63 int
64 fhandler_termios::tcsetpgrp (const pid_t pgid)
65 {
66   termios_printf ("tty %d pgid %d, sid %d, tsid %d", tc->ntty, pgid,
67                     myself->sid, tc->getsid ());
68   if (myself->sid != tc->getsid ())
69     {
70       set_errno (EPERM);
71       return -1;
72     }
73   int res;
74   while (1)
75     {
76       res = bg_check (-SIGTTOU);
77
78       switch (res)
79         {
80         case bg_ok:
81           tc->setpgid (pgid);
82           init_console_handler (tc->gethwnd ());
83           res = 0;
84           break;
85         case bg_signalled:
86           if (_my_tls.call_signal_handler ())
87             continue;
88           set_errno (EINTR);
89           /* fall through intentionally */
90         default:
91           res = -1;
92           break;
93         }
94       break;
95     }
96   return res;
97 }
98
99 int
100 fhandler_termios::tcgetpgrp ()
101 {
102   if (myself->ctty != -1 && myself->ctty == tc->ntty)
103     return tc->pgid;
104   set_errno (ENOTTY);
105   return -1;
106 }
107
108 int
109 fhandler_pty_master::tcgetpgrp ()
110 {
111   return tc->pgid;
112 }
113
114 void
115 tty_min::kill_pgrp (int sig)
116 {
117   int killself = 0;
118   winpids pids ((DWORD) PID_MAP_RW);
119   siginfo_t si = {0};
120   si.si_signo = sig;
121   si.si_code = SI_KERNEL;
122   for (unsigned i = 0; i < pids.npids; i++)
123     {
124       _pinfo *p = pids[i];
125       if (!p->exists () || p->ctty != ntty || p->pgid != pgid)
126         continue;
127       if (p == myself)
128         killself++;
129       else
130         sig_send (p, si);
131     }
132   if (killself)
133     sig_send (myself, si);
134 }
135
136 bg_check_types
137 fhandler_termios::bg_check (int sig)
138 {
139   if (!myself->pgid || tc->getpgid () == myself->pgid ||
140         myself->ctty != tc->ntty ||
141         ((sig == SIGTTOU) && !(tc->ti.c_lflag & TOSTOP)))
142     return bg_ok;
143
144   if (sig < 0)
145     sig = -sig;
146
147   termios_printf ("bg I/O pgid %d, tpgid %d, %s, ntty tty%d", myself->pgid, tc->getpgid (),
148                   myctty (), tc->ntty);
149
150   if (tc->getsid () == 0)
151     {
152       /* The pty has been closed by the master.  Return an EOF
153          indication.  FIXME: There is nothing to stop somebody
154          from reallocating this pty.  I think this is the case
155          which is handled by unlockpt on a Unix system.  */
156       termios_printf ("closed by master");
157       return bg_eof;
158     }
159
160   /* If the process group is no more or if process is ignoring or blocks 'sig',
161      return with error */
162   int pgid_gone = !pid_exists (myself->pgid);
163   int sigs_ignored =
164     ((void *) global_sigs[sig].sa_handler == (void *) SIG_IGN) ||
165     (_main_tls->sigmask & SIGTOMASK (sig));
166
167   if (pgid_gone)
168     goto setEIO;
169   else if (!sigs_ignored)
170     /* nothing */;
171   else if (sig == SIGTTOU)
172     return bg_ok;               /* Just allow the output */
173   else
174     goto setEIO;        /* This is an output error */
175
176   /* Don't raise a SIGTT* signal if we have already been interrupted
177      by another signal. */
178   if (WaitForSingleObject (signal_arrived, 0) != WAIT_OBJECT_0)
179     {
180       siginfo_t si = {0};
181       si.si_signo = sig;
182       si.si_code = SI_KERNEL;
183       kill_pgrp (myself->pgid, si);
184     }
185   return bg_signalled;
186
187 setEIO:
188   set_errno (EIO);
189   return bg_error;
190 }
191
192 #define set_input_done(x) input_done = input_done || (x)
193
194 inline void
195 fhandler_termios::echo_erase (int force)
196 {
197   if (force || tc->ti.c_lflag & ECHO)
198     doecho ("\b \b", 3);
199 }
200
201 line_edit_status
202 fhandler_termios::line_edit (const char *rptr, int nread, termios& ti)
203 {
204   line_edit_status ret = line_edit_ok;
205   char c;
206   int input_done = 0;
207   bool sawsig = false;
208   int iscanon = ti.c_lflag & ICANON;
209
210   while (nread-- > 0)
211     {
212       c = *rptr++;
213
214       termios_printf ("char %c", c);
215
216       /* Check for special chars */
217
218       if (c == '\r')
219         {
220           if (ti.c_iflag & IGNCR)
221             continue;
222           if (ti.c_iflag & ICRNL)
223             {
224               c = '\n';
225               set_input_done (iscanon);
226             }
227         }
228       else if (c == '\n')
229         {
230           if (ti.c_iflag & INLCR)
231             c = '\r';
232           else
233             set_input_done (iscanon);
234         }
235
236       if (ti.c_iflag & ISTRIP)
237         c &= 0x7f;
238       if (ti.c_lflag & ISIG)
239         {
240           int sig;
241           if (CCEQ (ti.c_cc[VINTR], c))
242             sig = SIGINT;
243           else if (CCEQ (ti.c_cc[VQUIT], c))
244             sig = SIGQUIT;
245           else if (CCEQ (ti.c_cc[VSUSP], c))
246             sig = SIGTSTP;
247           else
248             goto not_a_sig;
249
250           termios_printf ("got interrupt %d, sending signal %d", c, sig);
251           eat_readahead (-1);
252           tc->kill_pgrp (sig);
253           ti.c_lflag &= ~FLUSHO;
254           sawsig = true;
255           goto restart_output;
256         }
257     not_a_sig:
258       if (ti.c_iflag & IXON)
259         {
260           if (CCEQ (ti.c_cc[VSTOP], c))
261             {
262               if (!tc->output_stopped)
263                 {
264                   tc->output_stopped = 1;
265                   acquire_output_mutex (INFINITE);
266                 }
267               continue;
268             }
269           else if (CCEQ (ti.c_cc[VSTART], c))
270             {
271     restart_output:
272               tc->output_stopped = 0;
273               release_output_mutex ();
274               continue;
275             }
276           else if ((ti.c_iflag & IXANY) && tc->output_stopped)
277             goto restart_output;
278         }
279       if (iscanon && ti.c_lflag & IEXTEN && CCEQ (ti.c_cc[VDISCARD], c))
280         {
281           ti.c_lflag ^= FLUSHO;
282           continue;
283         }
284       if (!iscanon)
285         /* nothing */;
286       else if (CCEQ (ti.c_cc[VERASE], c))
287         {
288           if (eat_readahead (1))
289             echo_erase ();
290           continue;
291         }
292       else if (CCEQ (ti.c_cc[VWERASE], c))
293         {
294           int ch;
295           do
296             if (!eat_readahead (1))
297               break;
298             else
299               echo_erase ();
300           while ((ch = peek_readahead (1)) >= 0 && !isspace (ch));
301           continue;
302         }
303       else if (CCEQ (ti.c_cc[VKILL], c))
304         {
305           int nchars = eat_readahead (-1);
306           if (ti.c_lflag & ECHO)
307             while (nchars--)
308               echo_erase (1);
309           continue;
310         }
311       else if (CCEQ (ti.c_cc[VREPRINT], c))
312         {
313           if (ti.c_lflag & ECHO)
314             {
315               doecho ("\n\r", 2);
316               doecho (rabuf, ralen);
317             }
318           continue;
319         }
320       else if (CCEQ (ti.c_cc[VEOF], c))
321         {
322           termios_printf ("EOF");
323           accept_input ();
324           ret = line_edit_input_done;
325           continue;
326         }
327       else if (CCEQ (ti.c_cc[VEOL], c) ||
328                CCEQ (ti.c_cc[VEOL2], c) ||
329                c == '\n')
330         {
331           set_input_done (1);
332           termios_printf ("EOL");
333         }
334
335       if (ti.c_iflag & IUCLC && isupper (c))
336         c = cyg_tolower (c);
337
338       put_readahead (c);
339       if (ti.c_lflag & ECHO)
340         doecho (&c, 1);
341       if (!iscanon || input_done)
342         {
343           int status = accept_input ();
344           if (status != 1)
345             {
346               ret = status ? line_edit_error : line_edit_pipe_full;
347               eat_readahead (1);
348               break;
349             }
350           ret = line_edit_input_done;
351           input_done = 0;
352         }
353     }
354
355   if (!iscanon && ralen > 0)
356     ret = line_edit_input_done;
357
358   if (sawsig)
359     ret = line_edit_signalled;
360
361   return ret;
362 }
363
364 _off64_t
365 fhandler_termios::lseek (_off64_t, int)
366 {
367   set_errno (ESPIPE);
368   return -1;
369 }