posix_spawn(), posix_spawnp()

Updated: October 28, 2024

Spawn a process

Synopsis:

#include <spawn.h>

int posix_spawn( pid_t *_Restrict pid,
                 const char *_Restrict path,
                 const posix_spawn_file_actions_t *file_actions,
                 const posix_spawnattr_t *_Restrict attrp,
                 char * const argv[_Restrict_arr],
                 char * const envp[_Restrict_arr] );

int posix_spawnp( pid_t *_Restrict pid,
                  const char *_Restrict file,
                  const posix_spawn_file_actions_t *file_actions,
                  const posix_spawnattr_t *_Restrict attrp,
                  char * const argv[_Restrict_arr],
                  char * const envp[_Restrict_arr] );

Arguments:

pid
NULL, or a pointer to a location where the function can store the process ID of the child process.
path
(posix_spawn() only) A path to the executable.
file
(posix_spawnp() only) The name of the executable file, which is used to construct a pathname that identifies the new process image file:
  • If file contains a slash, the argument is used as the pathname for the new process image file.
  • Otherwise, the path prefix for this file is obtained by a search of the directories passed as the PATH environment variable. In QNX Neutrino, if PATH isn't defined, the function searches for the executable in the current working directory.
file_actions
NULL, or a pointer to an opaque spawn file actions object that specifies the actions you want to perform on the file descriptors in the child process. For more information, see “File actions,” below.
attrp
NULL, or a pointer to an opaque spawn attributes object that describes attributes to be applied during the spawn. If attrp is NULL, then the default attribute values are used. For more information, see the “Attributes” section, below.
argv
A pointer to an argument vector. The value in argv[0] should represent the filename of the program being loaded, but can be NULL if no arguments are being passed. The last member of argv must be NULL.

As a QNX Neutrino extension, the value of argv can be NULL. In this case, the behavior is exactly as if argv were a pointer to the two-element array:

  • {path, NULL} for posix_spawn()
  • {file, NULL} for posix_spawnp()
envp
A pointer to an array of character pointers, each pointing to a string defining an environment variable. The array is terminated with a NULL pointer. Each pointer points to a character string of the form:
variable=value

that's used to define an environment variable. If the value of envp is NULL, then the child process inherits the environment of the parent process.

If a variable appears more than once in the envp array, the behavior is undefined.

Note: The _Restrict_arr attribute informs the compiler that the argv and envp pointers don't alias each other, and that the compiler is therefore free to perform certain optimizations that otherwise might not be legal.

Library:

libc

Use the -l c option to qcc to link against this library. This library is usually included automatically.

Description:

The posix_spawn() and posix_spawnp() functions create a new process (child process) from the specified process image. The new process image is constructed from a regular executable file called the new process image file. The difference between these two functions is only in the means by which they specify the new process image file:
  • posix_spawn() takes an absolute path to the executable
  • posix_spawnp() performs a path search for the file

A running process has two sets of credentials of importance during its execution: the real user and group IDs (ruid and rgid respectively) and the effective user and group IDs (euid and egid respectively). Typically, when a new process (a child process) is spawned, both sets of credentials (real and effective) are taken from the spawning (parent) process. The exception to this is if the executable file being spawned has either its setuid and/or setgid mode bits set, in which case the euid is set to the uid of the executable, and/or the egid is set to the gid of the executable. POSIX doesn't define a way to directly specify the ruid and rgid of a spawned process. If you want to do this, call posix_spawnattr_setcred() —a QNX Neutrino extension—before spawning the child process.

The ability to do certain operations is controlled by procmgr_ability():
The ability to: Is controlled by:
Create a thread whose priority is above the maximum permitted for unprivileged processes PROCMGR_AID_PRIORITY
Spawn new processes PROCMGR_AID_SPAWN
Set the group ID of the child process PROCMGR_AID_SPAWN_SETGID
Set the user ID of the child process PROCMGR_AID_SPAWN_SETUID
Create a new application ID for the child process PROCMGR_AID_CHILD_NEWAPP
Specify a type identifier for the child process PROCMGR_AID_SETTYPEID
Let the child process link a library at load time or at run time (i.e., with dlopen()) PROCMGR_AID_PROT_EXEC and PROCMGR_AID_MAP_FIXED; these abilities must be given to the child

