1/****************************************************************************
2 *                                                                          *
3 *                         GNAT RUN-TIME COMPONENTS                         *
4 *                                                                          *
5 *                               E X P E C T                                *
6 *                                                                          *
7 *                          C Implementation File                           *
8 *                                                                          *
9 *                     Copyright (C) 2001-2015, AdaCore                     *
10 *                                                                          *
11 * GNAT is free software;  you can  redistribute it  and/or modify it under *
12 * terms of the  GNU General Public License as published  by the Free Soft- *
13 * ware  Foundation;  either version 3,  or (at your option) any later ver- *
14 * sion.  GNAT is distributed in the hope that it will be useful, but WITH- *
15 * OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY *
16 * or FITNESS FOR A PARTICULAR PURPOSE.                                     *
17 *                                                                          *
18 * As a special exception under Section 7 of GPL version 3, you are granted *
19 * additional permissions described in the GCC Runtime Library Exception,   *
20 * version 3.1, as published by the Free Software Foundation.               *
21 *                                                                          *
22 * You should have received a copy of the GNU General Public License and    *
23 * a copy of the GCC Runtime Library Exception along with this program;     *
24 * see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    *
25 * <http://www.gnu.org/licenses/>.                                          *
26 *                                                                          *
27 * GNAT was originally developed  by the GNAT team at  New York University. *
28 * Extensive contributions were provided by Ada Core Technologies Inc.      *
29 *                                                                          *
30 ****************************************************************************/
31
32#ifdef __alpha_vxworks
33#include "vxWorks.h"
34#endif
35
36#ifdef IN_RTS
37#define POSIX
38#include "tconfig.h"
39#include "tsystem.h"
40#else
41#include "config.h"
42#include "system.h"
43#endif
44
45#include <sys/types.h>
46
47#ifdef __MINGW32__
48# if OLD_MINGW
49#  include <sys/wait.h>
50# endif
51#elif defined (__vxworks) && defined (__RTP__)
52# include <wait.h>
53#elif defined (__Lynx__)
54  /* ??? See comment in adaint.c.  */
55# define GCC_RESOURCE_H
56# include <sys/wait.h>
57#elif defined (__PikeOS__)
58  /* No wait.h available */
59#else
60#include <sys/wait.h>
61#endif
62
63/* This file provides the low level functionalities needed to implement Expect
64   capabilities in GNAT.Expect.
65   Implementations for unix and windows systems is provided.
66   Dummy stubs are also provided for other systems. */
67
68#ifdef _AIX
69/* Work around the fact that gcc/cpp does not define "__unix__" under AiX.  */
70#define __unix__
71#endif
72
73#ifdef __APPLE__
74/* Work around the fact that gcc/cpp does not define "__unix__" on Darwin.  */
75#define __unix__
76#endif
77
78#ifdef _WIN32
79
80#include <windows.h>
81#include <process.h>
82#include <signal.h>
83#include <io.h>
84#include "mingw32.h"
85
86void
87__gnat_kill (int pid, int sig, int close)
88{
89  HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
90  if (h == NULL)
91    return;
92  if (sig == 9)
93    {
94      TerminateProcess (h, 0);
95      __gnat_win32_remove_handle (NULL, pid);
96    }
97  else if (sig == SIGINT)
98    GenerateConsoleCtrlEvent (CTRL_C_EVENT, pid);
99  else if (sig == SIGBREAK)
100    GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, pid);
101  /* ??? The last two alternatives don't really work. SIGBREAK requires setting
102     up process groups at start time which we don't do; treating SIGINT is just
103     not possible apparently. So we really only support signal 9. Fortunately
104     that's all we use in GNAT.Expect */
105
106  CloseHandle (h);
107}
108
109int
110__gnat_waitpid (int pid)
111{
112  HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
113  DWORD exitcode = 1;
114  DWORD res;
115
116  if (h != NULL)
117    {
118      res = WaitForSingleObject (h, INFINITE);
119      GetExitCodeProcess (h, &exitcode);
120      CloseHandle (h);
121    }
122
123  __gnat_win32_remove_handle (NULL, pid);
124  return (int) exitcode;
125}
126
127int
128__gnat_expect_fork (void)
129{
130  return 0;
131}
132
133void
134__gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[])
135{
136  *pid = __gnat_portable_no_block_spawn (argv);
137}
138
139int
140__gnat_pipe (int *fd)
141{
142  HANDLE read, write;
143
144  CreatePipe (&read, &write, NULL, 0);
145  fd[0]=_open_osfhandle ((intptr_t)read, 0);
146  fd[1]=_open_osfhandle ((intptr_t)write, 0);
147  return 0;  /* always success */
148}
149
150int
151__gnat_expect_poll (int *fd,
152                    int num_fd,
153                    int timeout,
154                    int *dead_process,
155                    int *is_set)
156{
157#define MAX_DELAY 100
158
159  int i, delay, infinite = 0;
160  DWORD avail;
161  HANDLE handles[num_fd];
162
163  *dead_process = 0;
164
165  for (i = 0; i < num_fd; i++)
166    is_set[i] = 0;
167
168  for (i = 0; i < num_fd; i++)
169    handles[i] = (HANDLE) _get_osfhandle (fd [i]);
170
171  /* Start with small delays, and then increase them, to avoid polling too
172     much when waiting a long time */
173  delay = 5;
174
175  if (timeout < 0)
176    infinite = 1;
177
178  while (1)
179    {
180      for (i = 0; i < num_fd; i++)
181        {
182          if (!PeekNamedPipe (handles [i], NULL, 0, NULL, &avail, NULL))
183            {
184              *dead_process = i + 1;
185              return -1;
186            }
187          if (avail > 0)
188            {
189              is_set[i] = 1;
190              return 1;
191            }
192        }
193
194      if (!infinite && timeout <= 0)
195        return 0;
196
197      Sleep (delay);
198      timeout -= delay;
199
200      if (delay < MAX_DELAY)
201        delay += 10;
202    }
203}
204
205#elif defined (VMS)
206#include <unistd.h>
207#include <stdio.h>
208#include <unixio.h>
209#include <stdlib.h>
210#include <string.h>
211#include <vms/descrip.h>
212#include <stdio.h>
213#include <vms/stsdef.h>
214#include <vms/iodef.h>
215#include <signal.h>
216
217void
218__gnat_kill (int pid, int sig, int close)
219{
220  kill (pid, sig);
221}
222
223int
224__gnat_waitpid (int pid)
225{
226  int status = 0;
227
228  waitpid (pid, &status, 0);
229  status = WEXITSTATUS (status);
230
231  return status;
232}
233
234int
235__gnat_pipe (int *fd)
236{
237  return pipe (fd);
238}
239
240int
241__gnat_expect_fork (void)
242{
243  return -1;
244}
245
246void
247__gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[])
248{
249  *pid = (int) getpid ();
250  /* Since cmd is fully qualified, it is incorrect to call execvp */
251  execv (cmd, argv);
252  _exit (1);
253}
254
255int
256__gnat_expect_poll (int *fd,
257                    int num_fd,
258                    int timeout,
259                    int *dead_process,
260                    int *is_set)
261{
262  int i, num, ready = 0;
263  unsigned int status;
264  int mbxchans [num_fd];
265  struct dsc$descriptor_s mbxname;
266  struct io_status_block {
267    short int condition;
268    short int count;
269    int dev;
270  } iosb;
271  char buf [256];
272
273  *dead_process = 0;
274
275  for (i = 0; i < num_fd; i++)
276    is_set[i] = 0;
277
278  for (i = 0; i < num_fd; i++)
279    {
280
281      /* Get name of the mailbox used in the pipe */
282      getname (fd [i], buf);
283
284      /* Assign a channel to the mailbox */
285      if (strlen (buf) > 0)
286	{
287	  mbxname.dsc$w_length = strlen (buf);
288	  mbxname.dsc$b_dtype = DSC$K_DTYPE_T;
289	  mbxname.dsc$b_class = DSC$K_CLASS_S;
290	  mbxname.dsc$a_pointer = buf;
291
292	  status = SYS$ASSIGN (&mbxname, &mbxchans[i], 0, 0, 0);
293
294	  if ((status & 1) != 1)
295	    {
296              ready = -1;
297              dead_process = i + 1;
298              return ready;
299	    }
300	}
301    }
302
303  num = timeout / 100;
304
305  while (1)
306    {
307      for (i = 0; i < num_fd; i++)
308	{
309	  if (mbxchans[i] > 0)
310	    {
311
312	      /* Peek in the mailbox to see if there's data */
313	      status = SYS$QIOW
314		(0, mbxchans[i], IO$_SENSEMODE|IO$M_READERCHECK,
315		 &iosb, 0, 0, 0, 0, 0, 0, 0, 0);
316
317	      if ((status & 1) != 1)
318		{
319		  ready = -1;
320		  goto deassign;
321		}
322
323	      if (iosb.count > 0)
324		{
325		  is_set[i] = 1;
326		  ready = 1;
327		  goto deassign;
328		}
329	    }
330	}
331
332      if (timeout > 0 && num == 0)
333	{
334	  ready = 0;
335	  goto deassign;
336	}
337
338      usleep (100000);
339      num--;
340    }
341
342 deassign:
343
344  /* Deassign channels assigned above */
345  for (i = 0; i < num_fd; i++)
346    {
347      if (mbxchans[i] > 0)
348	status = SYS$DASSGN (mbxchans[i]);
349    }
350
351  return ready;
352}
353#elif defined (__unix__)
354
355#ifdef __hpux__
356#include <sys/ptyio.h>
357#endif
358
359#include <sys/time.h>
360
361#ifndef NO_FD_SET
362#define SELECT_MASK fd_set
363#else /* !NO_FD_SET */
364#ifndef _AIX
365typedef long fd_mask;
366#endif /* _AIX */
367#ifdef _IBMR2
368#define SELECT_MASK void
369#else /* !_IBMR2 */
370#define SELECT_MASK int
371#endif /* !_IBMR2 */
372#endif /* !NO_FD_SET */
373
374void
375__gnat_kill (int pid, int sig, int close)
376{
377  kill (pid, sig);
378}
379
380int
381__gnat_waitpid (int pid)
382{
383  int status = 0;
384
385  waitpid (pid, &status, 0);
386  status = WEXITSTATUS (status);
387
388  return status;
389}
390
391int
392__gnat_pipe (int *fd)
393{
394  return pipe (fd);
395}
396
397int
398__gnat_expect_fork (void)
399{
400  return fork ();
401}
402
403void
404__gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[])
405{
406  *pid = (int) getpid ();
407  /* Since cmd is fully qualified, it is incorrect to call execvp */
408  execv (cmd, argv);
409  _exit (1);
410}
411
412int
413__gnat_expect_poll (int *fd,
414                    int num_fd,
415                    int timeout,
416                    int *dead_process,
417                    int *is_set)
418{
419  struct timeval tv;
420  SELECT_MASK rset;
421  SELECT_MASK eset;
422
423  int max_fd = 0;
424  int ready;
425  int i;
426  int received;
427
428  *dead_process = 0;
429
430  tv.tv_sec  = timeout / 1000;
431  tv.tv_usec = (timeout % 1000) * 1000;
432
433  do {
434    FD_ZERO (&rset);
435    FD_ZERO (&eset);
436
437    for (i = 0; i < num_fd; i++)
438      {
439        FD_SET (fd[i], &rset);
440        FD_SET (fd[i], &eset);
441
442        if (fd[i] > max_fd)
443	  max_fd = fd[i];
444      }
445
446    ready =
447      select (max_fd + 1, &rset, NULL, &eset, timeout == -1 ? NULL : &tv);
448
449    if (ready > 0)
450      {
451	received = 0;
452
453        for (i = 0; i < num_fd; i++)
454	  {
455	    if (FD_ISSET (fd[i], &rset))
456	      {
457		is_set[i] = 1;
458		received = 1;
459	      }
460	    else
461	      is_set[i] = 0;
462	  }
463
464#ifdef __hpux__
465        for (i = 0; i < num_fd; i++)
466	  {
467	    if (FD_ISSET (fd[i], &eset))
468	      {
469	        struct request_info ei;
470
471	        /* Only query and reset error state if no file descriptor
472	           is ready to be read, otherwise we will be signalling a
473	           died process too early */
474
475	        if (!received)
476		  {
477	            ioctl (fd[i], TIOCREQCHECK, &ei);
478
479	            if (ei.request == TIOCCLOSE)
480		      {
481		        ioctl (fd[i], TIOCREQSET, &ei);
482                        dead_process = i + 1;
483		        return -1;
484		      }
485
486	            ioctl (fd[i], TIOCREQSET, &ei);
487		  }
488	        ready--;
489	      }
490	  }
491#endif
492      }
493  } while (timeout == -1 && ready == 0);
494
495  return ready;
496}
497
498#else
499
500void
501__gnat_kill (int pid ATTRIBUTE_UNUSED,
502	     int sig ATTRIBUTE_UNUSED,
503	     int close ATTRIBUTE_UNUSED)
504{
505}
506
507int
508__gnat_waitpid (int pid ATTRIBUTE_UNUSED, int sig ATTRIBUTE_UNUSED)
509{
510  return 0;
511}
512
513int
514__gnat_pipe (int *fd ATTRIBUTE_UNUSED)
515{
516  return -1;
517}
518
519int
520__gnat_expect_fork (void)
521{
522  return -1;
523}
524
525void
526__gnat_expect_portable_execvp (int *pid ATTRIBUTE_UNUSED,
527			       char *cmd ATTRIBUTE_UNUSED,
528			       char *argv[] ATTRIBUTE_UNUSED)
529{
530  *pid = 0;
531}
532
533int
534__gnat_expect_poll (int *fd ATTRIBUTE_UNUSED,
535                    int num_fd ATTRIBUTE_UNUSED,
536                    int timeout ATTRIBUTE_UNUSED,
537                    int *dead_process ATTRIBUTE_UNUSED,
538                    int *is_set ATTRIBUTE_UNUSED)
539{
540  *dead_process = 0;
541  return -1;
542}
543#endif
544