/* RCS $Id: runargv.c,v 1.5 2002-10-11 13:42:48 waratah Exp $ -- -- SYNOPSIS -- Invoke a sub process. -- -- DESCRIPTION -- Use the standard methods of executing a sub process. -- -- AUTHOR -- Dennis Vadura, dvadura@dmake.wticorp.com -- -- WWW -- http://dmake.wticorp.com/ -- -- COPYRIGHT -- Copyright (c) 1996,1997 by WTI Corp. All rights reserved. -- -- This program is NOT free software; you can redistribute it and/or -- modify it under the terms of the Software License Agreement Provided -- in the file /readme/license.txt. -- -- LOG -- Use cvs log to obtain detailed change logs. */ #include #include #include "extern.h" /* temporarily comment out spwan code as it does not actually work yet */ #undef HAVE_SPAWN_H #if HAVE_SPAWN_H # include #endif #include "sysintf.h" #if HAVE_ERRNO_H # include #else extern int errno; #endif typedef struct prp { char *prp_cmd; int prp_group; int prp_ignore; int prp_last; int prp_shell; struct prp *prp_next; } RCP, *RCPPTR; typedef struct pr { int pr_valid; int pr_pid; CELLPTR pr_target; int pr_ignore; int pr_last; RCPPTR pr_recipe; RCPPTR pr_recipe_end; char *pr_dir; } PR; static PR *_procs = NIL(PR); static int _proc_cnt = 0; static int _abort_flg= FALSE; static int _use_i = -1; static void _add_child ANSI((int, CELLPTR, int, int)); static void _attach_cmd ANSI((char *, int, int, CELLPTR, int, int)); static void _finished_child ANSI((int, int)); static int _running ANSI((CELLPTR)); #if ! HAVE_STRERROR static char * private_strerror (errnum) int errnum; { #ifndef __APPLE__ #ifdef arm32 extern const char * const sys_errlist[]; #else #if defined(linux) || defined(__FreeBSD__) extern const char * const sys_errlist[]; #else extern char *sys_errlist[]; #endif #endif #endif extern int sys_nerr; if (errnum > 0 && errnum <= sys_nerr) return sys_errlist[errnum]; return "Unknown system error"; } #define strerror private_strerror #endif /* HAVE_STRERROR */ PUBLIC int runargv(target, ignore, group, last, shell, cmd) CELLPTR target; int ignore; int group; int last; int shell; char *cmd; { int pid; char **argv; if( _running(target) /*&& Max_proc != 1*/ ) { /* The command will be executed when the previous recipe * line completes. */ _attach_cmd( cmd, group, ignore, target, last, shell ); return(1); } /* Any Fatal call can potentially loop by recursion because we * are called from the Quit routine that Fatal indirectly calls * since Fatal should not happen I have left this bug in here */ while( _proc_cnt == Max_proc ) { if( Wait_for_child(FALSE, -1) == -1 ) { if( ! in_quit() || errno != ECHILD ) Fatal( "Lost a child %d: %s", errno, strerror( errno ) ); else {/* we are quitting and the _proc_cnt was stuffed up by ^C */ fprintf(stderr,"_proc_cnt %d, Max_proc %d\n",_proc_cnt,Max_proc); _proc_cnt = 0; } } } argv = Pack_argv( group, shell, cmd ); #if HAVE_SPAWN_H if (posix_spawn (&pid, argv[0], NULL, NULL, argv, (char *)NULL)) { /* posix_spawn failed */ Error("%s: %s", argv[0], strerror(errno)); Handle_result(-1, ignore, _abort_flg, target); return(-1); } else { _add_child(pid, target, ignore, last); } #else /* HAVE_SPAWN_H */ switch( pid=fork() ){ case -1: /* fork failed */ Error("%s: %s", argv[0], strerror( errno )); Handle_result(-1, ignore, _abort_flg, target); return(-1); case 0: /* child */ execvp(argv[0], argv); Continue = TRUE; /* survive error message */ Error("%s: %s", argv[0], strerror( errno )); kill(getpid(), SIGTERM); /*NOTREACHED*/ default: /* parent */ _add_child(pid, target, ignore, last); } #endif /* HAVE_SPAWN_H */ return(1); } PUBLIC int Wait_for_child( abort_flg, pid ) int abort_flg; int pid; { int wid; int status; int waitchild; waitchild = (pid == -1)? FALSE : Wait_for_completion; do { wid = wait(&status); if( wid == -1 ) return(-1); _abort_flg = abort_flg; _finished_child(wid, status); _abort_flg = FALSE; } while( waitchild && pid != wid ); return(0); } PUBLIC void Clean_up_processes() { register int i; if( _procs != NIL(PR) ) { for( i=0; ipr_valid = 1; pp->pr_pid = pid; pp->pr_target = target; pp->pr_ignore = ignore; pp->pr_last = last; pp->pr_dir = DmStrDup(Get_current_dir()); Current_target = NIL(CELL); _proc_cnt++; if( Wait_for_completion ) Wait_for_child( FALSE, pid ); } static void _finished_child(pid, status) int pid; int status; { register int i; char *dir; for( i=0; ice_attr & A_ERROR ) { Unlink_temp_files( _procs[i].pr_target ); _procs[i].pr_last = TRUE; goto ABORT_REMAINDER_OF_RECIPE; } _procs[i].pr_recipe = rp->prp_next; _use_i = i; runargv( _procs[i].pr_target, rp->prp_ignore, rp->prp_group, rp->prp_last, rp->prp_shell, rp->prp_cmd ); _use_i = -1; FREE( rp->prp_cmd ); FREE( rp ); if( _proc_cnt == Max_proc ) Wait_for_child( FALSE, -1 ); } else { Unlink_temp_files( _procs[i].pr_target ); Handle_result(status,_procs[i].pr_ignore,_abort_flg,_procs[i].pr_target); ABORT_REMAINDER_OF_RECIPE: if( _procs[i].pr_last ) { FREE(_procs[i].pr_dir ); if( !Doing_bang ) Update_time_stamp( _procs[i].pr_target ); } } Set_dir(dir); FREE(dir); } static int _running( cp ) CELLPTR cp; { register int i; if( !_procs ) return(FALSE); for( i=0; iprp_cmd = DmStrDup(cmd); rp->prp_group = group; rp->prp_ignore= ignore; rp->prp_last = last; rp->prp_shell = shell; if( _procs[i].pr_recipe == NIL(RCP) ) _procs[i].pr_recipe = _procs[i].pr_recipe_end = rp; else { _procs[i].pr_recipe_end->prp_next = rp; _procs[i].pr_recipe_end = rp; } }