When a C program is executed as the result of calling posix_spawn() or posix_spawnp(), it's entered as a C-language function call as follows:

int main(int argc, char *argv[]);

where argc is the argument count and argv is an array of character pointers to the arguments themselves.

In addition, the global environ variable is initialized as a pointer to an array of character pointers to the environment strings. The argument argv is an array of character pointers to NULL-terminated strings. The last member of this array is a NULL pointer and isn't counted in argc. These strings constitute the argument list available to the new process image. The value in argv[0] should point to a filename that's associated with the process image that you're starting.

The number of bytes available for the child process's combined argument and environment lists is {ARG_MAX}.

On successful completion, posix_spawn() and posix_spawnp() store the process ID of the child process in the variable pointed to by a non-NULL pid argument, and return zero as the function return value. Otherwise, no child process is created, the value stored in the variable pointed to by a non-NULL pid is undefined, and the functions return an error number. If the pid argument is NULL, the process ID of the child isn't returned to the caller.

If you're using adaptive partitioning, the child runs in the same partition as the parent; you can use SchedCtl() to control that after the child has been spawned.

File actions

The spawn file actions let you control which files are open in the spawned process. These actions are defined in an opaque posix_spawn_file_actions_t object.

If file_actions is NULL, then the file descriptors that are open in the calling process remain open in the child process, except for those whose close-on-exec flag, FD_CLOEXEC, is set. For those file descriptors that remain open, all attributes of the corresponding open file descriptions, including file locks, remain unchanged. For more information about FD_CLOEXEC and file locks, see fcntl().

If file_actions isn't NULL, then the file descriptors open in the child process are those open in the calling process as modified by the spawn file actions object pointed to by file_actions and the FD_CLOEXEC flag for each remaining open file descriptor after the spawn file actions have been processed. The effective order of processing the spawn file actions is:
  1. The set of open file descriptors for the child process is initially the same set as is open for the calling process. All attributes of the corresponding open file descriptions, including file locks, remain unchanged.
  2. The signal mask, signal default actions, and the effective user and group IDs for the child process are changed as specified in the attributes object referenced by attrp.
  3. The file actions specified by the spawn file actions object are performed in the order in which they were added to the spawn file actions object.
  4. Any file descriptor that has its FD_CLOEXEC flag set is closed.
To initialize a file actions object, call posix_spawn_file_actions_init(), and then:
Call: To specify a file descriptor that you want to:
posix_spawn_file_actions_addclose() Close
posix_spawn_file_actions_adddup2() Duplicate with dup2()
posix_spawn_file_actions_addopen() Open

To destroy the file actions object, call posix_spawn_file_actions_destroy().

Attributes

The spawn attributes are defined in an opaque posix_spawnattr_t object. Use posix_spawnattr_init() to initialize the object, and posix_spawnattr_destroy() to destroy it.

Note: In order to set an attribute, you must typically call the appropriate posix_spawnattr_*() function and set the corresponding flag.
By default (i.e., if you don't provide a spawn attributes object, or you don't set the appropriate attribute):
  • The child process inherits the parent's process group.
  • Signals set to the default action in the parent process are set to the default action in the child process.
  • Signals set to be caught by the calling process are set to the default action in the child process.
  • Signals (including SIGCHLD) set to be ignored by the calling process are set to be ignored by the child process.
  • The child process inherits the signal mask of the calling thread.
  • The child process uses the same scheduling policy and parameters as the calling thread.
  • The child process inherits the parent's effective user and group IDs.

    If the setuid bit is set for the process image file, the child process's effective user ID becomes the file's owner ID before the process starts. Similarly, if the setgid bit is set for the process image file, the child process's effective group ID becomes the file's group ID before the process starts.

  • The child process is started on the same node that the calling process is running on.
  • The child's runmask is set to the calling thread's inherit mask.
  • The child process's stack will be set to the default, 512 KB, if the maximum stack is not specified.
  • The child becomes a zombie on its death.
  • The child isn't held for debugging purposes.
  • The child uses the system default settings for alignment.
  • The child uses Address Space Layout Randomization (ASLR) if the parent uses it.
