spawn(), spawnp() — Spawn a new process
Standards
Standards / Extensions | C or C++ | Dependencies |
---|---|---|
POSIX.4b
z/OS® UNIX |
both |
Format
#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[]);
General description
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.- Parameter
- Description
- path
- Path name used by spawn() that identifies the new process image file to execute.
- file
- Used by spawnp() to construct path name that identifies the new
process image file. If the file parameter contains a slash character,
spawnp() uses the file parameter as a path name for the new process
image file. Otherwise, spawnp() obtains the path prefix for this file
by a search of the directories passed as the environment variable
PATH
. - fd_count
- Specifies the number of file descriptors the child process inherits.
It may take values from zero to OPEN_MAX. Except for those
file descriptors designated by
SPAWN_FDCLOSED
, each of the child's file descriptors,x
, in the range zero to fd_count-1 inherits descriptor fd_map[x] from the parent process.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
. - fd_map
- If the fd_map parameter is NULL, fd_count and fd_map are
ignored. All file descriptors except those with the
FD_CLOEXEC
orFD_CLOFORK
attribute are inherited without reordering. File descriptors with theFD_CLOEXEC
orFD_CLOFORK
attribute are closed under simple inheritance.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
andFD_CLOFORK
file descriptor attributes are never inherited.The
FD_CLOEXEC
andFD_CLOFORK
file descriptor attributes have no effect on inheritance when the fd_map parameter is not NULL.Note: For XTI endpoints, fd_map must not map to a number greater than 65535 in the child process. - inherit
- The name of a data area that contains the inheritance structure.
The 'struct inheritance' is defined as follows:
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() }
Theinherit.flags
effect spawn() and spawnp() as follows:SPAWN_SETGROUP
- If the
SPAWN_SETGROUP
flag is set ininherit.flags
, then the child's process group is as specified ininherit.pgroup
.If the
SPAWN_SETGROUP
flag is set ininherit.flags
andinherit.prgroup
is set toSPAWN_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. SPAWN_SETSIGMASK
- If the
SPAWN_SETSIGMASK
flag is set in inherit.flags, the child process initially has the signal mask specified ininherit.sigmask
. SPAWN_SETSIGDEF
- If the
SPAWN_SETSIGDEF
flag is set ininherit.flags
, the signals specified ininherit.sigdefault
are set to their default actions in the child process. Signals set to the default action in the parent process, are set to the default action in the new process.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 ininherit.flags
and the signal being indicated ininherit.sigdefault
. SPAWN_SETTCPGRP
- If the
SPAWN_SETTCPGRP
flag is set ininherit.flags
, the file descriptor specified ininherit.ctlttyfd
is used to set the controlling terminal file descriptor (tcsetpgrp()) for the child's foreground process group. The child's foreground process group is inherited from the parent, unless theSPAWN_SETGROUP
flag ininherit.flags
is set, indicating that the value specified ininherit.pgroup
is to be used to determine the child's process group. SPAWN_PROCESS_INITTAB
- If this flag is set, spawn attempts to read the /etc/inittab file and process the entries found
there. This processing involves the spawning of child shell processes to run each of the commands
identified in the file. Only the
SPAWN_SETSIGMASK
flag can be set in combination with this flag. All other flags will be ignored. Use of this flag implies that only file descriptors 0, 1, and 2 will be initially opened in the child process. File descriptor 0 will be initially opened as /dev/null, while file descriptors 1 and 2 will initially opened as /etc/log. Thefd_count
andfd_map
parameters will be ignored. This flag is currently restricted to the /usr/sbin/init process. See z/OS UNIX System Services Planning for more information on the /etc/inittab support.
- argv
- The value in the first element of argv should
point to a file name that is associated with the process being started
by the spawn() or spawnp() operation.
The number of bytes available for the new process's combined argument and environment lists is ARG_MAX.
- envp
- The value envp contains the list of environmental variables that is to be passed to the specified program.
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.
- Process group ID (unless the SPAWN_SETGROUP flag is set
in
inherit.flags
) - Session membership
- Real user ID
- Real group ID
- Supplementary group IDs
- Priority
- Current working directory
- Root directory
- File creation mask
- Signal mask (unless the SPAWN_SETSIGMASK flag is set in
inherit.flags
) - Signal actions specified as default (SIG_DFL)
- Signal actions specified as ignore (SIG_IGN) (except as modified
by
inherit.sigdefault
and the SPAWN_SETSIGDEF flag set ininherit.flags
)
- Signals set to be caught by the calling process are set to the default action (SIG_DFL).
- The process and system utilization times for the child are set to zero.
- Any file locks previously set by the parent are not inherited by the child.
- The child process has no alarms set.
- The child process has no interval timers set.
- The child has no pending signals.
- Memory mappings established by the parent are not inherited by the child.
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.
- Value
- Description
- nn
- Job log messages are to be written to open file descriptor nn.
- STDERR
- Job log messages are to be written to the standard error file descriptor, 2.
- None
- Job log messages are not to be written. This is the default.
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.
- _BPX_SHAREAS=YES - Indicates that the child process that is to
be created is to run in the same address space as the parent. In
the following circumstances, the _BPX_SHAREAS=YES value cannot be
honored, and the child process is created in its own address space:
- If the program to be run is a set-user-ID or set-group-ID program that would cause the effective user-ID or group-ID of the child process to be different from that of the parent process.
- If the program to be run is an APF-authorized HFS or MVS program and the caller is not running APF authorized.
- If the program to be run is an unauthorized HFS or MVS program and the caller is running APF authorized.
- If the specified file name represents an external link or a sticky bit file. However, if the program that is to be run is a shell script and _BPX_SPAWN_SCRIPT=YES is set, the process runs in the same address space. _BPX_SPAWN_SCRIPT only has an effect while running in the z/OS shell (/bin/sh... NOT /bin/tcsh).
- If the address space of the parent lacks the necessary resources to create another process within the address space.
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.
- _BPX_SHAREAS=MUST - Indicates that the child process that is to
be created must run in the same address space as the parent, or the
spawn request will fail. In the following circumstances, the _BPX_SHAREAS=MUST
value cannot be honored, and the spawn invocation fails:
- If the program to be run is a set-user-ID or set-group-ID program that would cause the effective user ID or group ID of the child process to be different from that of the parent process.
- If the program to be run is an APF-authorized HFS or MVS program and the caller is not running APF authorized.
- If the program to be run is an unauthorized HFS or MVS program and the caller is running APF authorized.
- If the address space of the parent lacks the necessary resources to create another process within the address space.
- _BPX_SHAREAS=REUSE - Indicates that the child process to be created
is to run in the same address space as the parent; also, that it will
be created as a medium-weight process. Specifying REUSE allows the
caller to indicate that it wants to reuse the existing process structure
for locally spawned processes. The same rules that apply to the creation of a local spawn process apply to the specification of a local spawn medium-weight process. In addition, in the following circumstances, the _BPX_SHAREAS=REUSE value cannot be honored, and the child process will be created as a non-medium weight local spawn process:
- If PTRACE is active for the process.
- If the program to execute is a REXX exec.
For performance reasons, the STEPLIB that is specified for each medium-weight process that is created for the address space should be the same.
- _BPX_SHAREAS=NO - Indicates that the child process that is to be created is to run in a separate address space from the address space of the parent. This is the default behavior for the spawn service if the _BPX_SHAREAS environment variable is not specified, or if it contains an unsupported value.
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.
- STEPLIB=NONE. No Steplib DD is to be created for the new process image.
- STEPLIB=CURRENT. The TASKLIB, STEPLIB or JOBLIB DD data set allocations that are active for the calling task at the time of the call to spawn() and spawnp() are propagated to the new process image, if found to be cataloged. Uncataloged data sets are not propagated to the new process image.
- STEPLIB=Dsn1:Dsn2:,...DsnN. The specified data sets, Dsn1:Dsn2:...DsnN,
are built into a STEPLIB DD in the new process image. Note: The actual name of the DD is not STEPLIB, but is a system-generated name that has the same effect as a STEPLIB DD.
- The caller does not have the proper security access to a data set.
- A data set is uncataloged or is not in load library format.
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.
- A prior loaded copy of an HFS program in the same address space
is reused under the same circumstances that apply to the reuse of
a prior loaded MVS unauthorized
program from an unauthorized library by the MVS XCTL service with the following exceptions:
- If the calling process is in Ptrace debug mode, a prior loaded copy is not reused.
- If the calling process is not in Ptrace debug mode, but the only prior loaded usable copy found of the HFS program is in storage modifiable by the caller, the prior copy is not reused.
- If the specified file name represents an external link or a sticky bit file, the
program is loaded from the caller's MVS load library search
order. For an external link, the external name is only used if the name is eight characters or less,
otherwise the caller receives an error from the
loadhfs
service. For a sticky bit program, the file name is used if it is eight characters or less. Otherwise, the program is loaded from the HFS, and the following restriction exists for sticky bit programs that have theset-user-ID
orset-group-ID
attribute:If the program is found in the MVS program search order, the MVS program name must have a
BPX.STICKYSUG.program_name
resource profile defined in the RACF® FACILITY class. See z/OS UNIX System Services Planning for details on defining the resource profile. Failure to follow this restriction will cause the abend EC6 with code xxxxE055. - If the calling task is in a WLM enclave, the resulting task in the new process image is joined to the same WLM enclave. This allows WLM to manage the old and new process images as one "business unit of work" entity for system accounting and management purposes.
Returned value
If successful, spawn() and spawnp() return the value of the process ID of the child process to the parent process.
- Error Code
- Description
- E2BIG
- The number of bytes used by the argument and environment list of the new process image is greater than the system-imposed limit of ARG_MAX bytes.
- EACCES
- Search permission is denied for a directory in the path of the new process image file or the new process image file denies execution permission, or the new process image file is not a regular file and the implementation does not support execution of files of its type.
- EAGAIN
- The system lacked the necessary resources to create another process or the system-imposed limit on the total number of processes or UIDs under execution by a single user would be exceeded.
- EBADF
- An entry in the
fd_map
array refers to an invalid file descriptor or the controlling terminal file descriptor specified in theinherit.ctlttyfd
is not valid. - EFAULT
- The system detected an invalid address in attempting to use a parameter of the call.
- EINVAL
- One or more of the following conditions were detected:
- The username that was specified on the _BPX_USERID environment variable has an incorrect length.
- An attribute that was specified in the inheritance structure (BPXYINHE) is not valid or contains an unsupported value.
- The version number that was specified for the inheritance structure (BPXYINHE) is not valid.
- The inheritance structure length that was specified by the Inherit_area_len parameter or within the inheritance structure does not contain a length that is appropriate for the BPXYINHE version.
- The process group ID that was specified in the inheritance structure is less than zero or has some other unsupported value.
The following reason codes can accompany the return code: JROK, JRUserNameLenError, JRJsRacXtr, JRInheUserid, JRInheRegion, JRInheCPUTime, JRInheDynamber, JRInheAccountData, JRInheCWD, JRInheSetPgrp, JRInheVersion, and JRInheLength.
- ELOOP
- A loop exists in symbolic links encountered during resolution file argument. This error is issued if more than 8 symbolic links are detected in the resolution of file name.
- EMVSERR
- An MVS internal error has occurred. This may indicate a problem with security permissions for the user calling spawn() or spawnp().
- EMVSSAF2ERR
- The executable file is a
set-user-ID
orset-group-ID
file and the file owner's UID or GID is not defined to the Security Authorization Facility (SAF), or _BPX_USERID was specified and the specified username was not defined to SAF with a z/OS UNIX segment. - ENAMETOOLONG
- The length of the path or file arguments, or an element of the environment variable PATH prefixed to file exceeds PATH_MAX, or a path name component is longer than NAME_MAX and {_POSIX_NO_TRUNC} is in effect for that file.
- ENOENT
- One or more components of the path name of the new process image file do not exist or the path or file argument is empty.
- ENOEXEC
- The new process image file has the appropriate access permission but is not in the proper
format. Note: Reason codes further qualify the errno. For most of the reason codes, see z/OS UNIX System Services Messages and Codes.For ENOEXEC, the reason codes are:
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. - ENOMEM
- The new process requires more memory than is permitted by the hardware or the operating system.
- ENOTDIR
- A component of the path prefix of the new process image file is not a directory.
- ENOTTY
- The tcsetpgrp() failed for the specified controlling terminal
file descriptor in
inherit.ctlttyfd
. The failure occurred because the calling process does not have a controlling terminal, or the specified file descriptor is not associated with the controlling terminal, or the controlling terminal is no longer associated with the session of the calling process. - EPERM
- The spawn failed for one of the following reasons:
- The spawned process is not a process group leader.
- The _BPX_USERID environment variable was specified, but the invoker does not have appropriate privileges to change the MVS identity.
- The invoker does not have the appropriate privileges to change one or more of the attributes specified in the inheritance structure (BPXYINHE).
The following reason codes can accompany the return code: JROK, JRNoChangeIdentity, JRInheUserid, JRInheRegion, JRInheCPUTime, JRInheUmask, and JRInheCWD.
- ESRCH
- The process group ID specified in
inherit.pgroup
is not that of a process group in the session of the calling process.
Example
#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);
}
Example
#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);
}
Related information
- spawn.h — spawn() constants and inheritance structure
- sys/wait.h — Hold processes
- alarm() — Set an alarm
- chmod() — Change the mode of a file or directory
- exit() — End program
- _exit() — End a process and bypass the cleanup
- fcntl() — Control open file descriptors
- fork() — Create a new process
- kill() — Send a signal to a process
- rexec() — Execute commands one at a time on a remote host
- setuid() — Set the effective user ID
- __spawn2(), __spawnp2() — Spawn a new process using enhanced inheritance structure
- stat(), stat64() — Get file information
- times() — Get process and child process times
- wait() — Wait for a child process to end
- waitpid() — Wait for a specific child process to end