Updated: October 28, 2024 |
Spawn a process
#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] );
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:
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.
libc
Use the -l c option to qcc to link against this library. This library is usually included automatically.
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: | 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.
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().
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().
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.
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.
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. |
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.
In both cases the length of the path used for comparing against PATH_MAX includes the terminating NUL.
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().
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, ¶m); /* 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, ¶m); /* 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);
Safety: | |
---|---|
Cancellation point | Yes |
Interrupt handler | No |
Signal handler | Yes |
Thread | Yes |