Note:

If the value of the attrp pointer is NULL, then the default values are used.

All process attributes, except those influenced by the spawn attributes or the file actions, appear in the new process image as though fork() had been called to create the child process and then exec*() had been called by the child to execute the new process image.

In QNX Neutrino, fork handlers aren't run when you call posix_spawn() or posix_spawnp().

You can do the following by using the attributes defined by POSIX. You can get and set the POSIX flags by calling the POSIX posix_spawnattr_getflags() and posix_spawnattr_setflags() routines, or the QNX Neutrino posix_spawnattr_getxflags() and posix_spawnattr_setxflags() routines.

If you want to: Do the following:
Explicitly specify the process group for the child process Set the POSIX_SPAWN_SETPGROUP flag and call posix_spawnattr_setpgroup(), specifying a nonzero process group ID
Put the child in a new process group with a process group ID equal to its process ID Set POSIX_SPAWN_SETPGROUP and call posix_spawnattr_setpgroup(), specifying a process group ID of zero
Set the initial signal mask of the child process Set POSIX_SPAWN_SETSIGMASK and call posix_spawnattr_setsigmask(), specifying the set of signals to mask
Set actions for certain signals to the default action in the child process Set POSIX_SPAWN_SETSIGDEF and call posix_spawnattr_setsigdefault(), specifying the set of signals for which you're defining actions
Explicitly set the child process's scheduling policy and parameters Set POSIX_SPAWN_SETSCHEDULER (in this case, you don't have to set POSIX_SPAWN_SETSCHEDPARAM), call posix_spawnattr_setschedpolicy() to set the scheduling policy, and call posix_spawnattr_setschedparam() to set the scheduling parameters
Set the child process's scheduling parameters, but use the parent's scheduling policy Set POSIX_SPAWN_SETSCHEDPARAM and call posix_spawnattr_setschedparam() to set the scheduling parameters
Reset the child process's effective user and group IDs to the parent's real user and group IDs, and make the child process inherit the parent's real (rather than the effective) user and group IDs Set POSIX_SPAWN_RESETIDS.

If the setuid bit is set for the process image file, the child process's effective user ID becomes the file's owner ID before the process starts. Similarly, if the setgid bit is set for the process image file, the child process's effective group ID becomes the file's group ID before the process starts.

You can do the following by using the attributes defined as extensions by QNX Neutrino. You can get and set the QNX Neutrino and POSIX flags by calling posix_spawnattr_getxflags() and posix_spawnattr_setxflags(). Both of these routines are QNX Neutrino extensions.

