OSDN Git Service

* fhandler_termios.cc (fhandler_termios::tcsetpgrp): Send __SIGSETPGRP
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / fhandler_termios.cc
1 /* fhandler_termios.cc
2
3    Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009,
4    2010, 2011 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 #include "ntdll.h"
23
24 /* Common functions shared by tty/console */
25
26 void
27 fhandler_termios::tcinit (bool is_pty_master)
28 {
29   /* Initial termios values */
30
31   if (is_pty_master || !tc ()->initialized ())
32     {
33       tc ()->ti.c_iflag = BRKINT | ICRNL | IXON;
34       tc ()->ti.c_oflag = OPOST | ONLCR;
35       tc ()->ti.c_cflag = B38400 | CS8 | CREAD;
36       tc ()->ti.c_lflag = ISIG | ICANON | ECHO | IEXTEN;
37
38       tc ()->ti.c_cc[VDISCARD]  = CFLUSH;
39       tc ()->ti.c_cc[VEOL]              = CEOL;
40       tc ()->ti.c_cc[VEOL2]     = CEOL2;
41       tc ()->ti.c_cc[VEOF]              = CEOF;
42       tc ()->ti.c_cc[VERASE]    = CERASE;
43       tc ()->ti.c_cc[VINTR]     = CINTR;
44       tc ()->ti.c_cc[VKILL]     = CKILL;
45       tc ()->ti.c_cc[VLNEXT]    = CLNEXT;
46       tc ()->ti.c_cc[VMIN]              = 1;
47       tc ()->ti.c_cc[VQUIT]     = CQUIT;
48       tc ()->ti.c_cc[VREPRINT]  = CRPRNT;
49       tc ()->ti.c_cc[VSTART]    = CSTART;
50       tc ()->ti.c_cc[VSTOP]     = CSTOP;
51       tc ()->ti.c_cc[VSUSP]     = CSUSP;
52       tc ()->ti.c_cc[VSWTC]     = CSWTCH;
53       tc ()->ti.c_cc[VTIME]     = 0;
54       tc ()->ti.c_cc[VWERASE]   = CWERASE;
55
56       tc ()->ti.c_ispeed = tc ()->ti.c_ospeed = B38400;
57       tc ()->pgid = is_pty_master ? 0 : myself->pgid;
58       tc ()->initialized (true);
59     }
60 }
61
62 int
63 fhandler_termios::tcsetpgrp (const pid_t pgid)
64 {
65   termios_printf ("tty %d pgid %d, sid %d, tsid %d", tc ()->ntty, pgid,
66                     myself->sid, tc ()->getsid ());
67   if (myself->sid != tc ()->getsid ())
68     {
69       set_errno (EPERM);
70       return -1;
71     }
72   int res;
73   while (1)
74     {
75       res = bg_check (-SIGTTOU);
76
77       switch (res)
78         {
79         case bg_ok:
80           tc ()->setpgid (pgid);
81           if (tc ()->is_console)
82             tc ()->kill_pgrp (__SIGSETPGRP);
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 int
137 tty_min::is_orphaned_process_group (int pgid)
138 {
139   /* An orphaned process group is a process group in which the parent
140      of every member is either itself a member of the group or is not
141      a member of the group's session. */
142   termios_printf ("checking pgid %d, my sid %d, my parent %d", pgid, myself->sid, myself->ppid);
143   winpids pids ((DWORD) 0);
144   for (unsigned i = 0; i < pids.npids; i++)
145     {
146       _pinfo *p = pids[i];
147       termios_printf ("checking pid %d - has pgid %d\n", p->pid, p->pgid);
148       if (!p || !p->exists () || p->pgid != pgid)
149         continue;
150       pinfo ppid (p->ppid);
151       if (!ppid)
152         continue;
153       termios_printf ("ppid->pgid %d, ppid->sid %d", ppid->pgid, ppid->sid);
154       if (ppid->pgid != pgid && ppid->sid == myself->sid)
155         return 0;
156     }
157   return 1;
158 }
159
160 bg_check_types
161 fhandler_termios::bg_check (int sig)
162 {
163   if (!myself->pgid || tc ()->getpgid () == myself->pgid ||
164         myself->ctty != tc ()->ntty ||
165         ((sig == SIGTTOU) && !(tc ()->ti.c_lflag & TOSTOP)))
166     return bg_ok;
167
168   if (sig < 0)
169     sig = -sig;
170
171   termios_printf ("bg I/O pgid %d, tpgid %d, %s, ntty %s", myself->pgid, tc ()->getpgid (),
172                   myctty (), tc ()->ttyname ());
173
174   if (tc ()->getsid () == 0)
175     {
176       /* The pty has been closed by the master.  Return an EOF
177          indication.  FIXME: There is nothing to stop somebody
178          from reallocating this pty.  I think this is the case
179          which is handled by unlockpt on a Unix system.  */
180       termios_printf ("closed by master");
181       return bg_eof;
182     }
183
184   int sigs_ignored =
185     ((void *) global_sigs[sig].sa_handler == (void *) SIG_IGN) ||
186     (_main_tls->sigmask & SIGTOMASK (sig));
187
188   /* If the process is ignoring SIGTT*, then background IO is OK.  If
189      the process is not ignoring SIGTT*, then the sig is to be sent to
190      all processes in the process group (unless the process group of the
191      process is orphaned, in which case we return EIO). */
192   if (sigs_ignored)
193     return bg_ok;   /* Just allow the IO */
194   else if (tc ()->is_orphaned_process_group (myself->pgid))
195     {
196       termios_printf ("process group is orphaned");
197       set_errno (EIO);   /* This is an IO error */
198       return bg_error;
199     }
200   else
201     {
202       /* Don't raise a SIGTT* signal if we have already been
203          interrupted by another signal. */
204       if (WaitForSingleObject (signal_arrived, 0) != WAIT_OBJECT_0)
205         {
206           siginfo_t si = {0};
207           si.si_signo = sig;
208           si.si_code = SI_KERNEL;
209           kill_pgrp (myself->pgid, si);
210         }
211       return bg_signalled;
212     }
213 }
214
215 #define set_input_done(x) input_done = input_done || (x)
216
217 inline void
218 fhandler_termios::echo_erase (int force)
219 {
220   if (force || tc ()->ti.c_lflag & ECHO)
221     doecho ("\b \b", 3);
222 }
223
224 line_edit_status
225 fhandler_termios::line_edit (const char *rptr, int nread, termios& ti)
226 {
227   line_edit_status ret = line_edit_ok;
228   char c;
229   int input_done = 0;
230   bool sawsig = false;
231   int iscanon = ti.c_lflag & ICANON;
232
233   while (nread-- > 0)
234     {
235       c = *rptr++;
236
237       termios_printf ("char %c", c);
238
239       /* Check for special chars */
240
241       if (c == '\r')
242         {
243           if (ti.c_iflag & IGNCR)
244             continue;
245           if (ti.c_iflag & ICRNL)
246             {
247               c = '\n';
248               set_input_done (iscanon);
249             }
250         }
251       else if (c == '\n')
252         {
253           if (ti.c_iflag & INLCR)
254             c = '\r';
255           else
256             set_input_done (iscanon);
257         }
258
259       if (ti.c_iflag & ISTRIP)
260         c &= 0x7f;
261       if (ti.c_lflag & ISIG)
262         {
263           int sig;
264           if (CCEQ (ti.c_cc[VINTR], c))
265             sig = SIGINT;
266           else if (CCEQ (ti.c_cc[VQUIT], c))
267             sig = SIGQUIT;
268           else if (CCEQ (ti.c_cc[VSUSP], c))
269             sig = SIGTSTP;
270           else
271             goto not_a_sig;
272
273           termios_printf ("got interrupt %d, sending signal %d", c, sig);
274           eat_readahead (-1);
275           tc ()->kill_pgrp (sig);
276           ti.c_lflag &= ~FLUSHO;
277           sawsig = true;
278           goto restart_output;
279         }
280     not_a_sig:
281       if (ti.c_iflag & IXON)
282         {
283           if (CCEQ (ti.c_cc[VSTOP], c))
284             {
285               if (!tc ()->output_stopped)
286                 {
287                   tc ()->output_stopped = 1;
288                   acquire_output_mutex (INFINITE);
289                 }
290               continue;
291             }
292           else if (CCEQ (ti.c_cc[VSTART], c))
293             {
294     restart_output:
295               tc ()->output_stopped = 0;
296               release_output_mutex ();
297               continue;
298             }
299           else if ((ti.c_iflag & IXANY) && tc ()->output_stopped)
300             goto restart_output;
301         }
302       if (iscanon && ti.c_lflag & IEXTEN && CCEQ (ti.c_cc[VDISCARD], c))
303         {
304           ti.c_lflag ^= FLUSHO;
305           continue;
306         }
307       if (!iscanon)
308         /* nothing */;
309       else if (CCEQ (ti.c_cc[VERASE], c))
310         {
311           if (eat_readahead (1))
312             echo_erase ();
313           continue;
314         }
315       else if (CCEQ (ti.c_cc[VWERASE], c))
316         {
317           int ch;
318           do
319             if (!eat_readahead (1))
320               break;
321             else
322               echo_erase ();
323           while ((ch = peek_readahead (1)) >= 0 && !isspace (ch));
324           continue;
325         }
326       else if (CCEQ (ti.c_cc[VKILL], c))
327         {
328           int nchars = eat_readahead (-1);
329           if (ti.c_lflag & ECHO)
330             while (nchars--)
331               echo_erase (1);
332           continue;
333         }
334       else if (CCEQ (ti.c_cc[VREPRINT], c))
335         {
336           if (ti.c_lflag & ECHO)
337             {
338               doecho ("\n\r", 2);
339               doecho (rabuf, ralen);
340             }
341           continue;
342         }
343       else if (CCEQ (ti.c_cc[VEOF], c))
344         {
345           termios_printf ("EOF");
346           accept_input ();
347           ret = line_edit_input_done;
348           continue;
349         }
350       else if (CCEQ (ti.c_cc[VEOL], c) ||
351                CCEQ (ti.c_cc[VEOL2], c) ||
352                c == '\n')
353         {
354           set_input_done (1);
355           termios_printf ("EOL");
356         }
357
358       if (ti.c_iflag & IUCLC && isupper (c))
359         c = cyg_tolower (c);
360
361       put_readahead (c);
362       if (ti.c_lflag & ECHO)
363         doecho (&c, 1);
364       if (!iscanon || input_done)
365         {
366           int status = accept_input ();
367           if (status != 1)
368             {
369               ret = status ? line_edit_error : line_edit_pipe_full;
370               eat_readahead (1);
371               break;
372             }
373           ret = line_edit_input_done;
374           input_done = 0;
375         }
376     }
377
378   if (!iscanon && ralen > 0)
379     ret = line_edit_input_done;
380
381   if (sawsig)
382     ret = line_edit_signalled;
383
384   return ret;
385 }
386
387 _off64_t
388 fhandler_termios::lseek (_off64_t, int)
389 {
390   set_errno (ESPIPE);
391   return -1;
392 }
393
394 void
395 fhandler_termios::sigflush ()
396 {
397   /* FIXME: Checking get_ttyp() for NULL is not right since it should not
398      be NULL while this is alive.  However, we can conceivably close a
399      ctty while exiting and that will zero this. */
400   if (get_ttyp () && !(get_ttyp ()->ti.c_lflag & NOFLSH))
401     tcflush (TCIFLUSH);
402 }