2 * The Regina Rexx Interpreter
3 * Copyright (C) 2005 Florian Grosse-Coosmann
5 * System interfacing functions for unix and equivalent systems
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #if defined(HAVE_STRING_H)
33 # ifdef _POSIX_SOURCE /* emulation system? */
39 #if defined(HAVE_ASSERT_H)
43 #if defined(HAVE_UNISTD_H)
47 #if defined(HAVE_SYS_STAT_H)
48 # include <sys/stat.h>
51 #if defined(HAVE_SYS_WAIT_H)
52 # include <sys/wait.h>
55 #if defined(HAVE_FCNTL_H)
59 #if defined(HAVE_SYS_FCNTL_H)
60 # include <sys/fcntl.h>
63 #if defined(HAVE_PROCESS_H)
67 #if defined(HAVE_SHARE_H)
71 #if defined(HAVE_TIME_H)
75 #if defined(HAVE_ERRNO_H)
79 #if defined(HAVE_SIGNAL_H)
83 #if defined(HAVE_ASSERT_H)
87 #if defined(HAVE_SYS_UTSNAME_H)
88 # include <sys/utsname.h>
91 #if defined(HAVE_POLL) && (defined(HAVE_POLL_H) || defined(HAVE_SYS_POLL_H))
92 # if defined(HAVE_POLL_H)
95 # include <sys/poll.h>
97 /* implement a simple(!) wait mechanism for a max. of 3 handles */
100 struct pollfd _p
[3] ;
103 #elif defined(HAVE_SYS_SELECT_H) || defined(SELECT_IN_TIME_H) || defined(HAVE_SYS_SOCKET_H)
104 # if defined(HAVE_SYS_SELECT_H)
105 # include <sys/select.h>
106 # elif defined(HAVE_SYS_SOCKET_H)
107 # include <sys/socket.h>
111 /* implement a simple(!) wait mechanism for a max. of 3 handles */
120 #if defined(HAVE_SYS_RESOURCE_H)
121 # include <sys/resource.h>
124 static int Unx_setenv( const char *name
, const char *value
)
126 #if defined(HAVE_SETENV)
127 setenv( name
, value
, 1 );
134 cmd
= malloc( strlen(name
) + strlen(value
) + 2);
135 sprintf( cmd
, "%s=%s", name
, value
);
141 /* MaxFiles returns the maximum number of files which can be addressed by a
142 * single process. We guess the result if we can't determine it.
144 #if defined(__QNX__) && !defined(__QNXNTO__)
145 #include <sys/osinfo.h>
146 static int MaxFiles(void)
148 * returns the maximum number of files which can be addressed by a single
149 * process. We guess the result if we can't determine it.
152 struct _osinfo osdata
;
153 if ( qnx_osinfo( 0, &osdata
) != -1 )
155 return osdata
.num_fds
[1];
163 static int MaxFiles(void)
165 int rlmax
= INT_MAX
; /* resource's limit */
166 int scmax
= INT_MAX
; /* sysconf limit */
169 scmax
= sysconf(_SC_OPEN_MAX
); /* systemwide maximum */
172 #if defined(HAVE_SYS_RESOURCE_H) && defined(RLIMIT_OFILE)
173 /* user's limit might be decreased by himself: */
177 if (getrlimit(RLIMIT_OFILE
,&rl
) == 0)
178 if ((unsigned) rl
.rlim_cur
< (unsigned) INT_MAX
)
179 rlmax
= (int) rl
.rlim_cur
;
183 if (rlmax
< scmax
) /* map rlmax to scmax */
185 if (scmax
!= INT_MAX
) /* either getrlimit or sysconf valid? */
188 #ifdef POSIX_OPEN_MAX
189 /* maybe, we have a hardcoded limit */
190 if (POSIX_OPEN_MAX
!= INT_MAX
) /* shall work in most cases */
191 return(POSIX_OPEN_MAX
);
194 return(256); /* just a guess */
199 * fork_exec spawns a new process with the given commandline.
200 * it returns -1 on error (errno set), 0 on process start error (rcode set),
201 * a process descriptor otherwise.
202 * Basically this is a child process and we run in the child's environment
203 * after the first few lines. The setup hasn't been done and the command needs
205 * Redirection takes place if one of the handles env->input.hdls[0],
206 * env->output.hdls[1] or env->error.hdls[1] is defined. Other handles (except
207 * standard handles) are closed. env->subtype must be a SUBENVIR_... constant.
208 * cmdline is the whole command line.
209 * Never use TSD after the fork() since this is not only a different thread,
210 * it's a different process!
212 int Unx_fork_exec(tsd_t
*TSD
, environment
*env
, const char *cmdline
, int *rcode
)
214 static const char *interpreter
[] = { "regina", /* preferable even if not */
218 int i
, rc
, max_hdls
= MaxFiles() ;
219 int broken_address_command
= get_options_flag( TSD
->currlevel
, EXT_BROKEN_ADDRESS_COMMAND
);
222 if ( ( rc
= fork() ) != 0 )
225 /* Now we are the child */
227 #define STD_REDIR(hdl,dest) if ((hdl != -1) && (hdl != dest)) dup2(hdl, dest)
228 #define SET_MAXHDL(hdl) if (hdl > max_hdls) max_hdls = hdl
229 #define SET_MAXHDLS(ep) SET_MAXHDL(ep.hdls[0]); SET_MAXHDL(ep.hdls[1])
231 /* Force the standard redirections: */
232 STD_REDIR(env
->input
.hdls
[0], 0);
233 STD_REDIR(env
->output
.hdls
[1], 1);
234 if (env
->error
.SameAsOutput
)
240 STD_REDIR(env
->error
.hdls
[1], 2);
243 /* any handle greater than the default ? */
244 SET_MAXHDLS(env
->input
);
245 SET_MAXHDLS(env
->output
);
246 if (!env
->error
.SameAsOutput
)
247 SET_MAXHDLS(env
->error
);
249 for (i
=3; i
<= max_hdls
; i
++)
253 * If the BROKEN_ADDRESS_COMMAND OPTION is in place,
254 * and our environment is COMMAND, change it to SYSTEM
256 if ( env
->subtype
== SUBENVIR_PATH
/* was SUBENVIR_COMMAND */
257 && broken_address_command
)
258 subtype
= SUBENVIR_SYSTEM
;
260 subtype
= env
->subtype
;
265 args
= makeargs(cmdline
, '\\');
269 case SUBENVIR_COMMAND
:
270 args
= makeargs(cmdline
, '\\');
274 case SUBENVIR_SYSTEM
:
275 #if defined(HAVE_WIN32GUI)
276 rc
= mysystem( cmdline
) ;
278 rc
= system( cmdline
) ;
281 exit (rc
); /* This is a separate process, exit() is allowed */
283 if ( WIFEXITED( rc
) )
286 _exit( (int) WEXITSTATUS(rc
) ); /* This is a separate process, exit() is allowed */
288 else if ( WIFSIGNALED( rc
) )
289 raise( WTERMSIG( rc
) ); /* This is a separate process, raise() is allowed */
291 raise( WSTOPSIG( rc
) ); /* This is a separate process, raise() is allowed */
302 len
= 7; /* max("rexx", "regina") */
307 len
= 7; /* max("rexx", "regina") */
309 len
+= strlen(cmdline
) + 2; /* Blank + term ASCII0 */
311 if ((new_cmdline
= (char *)malloc(len
)) == NULL
)
312 raise( SIGKILL
); /* This is a separate process, raise() is allowed */
314 if (argv0
!= NULL
) /* always the best choice */
316 strcpy(new_cmdline
, argv0
);
317 strcat(new_cmdline
, " ");
318 strcat(new_cmdline
, cmdline
);
319 args
= makeargs(new_cmdline
, '\\');
324 /* load an interpreter by name from the path */
325 for (i
= 0; i
< (int) (sizeof(interpreter
) / sizeof(interpreter
[0]));i
++)
327 strcpy(new_cmdline
, interpreter
[i
]);
328 strcat(new_cmdline
, " ");
329 strcat(new_cmdline
, cmdline
);
330 args
= makeargs(new_cmdline
, '\\');
335 /* last chance, worst choice, use the re-entering code: */
336 strcpy(new_cmdline
, "\"\" ");
337 strcat(new_cmdline
, cmdline
);
338 args
= makeargs(new_cmdline
, '\\');
340 for (i
= 0, run
= args
; *run
; run
++)
343 _exit(__regina_reexecute_main(i
, args
));
346 default: /* illegal subtype */
347 raise( SIGKILL
) ; /* This is a separate process, raise() is allowed */
351 raise( SIGKILL
); /* This is a separate process, raise() is allowed */
355 return -1; /* keep the compiler happy */
358 /* wait waits for a process started by fork_exec.
359 * In general, this is called after the complete IO to the called process but
360 * it isn't guaranteed. Never call if you don't expect a sudden death of the
362 * Returns the exit status of the subprocess under normal circumstances. If
363 * the subprocess has died by a signal, the return value is -(100+signalnumber)
365 static int Unx_wait(int process
)
367 int rc
, retval
, status
;
371 rc
= wait( &status
) ;
379 retval
= status
& 0xff ;
385 * According to Paul F. Kunz, NeXTSTEP 3.1 Prerelease doesn't have
386 * the waitpid() function, so wait() must be used instead. The
387 * following klugde will remain until NeXTSTEP gets waitpid().
390 # else /* ndef NEXT */
392 rc
= wait( &status
) ;
393 # else /* ndef DOS */
394 rc
= waitpid( process
, &status
, 0 ) ;
395 # endif /* def DOS */
396 # endif /* def NEXT */
405 if (WIFEXITED(status
))
407 retval
= (int) WEXITSTATUS(status
);
411 else if (WIFSIGNALED(status
))
413 retval
= -WTERMSIG(status
);
416 else if ( retval
== 0 )
421 retval
= -WSTOPSIG(status
);
424 else if ( retval
== 0 )
431 /* open_subprocess_connection acts like the unix-known function pipe and sets
432 * ep->RedirectedFile if necessary. Just in the latter case ep->data
433 * is set to the filename.
435 static int Unx_open_subprocess_connection(const tsd_t
*TSD
, environpart
*ep
)
437 return(pipe(ep
->hdls
));
440 /* sets the given handle to the non-blocking mode. The value may change.
441 * async_info CAN be used to add the handle to the internal list of watched
444 static void Unx_unblock_handle( int *handle
, void *async_info
)
451 fl
= fcntl( *handle
, F_GETFL
) ;
453 if ( fl
== -1 ) /* We can either abort or try to continue, try to */
454 return ; /* continue for now. */
456 fcntl( *handle
, F_SETFL
, fl
| O_NONBLOCK
) ;
459 /* restart_file sets the file pointer of the given handle to the beginning.
461 static void Unx_restart_file(int hdl
)
463 lseek(hdl
, 0l, SEEK_SET
);
466 /* close acts like close() but closes a handle returned by
467 * open_subprocess_connection.
468 * async_info MAY be used to delete the handle from the internal list of
471 static int Unx_close(int handle
, void *async_info
)
473 return(close(handle
));
477 * close_special acts like close() but closes any OS specific handle.
478 * The close happens if the handle is not -1. A specific operation may be
479 * associated with this. Have a look for occurances of "hdls[2]".
481 static void Unx_close_special( int handle
)
483 assert( handle
== -1 );
486 /* read acts like read() but returns either an error (return code
487 * == -errno) or the number of bytes read. EINTR and friends leads to a
489 * use_blocked_io is a flag. If set, the handle is set to blocked IO and
490 * we shall use blocked IO here.
492 static int Unx_read(int hdl
, void *buf
, unsigned size
, void *async_info
)
497 done
= read( hdl
, buf
, size
) ;
498 } while ((done
== -1) && (errno
== EINTR
));
503 if (done
== 0) /* no error set? */
504 done
= EPIPE
; /* good assumption */
505 #if defined(EWOULDBLOCK) && defined(EAGAIN) && (EAGAIN != EWOULDBLOCK)
506 /* BSD knows this value with the same meaning as EAGAIN */
507 if (done
== EWOULDBLOCK
)
510 return( -done
) ; /* error */
516 /* write acts like write() but returns either an error (return code
517 * == -errno) or the number of bytes written. EINTR and friends leads to a
519 * use_blocked_io is a flag. If set, the handle is set to blocked IO and
520 * we shall use blocked IO here.
521 * The file must be flushed if buf or size are 0.
523 static int Unx_write(int hdl
, const void *buf
, unsigned size
, void *async_info
)
527 if ((buf
== NULL
) || (size
== 0)) /* nothing to to for flushing buffers */
531 done
= write( hdl
, buf
, size
) ;
532 } while ((done
== -1) && (errno
== EINTR
));
537 if (done
== 0) /* no error set? */
538 done
= ENOSPC
; /* good assumption */
539 #if defined(EWOULDBLOCK) && defined(EAGAIN) && (EAGAIN != EWOULDBLOCK)
540 /* BSD knows this value with the same meaning as EAGAIN */
541 if (done
== EWOULDBLOCK
)
544 return( -done
) ; /* error */
550 /* create_async_info return an opaque structure to allow the process wait for
551 * asyncronous IO. There are three IO slots (in, out, error) which can be
552 * filled by add_waiter. The structure can be cleaned by reset_async_info.
553 * The structure must be destroyed by delete_async_info.
555 static void *Unx_create_async_info(const tsd_t
*TSD
)
557 AsyncInfo
*ai
= (AsyncInfo
*)MallocTSD(sizeof(AsyncInfo
));
562 /* delete_async_info deletes the structure created by create_async_info and
563 * all of its components.
565 static void Unx_delete_async_info(void *async_info
)
567 AsyncInfo
*ai
= (AsyncInfo
*)async_info
;
571 Free_TSD(ai
->TSD
, ai
);
574 #if defined(POLLIN) && defined(HAVE_POLL) /* we have poll() */
576 /* reset_async_info clear async_info in such a way that fresh add_waiter()
577 * calls can be performed.
579 static void Unx_reset_async_info(void *async_info
)
581 AsyncInfo
*ai
= (AsyncInfo
*)async_info
;
586 /* add_async_waiter adds a further handle to the asyncronous IO structure.
587 * add_as_read_handle must be != 0 if the next operation shall be a
588 * read, else it must be 0 for write.
589 * Call reset_async_info before a wait-cycle to different handles and use
590 * wait_async_info to wait for at least one IO-able handle.
592 static void Unx_add_async_waiter(void *async_info
, int handle
, int add_as_read_handle
)
594 AsyncInfo
*ai
= (AsyncInfo
*)async_info
;
596 assert(ai
->_p_cnt
< 3);
597 ai
->_p
[ai
->_p_cnt
].fd
= handle
;
598 ai
->_p
[ai
->_p_cnt
++].events
= (add_as_read_handle
) ? POLLIN
: POLLOUT
;
601 /* wait_async_info waits for some handles to become ready. This function
602 * returns if at least one handle becomes ready.
603 * A handle can be added with add_async_waiter to the bundle of handles to
605 * No special handling is implemented if an asyncronous interrupt occurs.
606 * Thus, there is no guarantee to have handle which works.
608 static void Unx_wait_async_info(void *async_info
)
610 AsyncInfo
*ai
= (AsyncInfo
*)async_info
;
613 poll(ai
->_p
, ai
->_p_cnt
, -1);
616 #else /* end of POLLIN, must be select */
618 /* reset_async_info clear async_info in such a way that fresh add_waiter()
619 * calls can be performed.
621 static void Unx_reset_async_info(void *async_info
)
623 AsyncInfo
*ai
= async_info
;
625 FD_ZERO( &ai
->_p_in
);
626 FD_ZERO( &ai
->_p_out
);
630 /* add_async_waiter adds a further handle to the asyncronous IO structure.
631 * add_as_read_handle must be != 0 if the next operation shall be a
632 * read, else it must be 0 for write.
633 * Call reset_async_info before a wait-cycle to different handles and use
634 * wait_async_info to wait for at least one IO-able handle.
636 static void Unx_add_async_waiter(void *async_info
, int handle
, int add_as_read_handle
)
638 AsyncInfo
*ai
= async_info
;
640 FD_SET(handle
,(add_as_read_handle
) ? &ai
->_p_in
: &ai
->_p_out
) ;
641 if (handle
> ai
->_p_max
)
642 ai
->_p_max
= handle
;
645 /* wait_async_info waits for some handles to become ready. This function
646 * returns if at least one handle becomes ready.
647 * A handle can be added with add_async_waiter to the bundle of handles to
649 * No special handling is implemented if an asyncronous interrupt occurs.
650 * Thus, there is no guarantee to have handle which works.
652 static void Unx_wait_async_info(void *async_info
)
654 AsyncInfo
*ai
= async_info
;
657 select( ai
->_p_max
+1, &ai
->_p_in
, &ai
->_p_out
, NULL
, NULL
);
660 #endif /* POLLIN or select */
663 static int Unx_uname(struct regina_utsname
*name
)
665 struct utsname osdata
;
668 * Don't know whether utsname uses pointer or char[].
671 if ( uname( &osdata
) < 0 )
673 memset( name
, 0, sizeof(struct regina_utsname
) );
677 strcpy( name
->sysname
, osdata
.sysname
);
678 strcpy( name
->nodename
, osdata
.nodename
);
679 strcpy( name
->release
, osdata
.release
);
680 strcpy( name
->version
, osdata
.version
);
681 strcpy( name
->machine
, osdata
.machine
);
686 static void Unx_init(void)
690 OS_Dep_funcs __regina_OS_Unx
=
693 Unx_setenv
, /* setenv */
694 Unx_fork_exec
, /* fork_exec */
696 Unx_open_subprocess_connection
, /* open_subprocess_connection */
697 Unx_unblock_handle
, /* unblock_handle */
698 Unx_restart_file
, /* restart_file */
699 Unx_close
, /* close */
700 Unx_close_special
, /* close_special */
702 Unx_write
, /* write */
703 Unx_create_async_info
, /* create_async_info */
704 Unx_delete_async_info
, /* delete_async_info */
705 Unx_reset_async_info
, /* reset_async_info */
706 Unx_add_async_waiter
, /* add_async_waiter */
707 Unx_wait_async_info
, /* wait_async_info */
708 Unx_uname
/* uname */