If you want to: Do the following:
Spawn the child process on a different node Set the POSIX_SPAWN_SETND flag and call posix_spawnattr_setnode(), specifying the remote node ID
Make the child process ignore specific signals Set POSIX_SPAWN_SETSIGIGN and call posix_spawnattr_setsigignore(), specifying the signals you want to ignore
Restrict the CPUs that the child process can run on Set POSIX_SPAWN_EXPLICIT_CPU and call posix_spawnattr_setrunmask(), specifying the processor affinity/runmask. If you don't set this flag, the child inherits the calling thread's runmask.
Specify the user and group IDs for the child process Set POSIX_SPAWN_SETCRED and call posix_spawnattr_setcred(), specifying the IDs
Set the maximum stack size for the child process Set POSIX_SPAWN_SETSTACKMAX and call posix_spawnattr_setstackmax(), specifying the stack size. If you don't set this flag, the stack size for the child's main thread will be the default, 512 KB. You can get the maximum size by calling posix_spawnattr_getstackmax().
Assign a new application ID to the process. For more information, see "Application groups" in the QNX Neutrino System Security Guide. Set POSIX_SPAWN_NEWAPP. If you don't set this flag, the process inherits the parent's application ID.
Prevent the child process from becoming a zombie on its death Set POSIX_SPAWN_NOZOMBIE. No child return or exit information will be available.
Hold the child process as if it had received a SIGSTOP as soon as it was spawned. To resume this process, you must send it a SIGCONT. This is useful for debugging, configuring the process's abilities, or using setgroupspid() to set the child's supplementary group set. Set POSIX_SPAWN_HOLD
(QNX Neutrino 7.0 or later) Start the child as a different security type Set POSIX_SPAWN_SETTYPEID
Use the system default settings for alignment Set POSIX_SPAWN_ALIGN_DEFAULT
Attempt to always fault data misalignment references Set POSIX_SPAWN_ALIGN_FAULT
Make the child process not fault on misalignment; attempt to fix it instead (this approach might be slow) Set POSIX_SPAWN_ALIGN_NOFAULT
Make the new process a session leader Set POSIX_SPAWN_SETSID
Debug process (this is used only for debugging the kernel itself) Set POSIX_SPAWN_DEBUG
Cause the spawn to act like exec*(), replacing the calling program in memory with the newly loaded program. If successful, no return is made to the calling program. Set POSIX_SPAWN_EXEC
Search the PATH environment variable for the executable Set POSIX_SPAWN_SEARCH_PATH
Start a shell, passing path as a script, if unable to run path in any other way Set POSIX_SPAWN_CHECK_SCRIPT
Start a new terminal group Set POSIX_SPAWN_TCSETPGROUP
(QNX Neutrino 7.0.4 or later) Assign the preset address space ID to the child Set POSIX_SPAWN_SETASID
(QNX Neutrino 7.0.4 or later) Indicate that the process is critical to the system functionality, meaning if this critical process dies, the system will crash. Set POSIX_SPAWN_CRITICAL. To create a critical process with POSIX_SPAWN_CRITICAL, your process needs the PROCMGR_AID_REBOOT ability. For more information, see procmgr_ability().
(QNX Neutrino 7.1 or later) Set the current working directory for the child process Set POSIX_SPAWN_SETCWD and call posix_spawnattr_setcwd_np(). If you don't set this flag, the child process has the same current working directory as the parent process.
Enable or disable Address Space Layout Randomization (ASLR) for the child process, or have the child inherit the parent's settings (the default). Call posix_spawnattr_setaslr().
Toggle the Address Space Layout Randomization (ASLR) feature. If it's enabled for the parent, disable it for the child; if it's disabled for the parent, enable it for the child. Set POSIX_SPAWN _ASLR_INVERT. However, QNX recommends that you use posix_spawnattr_setaslr() instead.

Returns:

EOK
The child was successfully spawned.
EACCES
The calling process doesn't have permission to search a directory listed in path, or it doesn't have permission to execute path, or path's filesystem was mounted with the ST_NOEXEC flag.
EBADF
A problem occurred when posix_spawn() was duplicating a file descriptor. For example, another thread might have opened or closed a file descriptor while the posix_spawn() was occurring. You can add synchronization around the operations that involve file descriptors, or try calling posix_spawn() again.
EINVAL
An argument was invalid; the spawn attributes or file actions object is invalid, or the name of the process image file is NULL or an empty string.

If you specify an invalid value in the file actions or spawn attributes, posix_spawn() or posix_spawnp() might fail; if the value causes an error to occur after the child has been successfully spawned, the child process may exit with a status of 127.

EIO
An internal error occurred in the library.
ENAMETOOLONG
  • The length of the path argument is greater than PATH_MAX.
  • An action set with posix_spawn_file_actions_addopen() has a path that's longer than PATH_MAX.

In both cases the length of the path used for comparing against PATH_MAX includes the terminating NUL.

ENOENT
  • For posix_spawn(), the executable specified by the path argument couldn't be found.
  • For posix_spawnp(), the executable specified by the file argument couldn't be found in any of the PATH environment variable locations.
ENOMEM
The memory required to create the message to send to procnto couldn't be allocated memory to create the new process and its associated data structures couldn't be allocated.
ENOTSUP
  • The POSIX_SPAWN_SETTYPEID flag was set without loading a security policy.
  • An address space ID asid was specified that's invalid for the architecture of the target system; see posix_spawn_setasid() for information on the valid values.
