_A PORTABLE LIBRARY FOR EXECUTING CHILD PROCESSES_ by Matt Weisfeld [LISTING ONE] #include #ifdef DOS #include #include #endif #include "exec.h" int _execv(char **argv) { int status, child_status; /* fork off the child process */ /* vfork returns values on two different occasions : 1) It returns a 0 the first time it is called, before the exec functions is called. 2) After the exec call is made, control is passed back to the parent at the point of the vfork. */ #ifdef DOS if ((child_status = spawnv(P_WAIT,argv[0],argv)) == -1) { return (BADEXEC); } #else if ((status = vfork()) != 0) { /* after the exec, control is returned here */ if (status < 0) { printf ("Parent: child failed\n"); return (BADFORK); } else { printf ("Parent - Waiting for child\n"); if ((status=wait(&child_status)) == -1) { printf ("Parent: wait failed\n"); return (BADWAIT); } } } else { /* if vfork returns a 0 */ /* execute command after the initial vfork */ printf ("Parent - Starting Child\n"); if ((status=execv(argv[0], argv)) == -1) { printf ("Parent: execv on child failed\n"); return (BADEXEC); } } #endif #ifdef UNIX child_status = child_status >> 8; #endif return (child_status); } int _execvp(char **argv) { /* fork off the child process */ /* vfork returns values on two different occasions : 1) It returns a 0 the first time it is called, before the exec functions is called. 2) After the exec call is made, control is passed back to the parent at the point of the vfork. */ int status, child_status; int pathlen,comlen; char *path; char *command; /* This code has to be here, if it is within the vfork domain, then any error return code will be interpreted as an error from the child. */ #ifdef VMS if ( (path = getenv("CHILD$PATH")) == NULL) {; printf ("Error: CHILD$PATH not defined\n"); return(BADPATH); } pathlen = strlen (path); comlen = strlen (argv[0]); if ( (command = malloc(pathlen+comlen+1)) == NULL) { printf ("Error: malloc failed\n"); return(BADMALLOC); } strcpy (command, path); strcat (command, argv[0]); argv[0] = command; printf ("command = %s\n", command); #endif #ifdef DOS if ((child_status = spawnvp(P_WAIT,argv[0],argv)) == -1) { return (BADEXEC); } #else if ((status = vfork()) != 0) { /* after the exec, control is returned here */ if (status < 0) { printf ("Parent: child failed\n"); return (BADFORK); } else { printf ("Parent - Waiting for child\n"); if ((status=wait(&child_status)) == -1) { printf ("Parent: wait failed\n"); return (BADWAIT); } } } else { /* if vfork returns a 0 */ /* execute command after the initial vfork */ printf ("Parent - Starting Child\n"); #ifdef VMS if ((status=execv(argv[0], argv)) == -1) { #else if ((status=execvp(argv[0], argv)) == -1) { #endif printf ("Parent: execv on child failed\n"); return (BADEXEC); } } #endif #ifdef UNIX child_status = child_status >> 8; #endif return (child_status); } int _execve(char **argv, char **envp) { int status, child_status; /* fork off the child process */ /* vfork returns values on two different occasions : 1) It returns a 0 the first time it is called, before the exec functions is called. 2) After the exec call is made, control is passed back to the parent at the point of the vfork. */ #ifdef DOS if ((child_status = spawnve(P_WAIT,argv[0],argv,envp)) == -1) { return (BADEXEC); } #else if ((status = vfork()) != 0) { /* after the exec, control is returned here */ if (status < 0) { printf ("Parent: child failed\n"); return (BADFORK); } else { printf ("Parent - Waiting for child\n"); if ((status=wait(&child_status)) == -1) { printf ("Parent: wait failed\n"); return (BADWAIT); } } } else { /* if vfork returns a 0 */ /* execute command after the initial vfork */ printf ("Parent - Starting Child\n"); if ((status=execve(argv[0], argv, envp)) == -1) { printf ("Parent: execve on child failed\n"); return (BADEXEC); } } #endif #ifdef UNIX child_status = child_status >> 8; #endif return (child_status); } [LISTING TWO] /* One of the following must be defined here or on the compile line #define DOS 1 #define UNIX 1 */ #define VMS 1 #define BADFORK -1 #define BADEXEC -2 #define BADWAIT -3 #define BADPATH -4 #define BADMALLOC -5 [LISTING THREE] #include #include #include "exec.h" char envp1[50] = "HOME=sys$sysdevice:[weisfeld]"; char envp2[50] = "TERM=vt100"; char envp3[50] = "PATH=sys$sysdevice:[weisfeld.exe]"; char envp4[50] = "USER=test"; int main() { int status, child_status; char **argv; char *envp[6]; envp[0] = envp1; envp[1] = envp2; envp[2] = envp3; envp[3] = envp4; envp[4] = 0; printf ("CALL EXECV\n"); argv = (char *)convert("getenv"); status = _execv(argv); check_status(status); free (argv); printf ("CALL EXECVE\n"); argv = (char *)convert("getenv"); status = _execve(argv, envp); check_status(status); free (argv); printf ("CALL EXECVP\n"); argv = (char *)convert("getenv"); status = _execvp(argv); check_status(status); free (argv); return; } check_status(status) int status; { switch(status) { case BADFORK: printf ("Error: bad fork\n"); break; case BADEXEC: printf ("Error: bad exec\n"); break; case BADWAIT: printf ("Error: bad wait\n"); break; case BADPATH: printf ("Error: bad path\n"); break; case BADMALLOC: printf ("Error: bad malloc\n"); break; default: printf ("Child status = %d\n", status); break; } } [LISTING FOUR] #include #include #include #define EXIT_NORMAL 1 #define EXIT_ERROR 5 /* convert line to 'c' like argv */ char **convert(char *ptr) { static char buffer[100]; char *bufptr; int offset = 0; int counter = 0; char **argv; strcpy (buffer, ptr); bufptr = &buffer; for (;;) { /* bypass white space */ while (isspace(*bufptr)) { bufptr++; } /* if we have a null string break out of loop */ if (*bufptr == '\0') break; counter++; /* continue until white space of string terminator is found */ while ((!isspace(*bufptr)) && (*bufptr != '\0')) { bufptr++; } } /* get space for argument */ if ((argv = (char **)calloc(counter+1, sizeof(char *))) == (char **) 0) { printf ("Error: no space available\n"); return (EXIT_ERROR); } bufptr = &buffer; /* build argument */ for (;;) { while (isspace(*bufptr)) { *bufptr = '\0'; bufptr++; } if (*bufptr == '\0') break; *(argv + offset++) = bufptr; while ((!isspace(*++bufptr)) && (*bufptr != '\0')); } /* return all the arguments */ return(argv); } [LISTING FIVE] #include #define EXIT_NORMAL 1 main() { char *logical; logical = getenv("HOME"); printf ("HOME = %s\n", logical); logical = getenv("TERM"); printf ("TERM = %s\n", logical); logical = getenv("PATH"); printf ("PATH = %s\n", logical); logical = getenv("USER"); printf ("USER = %s\n", logical); return(EXIT_NORMAL); } [LISTING SIX] CALL EXECV Parent - Starting Child HOME = sys$sysdevice:[weisfeld] TERM = vt300-80 PATH = sys$sysdevice:[weisfeld.test] USER = WEISFELD Child status = 1 CALL EXECVE Parent - Starting Child HOME = sys$sysdevice:[weisfeld] TERM = vt100 PATH = sys$sysdevice:[weisfeld.exe] USER = test Child status = 1 CALL EXECVP command = [WEISFELD.EXE]getenv Parent - Starting Child HOME = sys$sysdevice:[weisfeld] TERM = vt300-80 PATH = sys$sysdevice:[weisfeld.test] USER = WEISFELD Child status = 1 Example 1: if ( (status = fork()) != 0) { /* parent code */ if (status < 0) error (fork failed); if (wait(&child_status) == -1) error (wait failed); } else { /* exec the child */ if (exec() == -1) error(exec failed); } Example 2: if ((status = spawn ()) == -1 ) error (spawn failed); Example 3: main(argc,argv,envp); int argc; char *argv[]; char *envp[]; Example 4: (a) execv(argv[0], argv); spawnv(P_WAIT, argv[0], argv); (b) execl(command, command, arg 1, ..., arg N, NULL); (c) execl ("command", "command", "-x", "-c", "-v", NULL); spawnl (P_WAIT, "command", "command", "-x", "-c", "-v", NULL); (d) char *argv[] = {"command", "-x", "-c", "-v", NULL} execv(argv[0], argv); spawnv(P_WAIT, argv[0], argv); (e) char *argv[] = {"getenv",NULL}; execv(argv[0], argv); spawnv(P_WAIT, argv[0], argv); (f) char *argv[] = {"[test.exe]getenv",NULL}; /* for VMS */ char *argv[] = {"/test/bin/getenv",NULL}; /* for UNIX */ char *argv[] = {"C:\\bin\\getenv",NULL}; /* for DOS */ (g) execvp(argv[0], argv); spawnvp(P_WAIT, argv[0], argv); (h) char *argv[] = {"getenv",NULL}; char *envp[] = { "HOME = /test/home", "TERM = vt100", "PATH = /test/bin", "USER = test" NULL } execve(argv[0], argv, envp); spawnve(P_WAIT, argv[0], argv, envp);