Standards / Extensions | C or C++ | Dependencies |
---|---|---|
POSIX.4b |
both |
#define _POSIX_SOURCE
#include <spawn.h>
pid_t spawn(const char *path,
const int fd_count,
const int fd_map[],
const struct inheritance *inherit,
const char *argv[],
const char *envp[]);
pid_t spawnp(const char *file,
const int fd_count,
const int fd_map[],
const struct inheritance *inherit,
const char *argv[],
const char *envp[]);
The spawn() and spawnp() functions create a new process from the specified process image. spawn() and spawnp() create the new process image from a regular executable file called the new process image file.
int main (int argc, char *argv[]);
extern char **environ;
is
initialized as a pointer to an array of character pointers to the
environment strings. The argv and environ arrays
are each terminated by a NULL pointer. The NULL pointer terminating
the argv array is not counted in argc.The files from fd_count through OPEN_MAX are closed in the child process, as are any elements of fd_map designated as SPAWN_FDCLOSED.
For those file descriptors that remain open, all other attributes of the associated file descriptor object and open file description remain unchanged by this operation.
Directory streams open in the calling process are closed in the new process image.
If an element of fd_map refers to an invalid file descriptor, then the (EBADF) spawn() or spawnp() posts the error status.
The FD_CLOEXEC and FD_CLOFORK file descriptor attributes are never inherited.
The FD_CLOEXEC and FD_CLOFORK file descriptor attributes have no effect on inheritance when the fd_map parameter is not NULL.
struct inheritance {
short flags; --Flags
pid_t pgroup; --Process group
sigset_t sigmask; --Signal mask
sigset_t sigdefault; --Signals set to SIG_DFL
int ctlttyfd; --Cntl tty FD for tcsetpgrp()
}
If the SPAWN_SETGROUP flag is set in inherit.flags and inherit.prgroup is set to SPAWN_NEWPGROUP, then the child is in a new process group with a process group ID equal to its process ID.
If the SPAWN_SETGROUP flag is not set in inherit.flags, the new child process inherits the parent's process group ID.
Signals set to be caught by the calling process are set to the default action in the child process.
Signals set to be ignored by the calling process are set to be ignored by the new process, unless otherwise specified by the SPAWN_SETSIGDEF flag being set in inherit.flags and the signal being indicated in inherit.sigdefault.
The number of bytes available for the new process's combined argument and environment lists is ARG_MAX.
If the set-user-ID mode bit of the new process image file is set, the effective user ID of the new process image is set to the owner id of the new process image file. Similarly, if the set-group-ID mode bit of the new process image file is set, the effective group ID of the new process image is set to the group id of the new process image file. The real user ID, real group ID, and supplementary group IDs of the new process image remain the same as those of the calling process image. The effective user ID and effective group ID of the new process image are saved (as the saved set-user-ID and the saved set-group-ID) for use by the setuid() function.
If the process image was read from a writable file system, then upon successful completion, the spawn() or spawnp() function mark for update the st_atime field of the new process image file.
If the spawn() or spawnp() function is successful, the new child process image file is opened, with all the effects of the open() function.
stdin = fopen("/tmp/sys.stdin","r");
stdout = fopen("/tmp/sys.stdout","w");
stderr = fopen("/tmp/sys.stderr","w");
Aspects of spawn processing are controlled by environment variables. The environment variables that affect spawn processing are the ones that are passed into the spawn syscall and not the environment variables of the calling process. The environment variables of the calling process do not affect spawn processing unless they are the same as those that are passed in envp.
The file that is used to capture messages can be changed at any time by calling the oe_env_np service (BPX1ENV) and specifying _BPXK_JOBLOG with a different file descriptor.
Message capturing is turned off if the specified file descriptor is marked for close on a fork or exec.
Message capturing is process-related. All threads under a given process share the same job log file. Message capturing may be initiated by any thread under that process.
Multiple processes in a single address space can each have different files active as the JOBLOG file; some or all of them can share the same file; and some processes can have message capturing active while others do not.
Only files that can be represented by file descriptors may be used as job log files; MVS™ data sets are not supported.
Message capturing will be propagated on a fork() or spawn(). In the case where a file descriptor was specified, the physical file must be the same for message capturing to continue in the forked or spawned process. If STDERR was specified, the file descriptor may be re-mapped to a different physical file.
Message capturing may be overridden on exec() or spawn() by specifying the _BPXK_JOBLOG environment variable as a parameter to the exec() or spawn().
For more information on the use of environment variables, see z/OS UNIX System Services Programming: Assembler Callable Services Reference.
Security information from the parent's address space is propagated to the child's address space, unless the _BPX_USERID environment variable specifies otherwise. As a result, the child has a security environment equivalent to that of the parent.
The TASKLIB, STEPLIB, or JOBLIB DD data set allocations that are active for the current task are propagated to the child's address space, unless the STEPLIB environment variable specifies otherwise. This causes the child address space to have the same exact MVS program search order as the calling parent task.
The accounting information of the parent's address space is propagated to the child's address space. See z/OS UNIX System Services Planning.
The jobname of the parent is propagated to the child and appended with a numeric value in the range of 1-9 if the jobname is 7 characters or less. If the jobname is 8 characters, then it is propagated as-is. When a jobname is appended with a numeric value, the count wraps back to 1 when it exceeds 9.
If the calling parent task is in a WLM enclave, the child is joined to the same WLM enclave. This allows WLM to manage the parent and child as one "business unit of work" entity for system accounting and management purposes.
Note that only one local spawned process per TSO address space is supported at a given time. This is done to reduce conflict among multiple shells running in the same address space.
For performance reasons, the STEPLIB that is specified for each medium-weight process that is created for the address space should be the same.
If you specify the _BPX_USERID environment variable, then spawn() creates the new address space and image with the specified userid's identity. The invoker of spawn() must be authorized to change MVS identity. The resulting spawn() image will emerge as if a program had done a fork(), setgid(), initgroups(), setuid(), and exec.
The value of _BPX_USERID can be any 1-to-8-character XPG4 compliant username. If you specify both _BPX_USERID and _BPX_SHAREAS, then spawn() ignores _BPX_SHAREAS, and creates a new address space with the new identity.
If the caller of the spawn() function is the z/OS UNIX shell (i.e /bin/sh), then the setting of the _BPX_SPAWN_SCRIPT= environment variable to YES is recommended. The setting of this variable to YES provides a more efficient mechanism to invoke z/OS UNIX shell scripts.
If the STEPLIB environment variable is not specified, spawn() and spawnp() default behavior is the same as if STEPLIB=CURRENT were specified.
If the program to be invoked is a set-user-ID or set-group-ID file and the user-ID or group-ID of the file is different from that of the current process image, then the data sets to be built into the STEPLIB environment for the new process image must be found in the system sanction list for set-user-id and set-group-id programs. Only those data sets that are found in the sanction list are built into the STEPLIB environment for the new process image. For detailed information regarding the sanction list, and for information on STEPLIB performance considerations, see z/OS UNIX System Services Planning.
If successful, spawn() and spawnp() return the value of the process ID of the child process to the parent process.
The following reason codes can accompany the return code: JROK, JRUserNameLenError, JRJsRacXtr, JRInheUserid, JRInheRegion, JRInheCPUTime, JRInheDynamber, JRInheAccountData, JRInheCWD, JRInheSetPgrp, JRInheVersion, and JRInheLength.
Reason Code | Explanation |
---|---|
X'xxxx0C27' | The target HFS file is not in the correct format to be an executable file. |
X'xxxx0C31' | The target HFS file is built at a level that is higher than that supported by the running system. |
The following reason codes can accompany the return code: JROK, JRNoChangeIdentity, JRInheUserid, JRInheRegion, JRInheCPUTime, JRInheUmask, and JRInheCWD.
#define _XOPEN_SOURCE_EXTENDED 1
#include <unistd.h>
#include <spawn.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
/* This program uses spawn instead of fork/exec to create a child
* process and uses unnamed pipes to allow the parent and child to
* exchange communication.
*/
void main(int argc, char *argv[]) {
pid_t child;
int fd_count, fd_map[10];
struct inheritance inherit;
const char *c_argv[10], *c_envp[10];
char buf[256];
int nbytes;
int c_stdin[2], c_stdout[2], c_stderr[2]; /* Pipes for child
* communication */
/* Create pipes to communicate with child via stdin/stdout/stderr */
if(pipe(c_stdin) ||
pipe(c_stdout) ||
pipe(c_stderr) ) {
perror("Bad pipe");
exit(-1);
}
/* Set up file descriptor map for child process */
fd_map[0]=dup(c_stdin[0]); /* child stdin is read end of pipe */
fd_map[1]=dup(c_stdout[1]); /* child stdout is write end of pipe */
fd_map[2]=dup(c_stderr[1]); /* child stderr is write end of pipe */
fd_count=3;
/* Close unused end of pipes for the parent */
close(c_stdin[0]); close(c_stdout[1]); close(c_stderr[1]);
/* Build the argument structure for child arguments.
* [0] is the program name */
c_argv[0]="spawnc";
c_argv[1]="arg1"; c_argv[2]="arg2"; c_argv[3]=NULL;
/* Build the environment structure which defines the child's
* environment variables */
c_envp[0]="TEST_ENV=YES"; c_envp[1]="BPX_SHAREAS=NO"; c_envp[2]=NULL;
/* Spawn the child process */
child=spawnp("spawnc", fd_count, fd_map, &inherit, c_argv, c_envp);
if(child==-1) {
perror("Error on spawn");
exit(-1);
}
else printf("Spawned %i\n", child);
/* Test interaction with the child process */
printf("parent: Asking child, \"what are you doing?\\n\"\n");
strcpy(buf, "child from parent: what are you doing?\n");
if(write(c_stdin[1], buf, sizeof(buf))==-1) {
perror("write stdout");
exit(-1);
}
memset(buf, 0, 255); /* Just zeroing out the buffer */
printf("parent: reading from child now\n");
if((nbytes=read(c_stdout[0], buf, 255))==-1) {
perror("read error:");
exit(-1);
}
printf("parent: child says, \"%s\"\n", buf);
/* Cleanup pipes before exiting */
close(c_stdin[1]); close(c_stdout[0]); close(c_stderr[0]);
exit(0);
}
#include <stdlib.h>
#include <stdio.h>
/* This is a sample child program used by spawn. This program will
* work stand-alone as well as from spawn or fork/exec. */
extern char ** environ; /* External used to access the environment
directly instead of using getenv */
void main(int argc, char *argv[]) {
char *e, **env=environ; /* Used to step through the environment
* to write out to file. */
char buf[256]={0};
FILE *fp=fopen("spawntest.out","w");
int i;
/* Print out the environment variables */
i=0;
fprintf(fp, "Environment:\n");
while(e=env[i++]) fprintf(fp, "%s\n", e);
fprintf(fp, "\n\n");
/* Just to prove getenv works */
fprintf(fp, "TEST_ENV envvar = %s", getenv("TEST_ENV"));
/* Print out the command line arguments */
i=0;
fprintf(fp,"Args:\n");
while(e=argv[i++]) fprintf(fp,"%s\n", e);
fprintf(fp, "\n\n");
/* Print out what was sent on stdin */
fprintf(fp, "Child/parent\n");
if(!gets(buf)) {
ferror(stdin);
exit(-1);
}
fprintf(fp, "child from parent: %i bytes,[%s]\n", strlen(buf), buf);
/* Send something to stdout */
printf("nothing");
fclose(fp);
exit(0);
}