EPERM
The calling process doesn't have the required permission (see procmgr_ability()), or an underlying call to mmap() failed because it attempted to set PROT_EXEC for a region of memory covered by an untrusted memory-mapped file. This error may also indicate that the process lacks the PROCMGR_AID_SETTYPEID ability or does not have a subrange that includes typeid.
ESECTYPEINVAL
The type identifier either does not exist or has no abilities associated with it. A type must be the source type in at least one allow, allow_attach or allow_link rule for a process to have its type identifier set to it. (These rules are defined in the security policy.)
ETXTBSY
The file that you're trying to execute is open for writing.

If posix_spawn() or posix_spawnp() fails for any of the reasons that would cause fork() or one of the exec*() family of functions to fail, an error value is returned as described for those functions (or, if the error occurs after the calling process successfully returns, the child process exits with exit status 127).

If POSIX_SPAWN_SETPGROUP is set in the spawn-flags attribute of the object referenced by attrp, and posix_spawn() or posix_spawnp() fails while changing the child's process group, an error value is returned as described for setpgid() (or, if the error occurs after the calling process successfully returns, the child process exits with exit status 127).

If POSIX_SPAWN_SETSCHEDPARAM is set and POSIX_SPAWN_SETSCHEDULER isn't set in the spawn-flags attribute of the object referenced by attrp, then if posix_spawn() or posix_spawnp() fails for any of the reasons that would cause sched_setparam() to fail, an error value is returned as described for sched_setparam() (or, if the error occurs after the calling process successfully returns, the child process exits with exit status 127).

If POSIX_SPAWN_SETSCHEDULER is set in the spawn-flags attribute of the object referenced by attrp, and if posix_spawn() or posix_spawnp() fails for any of the reasons that would cause sched_setscheduler() to fail, an error value is returned as described for sched_setscheduler() (or, if the error occurs after the calling process successfully returns, the child process exits with exit status 127).

If the file_actions argument isn't NULL, and specifies any close(), dup2(), or open() actions to be performed, and if posix_spawn() or posix_spawnp() fails for any of the reasons that would cause close(), dup2(), or open() to fail, an error value is returned as described for those functions (or, if the error occurs after the calling process successfully returns, the child process exits with exit status 127). For example, if the parent process closes a file descriptor while it's being duplicated, you'll get an error of EBADF. An open() file action may, by itself, result in any of the errors described by close() or dup2(), in addition to those described by open().

The posix_spawn() and posix_spawnp() functions can also return any error returned by a stat() on path. See also the errors for ConnectAttach() and MsgSendvnc().

Examples:

Specify an absolute path, using posix_spawn():

pid_t child_pid;
int ret;

ret = posix_spawn (&child_pid, "/home/dpr/hello", NULL, NULL, NULL, NULL);
if (ret != EOK)
{
    printf("posix_spawn() failed: %s\n", strerror(ret) );
    return EXIT_FAILURE;
}

printf ("Child pid: %d\n\n", child_pid);

To specify a relative path, use posix_spawnp():

ret = posix_spawnp (&child_pid, "./hello", NULL, NULL, NULL, NULL);

If the path doesn't include a slash, search the PATH for the executable:

ret = posix_spawnp (&child_pid, "hello", NULL, NULL, NULL, NULL);

Use the spawn attributes and flags to lower the child process's priority (with error checking omitted, in the interest of brevity):

pid_t child_pid;
posix_spawnattr_t attr;
int policy;
struct sched_param param;

/* Get the parent's scheduling policy and parameters. */
pthread_getschedparam (pthread_self(), &policy, &param);

/* Initialize the spawn attributes structure. */
posix_spawnattr_init (&attr);

/* Set the child's priority to be two levels lower. */
param.sched_priority -= 2;
posix_spawnattr_setschedparam (&attr, &param);

/* Set the appropriate flag to make the changes take effect. */
posix_spawnattr_setflags (&attr, POSIX_SPAWN_SETSCHEDPARAM);
  
/* Spawn the child process. */
posix_spawnp (&child_pid, "./hello", NULL, &attr, NULL, NULL);

Classification:

POSIX 1003.1 SPN

Safety:  
Cancellation point Yes
Interrupt handler No
Signal handler Yes
Thread Yes