mirror of https://github.com/sheumann/dmake.git
190 lines
4.3 KiB
C
190 lines
4.3 KiB
C
/* if gsh $PATH parsing ever gets straighted out, remove this */
|
|
#define BACKWARDS
|
|
|
|
#include <sys/wait.h>
|
|
#include <errno.h>
|
|
#include "extern.h"
|
|
#include "sysintf.h"
|
|
|
|
static int _abort_flg = FALSE;
|
|
static void _add_child ANSI((CELLPTR, int));
|
|
static void _finished_child ANSI((int));
|
|
|
|
static int child_status; /* the exit value of the child process */
|
|
|
|
/* These two are from lenviron */
|
|
extern char *build_cmd (char *const *argv);
|
|
extern char *build_path (const char *file);
|
|
|
|
#pragma databank 1
|
|
|
|
static void child_process(char *path, char *comd) {
|
|
_execve(path, comd);
|
|
return;
|
|
}
|
|
#pragma databank 0
|
|
|
|
/*
|
|
* static int execp(const char *file, char *const argv[]);
|
|
*
|
|
* This is like the Gno/ME exec(2) routine in that it waits for the child
|
|
* to exit before returning. The difference is that it will find <file>
|
|
* if it is in the $PATH, and expects an array of strings (vice a single
|
|
* string) as the second argument.
|
|
*
|
|
* This is very much a _non_ standard function ...
|
|
*
|
|
* returns:
|
|
* -1 and errno set if execp call failed (child_status undefined)
|
|
* otherwise return 0, errno=0, and child_status is the return value
|
|
* of the called program <file>
|
|
*/
|
|
|
|
static int execp(const char *file, char *const argv[]) {
|
|
char *comd;
|
|
char *path;
|
|
int result;
|
|
int w_result;
|
|
union wait w_status;
|
|
int terrno;
|
|
|
|
/* errno = 0; (This is set in runargv() just before calling execp()) */
|
|
|
|
/*
|
|
* Are we using a full or partial pathname? If partial, then we have
|
|
* to build it.
|
|
*/
|
|
|
|
if (If_root_path(file)) {
|
|
/* full pathname */
|
|
path = strdup(file);
|
|
if (!path) return -1;
|
|
} else {
|
|
/* partial pathname: is $PATH defined in the environment? */
|
|
path = getenv("PATH");
|
|
if (path) { /* PATH exists; good start ... */
|
|
path = build_path (file);
|
|
if (path == NULL) return -1;
|
|
} else { /* no PATH; use default */
|
|
#ifdef BACKWARDS
|
|
if (setenv("PATH","/usr/bin /bin",1) != 0) return -1;
|
|
#else
|
|
if (setenv("PATH","/bin /usr/bin",1) != 0) return -1;
|
|
#endif
|
|
path = build_path (file);
|
|
result = (path == NULL) ? -1 : 0;
|
|
terrno = errno; /* unsetenv may affect errno */
|
|
unsetenv("PATH");
|
|
errno = terrno;
|
|
if (result!=0) return -1;
|
|
}
|
|
}
|
|
|
|
/* build the command line */
|
|
comd = build_cmd (argv);
|
|
if (comd == NULL) {
|
|
terrno = errno;
|
|
free(path);
|
|
errno = terrno;
|
|
return -1;
|
|
}
|
|
|
|
/* execute it */
|
|
result = fork2(child_process, 1536, 0, "forked child of dmake", 4,
|
|
path, comd);
|
|
|
|
/* the parent has to wait for the child to exit so we can get the status */
|
|
if (result != -1) {
|
|
|
|
/* this method will only work if there are no other children! */
|
|
for (;;) {
|
|
w_result = wait (&w_status);
|
|
if (w_result == -1) {
|
|
result = -1;
|
|
break;
|
|
}
|
|
/*
|
|
* we can ignore WIFSIGNALLED in the following test because we
|
|
* have a signal handler installed
|
|
*/
|
|
if (WIFEXITED(w_status) || WIFSIGNALED(w_status)) {
|
|
child_status = w_status.w_retcode;
|
|
result = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* At this point, "result" has been set under all conditions, and there
|
|
* is no child process left.
|
|
*/
|
|
|
|
/* free the memory */
|
|
terrno = errno;
|
|
free(path);
|
|
free(comd);
|
|
errno = terrno;
|
|
|
|
return result;
|
|
}
|
|
|
|
PUBLIC int
|
|
runargv(CELLPTR target, int ignore, int group, int last, int shell, char *cmd)
|
|
{
|
|
char **argv;
|
|
int pid;
|
|
|
|
argv = Pack_argv( group, shell, cmd );
|
|
_add_child(target, ignore);
|
|
|
|
errno = 0;
|
|
if (execp (*argv, argv) == -1)
|
|
Error("%s: %s", argv[0], strerror(errno));
|
|
|
|
_finished_child(child_status);
|
|
if( last && !Doing_bang ) Update_time_stamp( target );
|
|
|
|
return 0; /* means: all children exited */
|
|
}
|
|
|
|
|
|
PUBLIC void
|
|
Clean_up_processes(void)
|
|
{
|
|
_abort_flg = TRUE;
|
|
_finished_child(-1);
|
|
}
|
|
|
|
|
|
PUBLIC int
|
|
Wait_for_child( int abort_flg, int pid )
|
|
{
|
|
return(1);
|
|
}
|
|
|
|
|
|
static int _valid = -1;
|
|
static CELLPTR _tg;
|
|
static int _ignore;
|
|
|
|
static void
|
|
_add_child( CELLPTR target, int ignore )
|
|
{
|
|
_tg = target;
|
|
_ignore = ignore;
|
|
_valid = 0;
|
|
|
|
Current_target = NIL(CELL);
|
|
}
|
|
|
|
|
|
static void
|
|
_finished_child( int status)
|
|
{
|
|
if( _valid == -1 ) return;
|
|
Unlink_temp_files( _tg );
|
|
_valid = -1;
|
|
Handle_result( status, _ignore, _abort_flg, _tg );
|
|
}
|