posix_spawn(), posix_spawnp()

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) An absolute path to the executable. Use posix_spawnp() to search for the executable to spawn.
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:

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

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.

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()

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):

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

All process attributes—other than those influenced by the spawn attributes or the file actions—appear in the new process image as though fork() had been called to create a child process, and then a member of the exec() family of functions had been called by the child process to execute the new process image.

In the QNX Neutrino implementation, 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 the POSIX_SPAWN_SETPGROUP flag, 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 you want to mask
Set the 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.
Explicitly set the child process's scheduling policy and parameters Set the POSIX_SPAWN_SETSCHEDULER flag (in which case the setting of the POSIX_SPAWN_SETSCHEDPARAM flag doesn't matter), call posix_spawnattr_setschedpolicy() to specify the scheduling policy, and call posix_spawnattr_setschedparam() to specify the scheduling parameters.
Set the child process's scheduling parameters, but use the parent's scheduling policy Set the POSIX_SPAWN_SETSCHEDPARAM flag and call posix_spawnattr_setschedparam() to specify 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 the POSIX_SPAWN_RESETIDS flag.

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 POSIX_SPAWN_SETND 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
Associate the child process with a scheduler partition Set POSIX_SPAWN_SETSPART and call posix_spawnattr_addpartid(), specifying a partition ID, or posix_spawnattr_addpartition(), specifying a partition name
Restrict the CPUs that the child process can run on Set POSIX_SPAWN_EXPLICIT_CPU and call posix_spawnattr_setrunmask(), specifying the CPU affinity/runmask. If you don't set flag, the child inherits the inherit mask of the calling thread.
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 POSIX_SPAWN_SETSTACKMAX, the stack for the child's main thread will be the default, 512 KB. You can retrieve the default value with a call to posix_spawnattr_getstackmax() using an initialized posix_spawnattr_t object.

Assign a new application ID to the process. 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 for debugging purposes Set POSIX_SPAWN_HOLD
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
Toggle the Address Space Layout Randomization bit. If the parent has ASLR, turn it off for the child; if the parent's bit is off, turn it on for the child. Set POSIX_SPAWN_ASLR_INVERT
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*(): replace 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
Indicate that the process is known to operate safely with 64-bit addressing or doesn't care about the physical memory location Set POSIX_SPAWN_PADDR64_SAFE
Start a new terminal group Set POSIX_SPAWN_TCSETPGROUP

Returns:

EOK
The child was successfully spawned.
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.
ENOENT
  • For posix_spawn(), the executable specified by the path argument couldn't be found. The path must be the full path to the executable. Use posix_spawnp() if you want to search for the executable to spawn.
  • 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. For partitions, the partition ID couldn't be added to the attributes object.
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.
ETXTBSY
The text file that you're trying to execute is busy (e.g., it might be 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().

When Adaptive Partitioning modules are also included in the image, the following error codes can be returned:

EACCES
The spawned program doesn't have permission to associate with the specified partitions.
EEXIST
You tried to associate the child process with more than one scheduling partition. This typically occurs when you create a group name partition with more than one scheduler pseudo-partition, and then attempt to spawn a process and associate with that group name partition.

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