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 
86 int
__gnat_waitpid(int pid)87 __gnat_waitpid (int pid)
88 {
89   HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
90   DWORD exitcode = 1;
91   DWORD res;
92 
93   if (h != NULL)
94     {
95       res = WaitForSingleObject (h, INFINITE);
96       GetExitCodeProcess (h, &exitcode);
97       CloseHandle (h);
98     }
99 
100   __gnat_win32_remove_handle (NULL, pid);
101   return (int) exitcode;
102 }
103 
104 int
__gnat_expect_fork(void)105 __gnat_expect_fork (void)
106 {
107   return 0;
108 }
109 
110 void
__gnat_expect_portable_execvp(int * pid,char * cmd,char * argv[])111 __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[])
112 {
113   *pid = __gnat_portable_no_block_spawn (argv);
114 }
115 
116 int
__gnat_pipe(int * fd)117 __gnat_pipe (int *fd)
118 {
119   HANDLE read, write;
120 
121   CreatePipe (&read, &write, NULL, 0);
122   fd[0]=_open_osfhandle ((intptr_t)read, 0);
123   fd[1]=_open_osfhandle ((intptr_t)write, 0);
124   return 0;  /* always success */
125 }
126 
127 int
__gnat_expect_poll(int * fd,int num_fd,int timeout,int * dead_process,int * is_set)128 __gnat_expect_poll (int *fd,
129                     int num_fd,
130                     int timeout,
131                     int *dead_process,
132                     int *is_set)
133 {
134 #define MAX_DELAY 100
135 
136   int i, delay, infinite = 0;
137   DWORD avail;
138   HANDLE handles[num_fd];
139 
140   *dead_process = 0;
141 
142   for (i = 0; i < num_fd; i++)
143     is_set[i] = 0;
144 
145   for (i = 0; i < num_fd; i++)
146     handles[i] = (HANDLE) _get_osfhandle (fd [i]);
147 
148   /* Start with small delays, and then increase them, to avoid polling too
149      much when waiting a long time */
150   delay = 5;
151 
152   if (timeout < 0)
153     infinite = 1;
154 
155   while (1)
156     {
157       for (i = 0; i < num_fd; i++)
158         {
159           if (!PeekNamedPipe (handles [i], NULL, 0, NULL, &avail, NULL))
160             {
161               *dead_process = i + 1;
162               return -1;
163             }
164           if (avail > 0)
165             {
166               is_set[i] = 1;
167               return 1;
168             }
169         }
170 
171       if (!infinite && timeout <= 0)
172         return 0;
173 
174       Sleep (delay);
175       timeout -= delay;
176 
177       if (delay < MAX_DELAY)
178         delay += 10;
179     }
180 }
181 
182 #elif defined (VMS)
183 #include <unistd.h>
184 #include <stdio.h>
185 #include <unixio.h>
186 #include <stdlib.h>
187 #include <string.h>
188 #include <vms/descrip.h>
189 #include <stdio.h>
190 #include <vms/stsdef.h>
191 #include <vms/iodef.h>
192 #include <signal.h>
193 
194 int
__gnat_waitpid(int pid)195 __gnat_waitpid (int pid)
196 {
197   int status = 0;
198 
199   waitpid (pid, &status, 0);
200   status = WEXITSTATUS (status);
201 
202   return status;
203 }
204 
205 int
__gnat_pipe(int * fd)206 __gnat_pipe (int *fd)
207 {
208   return pipe (fd);
209 }
210 
211 int
__gnat_expect_fork(void)212 __gnat_expect_fork (void)
213 {
214   return -1;
215 }
216 
217 void
__gnat_expect_portable_execvp(int * pid,char * cmd,char * argv[])218 __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[])
219 {
220   *pid = (int) getpid ();
221   /* Since cmd is fully qualified, it is incorrect to call execvp */
222   execv (cmd, argv);
223   _exit (1);
224 }
225 
226 int
__gnat_expect_poll(int * fd,int num_fd,int timeout,int * dead_process,int * is_set)227 __gnat_expect_poll (int *fd,
228                     int num_fd,
229                     int timeout,
230                     int *dead_process,
231                     int *is_set)
232 {
233   int i, num, ready = 0;
234   unsigned int status;
235   int mbxchans [num_fd];
236   struct dsc$descriptor_s mbxname;
237   struct io_status_block {
238     short int condition;
239     short int count;
240     int dev;
241   } iosb;
242   char buf [256];
243 
244   *dead_process = 0;
245 
246   for (i = 0; i < num_fd; i++)
247     is_set[i] = 0;
248 
249   for (i = 0; i < num_fd; i++)
250     {
251 
252       /* Get name of the mailbox used in the pipe */
253       getname (fd [i], buf);
254 
255       /* Assign a channel to the mailbox */
256       if (strlen (buf) > 0)
257 	{
258 	  mbxname.dsc$w_length = strlen (buf);
259 	  mbxname.dsc$b_dtype = DSC$K_DTYPE_T;
260 	  mbxname.dsc$b_class = DSC$K_CLASS_S;
261 	  mbxname.dsc$a_pointer = buf;
262 
263 	  status = SYS$ASSIGN (&mbxname, &mbxchans[i], 0, 0, 0);
264 
265 	  if ((status & 1) != 1)
266 	    {
267               ready = -1;
268               dead_process = i + 1;
269               return ready;
270 	    }
271 	}
272     }
273 
274   num = timeout / 100;
275 
276   while (1)
277     {
278       for (i = 0; i < num_fd; i++)
279 	{
280 	  if (mbxchans[i] > 0)
281 	    {
282 
283 	      /* Peek in the mailbox to see if there's data */
284 	      status = SYS$QIOW
285 		(0, mbxchans[i], IO$_SENSEMODE|IO$M_READERCHECK,
286 		 &iosb, 0, 0, 0, 0, 0, 0, 0, 0);
287 
288 	      if ((status & 1) != 1)
289 		{
290 		  ready = -1;
291 		  goto deassign;
292 		}
293 
294 	      if (iosb.count > 0)
295 		{
296 		  is_set[i] = 1;
297 		  ready = 1;
298 		  goto deassign;
299 		}
300 	    }
301 	}
302 
303       if (timeout > 0 && num == 0)
304 	{
305 	  ready = 0;
306 	  goto deassign;
307 	}
308 
309       usleep (100000);
310       num--;
311     }
312 
313  deassign:
314 
315   /* Deassign channels assigned above */
316   for (i = 0; i < num_fd; i++)
317     {
318       if (mbxchans[i] > 0)
319 	status = SYS$DASSGN (mbxchans[i]);
320     }
321 
322   return ready;
323 }
324 #elif defined (__unix__)
325 
326 #ifdef __hpux__
327 #include <sys/ptyio.h>
328 #endif
329 
330 #include <sys/time.h>
331 
332 #ifndef NO_FD_SET
333 #define SELECT_MASK fd_set
334 #else /* !NO_FD_SET */
335 #ifndef _AIX
336 typedef long fd_mask;
337 #endif /* _AIX */
338 #ifdef _IBMR2
339 #define SELECT_MASK void
340 #else /* !_IBMR2 */
341 #define SELECT_MASK int
342 #endif /* !_IBMR2 */
343 #endif /* !NO_FD_SET */
344 
345 int
__gnat_waitpid(int pid)346 __gnat_waitpid (int pid)
347 {
348   int status = 0;
349 
350   waitpid (pid, &status, 0);
351   status = WEXITSTATUS (status);
352 
353   return status;
354 }
355 
356 int
__gnat_pipe(int * fd)357 __gnat_pipe (int *fd)
358 {
359   return pipe (fd);
360 }
361 
362 int
__gnat_expect_fork(void)363 __gnat_expect_fork (void)
364 {
365   return fork ();
366 }
367 
368 void
__gnat_expect_portable_execvp(int * pid,char * cmd,char * argv[])369 __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[])
370 {
371   *pid = (int) getpid ();
372   /* Since cmd is fully qualified, it is incorrect to call execvp */
373   execv (cmd, argv);
374   _exit (1);
375 }
376 
377 int
__gnat_expect_poll(int * fd,int num_fd,int timeout,int * dead_process,int * is_set)378 __gnat_expect_poll (int *fd,
379                     int num_fd,
380                     int timeout,
381                     int *dead_process,
382                     int *is_set)
383 {
384   struct timeval tv;
385   SELECT_MASK rset;
386   SELECT_MASK eset;
387 
388   int max_fd = 0;
389   int ready;
390   int i;
391   int received;
392 
393   *dead_process = 0;
394 
395   tv.tv_sec  = timeout / 1000;
396   tv.tv_usec = (timeout % 1000) * 1000;
397 
398   do {
399     FD_ZERO (&rset);
400     FD_ZERO (&eset);
401 
402     for (i = 0; i < num_fd; i++)
403       {
404         FD_SET (fd[i], &rset);
405         FD_SET (fd[i], &eset);
406 
407         if (fd[i] > max_fd)
408 	  max_fd = fd[i];
409       }
410 
411     ready =
412       select (max_fd + 1, &rset, NULL, &eset, timeout == -1 ? NULL : &tv);
413 
414     if (ready > 0)
415       {
416 	received = 0;
417 
418         for (i = 0; i < num_fd; i++)
419 	  {
420 	    if (FD_ISSET (fd[i], &rset))
421 	      {
422 		is_set[i] = 1;
423 		received = 1;
424 	      }
425 	    else
426 	      is_set[i] = 0;
427 	  }
428 
429 #ifdef __hpux__
430         for (i = 0; i < num_fd; i++)
431 	  {
432 	    if (FD_ISSET (fd[i], &eset))
433 	      {
434 	        struct request_info ei;
435 
436 	        /* Only query and reset error state if no file descriptor
437 	           is ready to be read, otherwise we will be signalling a
438 	           died process too early */
439 
440 	        if (!received)
441 		  {
442 	            ioctl (fd[i], TIOCREQCHECK, &ei);
443 
444 	            if (ei.request == TIOCCLOSE)
445 		      {
446 		        ioctl (fd[i], TIOCREQSET, &ei);
447                         dead_process = i + 1;
448 		        return -1;
449 		      }
450 
451 	            ioctl (fd[i], TIOCREQSET, &ei);
452 		  }
453 	        ready--;
454 	      }
455 	  }
456 #endif
457       }
458   } while (timeout == -1 && ready == 0);
459 
460   return ready;
461 }
462 
463 #else
464 
465 int
__gnat_waitpid(int pid ATTRIBUTE_UNUSED,int sig ATTRIBUTE_UNUSED)466 __gnat_waitpid (int pid ATTRIBUTE_UNUSED, int sig ATTRIBUTE_UNUSED)
467 {
468   return 0;
469 }
470 
471 int
__gnat_pipe(int * fd ATTRIBUTE_UNUSED)472 __gnat_pipe (int *fd ATTRIBUTE_UNUSED)
473 {
474   return -1;
475 }
476 
477 int
__gnat_expect_fork(void)478 __gnat_expect_fork (void)
479 {
480   return -1;
481 }
482 
483 void
__gnat_expect_portable_execvp(int * pid ATTRIBUTE_UNUSED,char * cmd ATTRIBUTE_UNUSED,char * argv[]ATTRIBUTE_UNUSED)484 __gnat_expect_portable_execvp (int *pid ATTRIBUTE_UNUSED,
485 			       char *cmd ATTRIBUTE_UNUSED,
486 			       char *argv[] ATTRIBUTE_UNUSED)
487 {
488   *pid = 0;
489 }
490 
491 int
__gnat_expect_poll(int * fd ATTRIBUTE_UNUSED,int num_fd ATTRIBUTE_UNUSED,int timeout ATTRIBUTE_UNUSED,int * dead_process ATTRIBUTE_UNUSED,int * is_set ATTRIBUTE_UNUSED)492 __gnat_expect_poll (int *fd ATTRIBUTE_UNUSED,
493                     int num_fd ATTRIBUTE_UNUSED,
494                     int timeout ATTRIBUTE_UNUSED,
495                     int *dead_process ATTRIBUTE_UNUSED,
496                     int *is_set ATTRIBUTE_UNUSED)
497 {
498   *dead_process = 0;
499   return -1;
500 }
501 #endif
502