555 lines
18 KiB
HTML
555 lines
18 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
|
<html>
|
|
<head>
|
|
<meta name="generator" content="HTML Tidy, see www.w3.org">
|
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
<link type="text/css" rel="stylesheet" href="style.css"><!-- Generated by The Open Group's rhtm tool v1.2.1 -->
|
|
<!-- Copyright (c) 2001 The Open Group, All Rights Reserved -->
|
|
<title>Rationale</title>
|
|
</head>
|
|
<body>
|
|
|
|
<basefont size="3">
|
|
|
|
<center><font size="2">The Open Group Base Specifications Issue 6<br>
|
|
IEEE Std 1003.1-2001<br>
|
|
Copyright © 2001 The IEEE and The Open Group</font></center>
|
|
|
|
<hr size="2" noshade>
|
|
<h3><a name="tag_03_03"></a>System Interfaces</h3>
|
|
|
|
<p>See the RATIONALE sections on the individual reference pages.</p>
|
|
|
|
<h4><a name="tag_03_03_01"></a>Examples for Spawn</h4>
|
|
|
|
<p>The following long examples are provided in the Rationale (Informative) volume of IEEE Std 1003.1-2001 as a supplement
|
|
to the reference page for <a href="../functions/posix_spawn.html"><i>posix_spawn</i>()</a>.</p>
|
|
|
|
<h5><a name="tag_03_03_01_01"></a>Example Library Implementation of Spawn</h5>
|
|
|
|
<p>The <a href="../functions/posix_spawn.html"><i>posix_spawn</i>()</a> or <a href=
|
|
"../functions/posix_spawnp.html"><i>posix_spawnp</i>()</a> functions provide the following:</p>
|
|
|
|
<ul>
|
|
<li>
|
|
<p>Simply start a process executing a process image. This is the simplest application for process creation, and it may cover most
|
|
executions of <a href="../functions/fork.html"><i>fork</i>()</a>.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<p>Support I/O redirection, including pipes.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<p>Run the child under a user and group ID in the domain of the parent.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<p>Run the child at any priority in the domain of the parent.</p>
|
|
</li>
|
|
</ul>
|
|
|
|
<p>The <a href="../functions/posix_spawn.html"><i>posix_spawn</i>()</a> or <a href=
|
|
"../functions/posix_spawnp.html"><i>posix_spawnp</i>()</a> functions do not cover every possible use of the <a href=
|
|
"../functions/fork.html"><i>fork</i>()</a> function, but they do span the common applications: typical use by a shell and a login
|
|
utility.</p>
|
|
|
|
<p>The price for an application is that before it calls <a href="../functions/posix_spawn.html"><i>posix_spawn</i>()</a> or <a
|
|
href="../functions/posix_spawnp.html"><i>posix_spawnp</i>()</a>, the parent must adjust to a state that <a href=
|
|
"../functions/posix_spawn.html"><i>posix_spawn</i>()</a> or <a href="../functions/posix_spawnp.html"><i>posix_spawnp</i>()</a> can
|
|
map to the desired state for the child. Environment changes require the parent to save some of its state and restore it afterwards.
|
|
The effective behavior of a successful invocation of <a href="../functions/posix_spawn.html"><i>posix_spawn</i>()</a> is as if the
|
|
operation were implemented with POSIX operations as follows:</p>
|
|
|
|
<pre>
|
|
<tt>#include <sys/types.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <sched.h>
|
|
#include <fcntl.h>
|
|
#include <signal.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
<br>
|
|
/* #include <spawn.h> */
|
|
/*******************************************/
|
|
/* Things that could be defined in spawn.h */
|
|
/*******************************************/
|
|
typedef struct
|
|
{
|
|
short posix_attr_flags;
|
|
#define POSIX_SPAWN_SETPGROUP 0x1
|
|
#define POSIX_SPAWN_SETSIGMASK 0x2
|
|
#define POSIX_SPAWN_SETSIGDEF 0x4
|
|
#define POSIX_SPAWN_SETSCHEDULER 0x8
|
|
#define POSIX_SPAWN_SETSCHEDPARAM 0x10
|
|
#define POSIX_SPAWN_RESETIDS 0x20
|
|
pid_t posix_attr_pgroup;
|
|
sigset_t posix_attr_sigmask;
|
|
sigset_t posix_attr_sigdefault;
|
|
int posix_attr_schedpolicy;
|
|
struct sched_param posix_attr_schedparam;
|
|
} posix_spawnattr_t;
|
|
<br>
|
|
typedef char *posix_spawn_file_actions_t;
|
|
<br>
|
|
int posix_spawn_file_actions_init(
|
|
posix_spawn_file_actions_t *file_actions);
|
|
int posix_spawn_file_actions_destroy(
|
|
posix_spawn_file_actions_t *file_actions);
|
|
int posix_spawn_file_actions_addclose(
|
|
posix_spawn_file_actions_t *file_actions, int fildes);
|
|
int posix_spawn_file_actions_adddup2(
|
|
posix_spawn_file_actions_t *file_actions, int fildes,
|
|
int newfildes);
|
|
int posix_spawn_file_actions_addopen(
|
|
posix_spawn_file_actions_t *file_actions, int fildes,
|
|
const char *path, int oflag, mode_t mode);
|
|
int posix_spawnattr_init(posix_spawnattr_t *attr);
|
|
int posix_spawnattr_destroy(posix_spawnattr_t *attr);
|
|
int posix_spawnattr_getflags(const posix_spawnattr_t *attr,
|
|
short *lags);
|
|
int posix_spawnattr_setflags(posix_spawnattr_t *attr, short flags);
|
|
int posix_spawnattr_getpgroup(const posix_spawnattr_t *attr,
|
|
pid_t *pgroup);
|
|
int posix_spawnattr_setpgroup(posix_spawnattr_t *attr, pid_t pgroup);
|
|
int posix_spawnattr_getschedpolicy(const posix_spawnattr_t *attr,
|
|
int *schedpolicy);
|
|
int posix_spawnattr_setschedpolicy(posix_spawnattr_t *attr,
|
|
int schedpolicy);
|
|
int posix_spawnattr_getschedparam(const posix_spawnattr_t *attr,
|
|
struct sched_param *schedparam);
|
|
int posix_spawnattr_setschedparam(posix_spawnattr_t *attr,
|
|
const struct sched_param *schedparam);
|
|
int posix_spawnattr_getsigmask(const posix_spawnattr_t *attr,
|
|
sigset_t *sigmask);
|
|
int posix_spawnattr_setsigmask(posix_spawnattr_t *attr,
|
|
const sigset_t *sigmask);
|
|
int posix_spawnattr_getdefault(const posix_spawnattr_t *attr,
|
|
sigset_t *sigdefault);
|
|
int posix_spawnattr_setsigdefault(posix_spawnattr_t *attr,
|
|
const sigset_t *sigdefault);
|
|
int posix_spawn(pid_t *pid, const char *path,
|
|
const posix_spawn_file_actions_t *file_actions,
|
|
const posix_spawnattr_t *attrp, char *const argv[],
|
|
char *const envp[]);
|
|
int posix_spawnp(pid_t *pid, const char *file,
|
|
const posix_spawn_file_actions_t *file_actions,
|
|
const posix_spawnattr_t *attrp, char *const argv[],
|
|
char *const envp[]);
|
|
<br>
|
|
/*****************************************/
|
|
/* Example posix_spawn() library routine */
|
|
/*****************************************/
|
|
int posix_spawn(pid_t *pid,
|
|
const char *path,
|
|
const posix_spawn_file_actions_t *file_actions,
|
|
const posix_spawnattr_t *attrp,
|
|
char *const argv[],
|
|
char *const envp[])
|
|
{
|
|
/* Create process */
|
|
if ((*pid = fork()) == (pid_t) 0)
|
|
{
|
|
/* This is the child process */
|
|
/* Worry about process group */
|
|
if (attrp->posix_attr_flags & POSIX_SPAWN_SETPGROUP)
|
|
{
|
|
/* Override inherited process group */
|
|
if (setpgid(0, attrp->posix_attr_pgroup) != 0)
|
|
{
|
|
/* Failed */
|
|
exit(127);
|
|
}
|
|
}
|
|
<br>
|
|
/* Worry about process signal mask */
|
|
if (attrp->posix_attr_flags & POSIX_SPAWN_SETSIGMASK)
|
|
{
|
|
/* Set the signal mask (can't fail) */
|
|
sigprocmask(SIG_SETMASK, &attrp->posix_attr_sigmask, NULL);
|
|
}
|
|
<br>
|
|
/* Worry about resetting effective user and group IDs */
|
|
if (attrp->posix_attr_flags & POSIX_SPAWN_RESETIDS)
|
|
{
|
|
/* None of these can fail for this case. */
|
|
setuid(getuid());
|
|
setgid(getgid());
|
|
}
|
|
<br>
|
|
/* Worry about defaulted signals */
|
|
if (attrp->posix_attr_flags & POSIX_SPAWN_SETSIGDEF)
|
|
{
|
|
struct sigaction deflt;
|
|
sigset_t all_signals;
|
|
<br>
|
|
int s;
|
|
<br>
|
|
/* Construct default signal action */
|
|
deflt.sa_handler = SIG_DFL;
|
|
deflt.sa_flags = 0;
|
|
<br>
|
|
/* Construct the set of all signals */
|
|
sigfillset(&all_signals);
|
|
<br>
|
|
/* Loop for all signals */
|
|
for (s = 0; sigismember(&all_signals, s); s++)
|
|
{
|
|
/* Signal to be defaulted? */
|
|
if (sigismember(&attrp->posix_attr_sigdefault, s))
|
|
{
|
|
/* Yes; default this signal */
|
|
if (sigaction(s, &deflt, NULL) == -1)
|
|
{
|
|
/* Failed */
|
|
exit(127);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
<br>
|
|
/* Worry about the fds if they are to be mapped */
|
|
if (file_actions != NULL)
|
|
{
|
|
/* Loop for all actions in object file_actions */
|
|
/* (implementation dives beneath abstraction) */
|
|
char *p = *file_actions;
|
|
<br>
|
|
while (*p != '\0')
|
|
{
|
|
if (strncmp(p, "close(", 6) == 0)
|
|
{
|
|
int fd;
|
|
<br>
|
|
if (sscanf(p + 6, "%d)", &fd) != 1)
|
|
{
|
|
exit(127);
|
|
}
|
|
if (close(fd) == -1)
|
|
exit(127);
|
|
}
|
|
else if (strncmp(p, "dup2(", 5) == 0)
|
|
{
|
|
int fd, newfd;
|
|
<br>
|
|
if (sscanf(p + 5, "%d,%d)", &fd, &newfd) != 2)
|
|
{
|
|
exit(127);
|
|
}
|
|
if (dup2(fd, newfd) == -1)
|
|
exit(127);
|
|
}
|
|
else if (strncmp(p, "open(", 5) == 0)
|
|
{
|
|
int fd, oflag;
|
|
mode_t mode;
|
|
int tempfd;
|
|
char path[1000]; /* Should be dynamic */
|
|
char *q;
|
|
<br>
|
|
if (sscanf(p + 5, "%d,", &fd) != 1)
|
|
{
|
|
exit(127);
|
|
}
|
|
p = strchr(p, ',') + 1;
|
|
q = strchr(p, '*');
|
|
if (q == NULL)
|
|
exit(127);
|
|
strncpy(path, p, q - p);
|
|
path[q - p] = '\0';
|
|
if (sscanf(q + 1, "%o,%o)", &oflag, &mode) != 2)
|
|
{
|
|
exit(127);
|
|
}
|
|
if (close(fd) == -1)
|
|
{
|
|
if (errno != EBADF)
|
|
exit(127);
|
|
}
|
|
tempfd = open(path, oflag, mode);
|
|
if (tempfd == -1)
|
|
exit(127);
|
|
if (tempfd != fd)
|
|
{
|
|
if (dup2(tempfd, fd) == -1)
|
|
{
|
|
exit(127);
|
|
}
|
|
if (close(tempfd) == -1)
|
|
{
|
|
exit(127);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
exit(127);
|
|
}
|
|
p = strchr(p, ')') + 1;
|
|
}
|
|
}
|
|
<br>
|
|
/* Worry about setting new scheduling policy and parameters */
|
|
if (attrp->posix_attr_flags & POSIX_SPAWN_SETSCHEDULER)
|
|
{
|
|
if (sched_setscheduler(0, attrp->posix_attr_schedpolicy,
|
|
&attrp->posix_attr_schedparam) == -1)
|
|
{
|
|
exit(127);
|
|
}
|
|
}
|
|
<br>
|
|
/* Worry about setting only new scheduling parameters */
|
|
if (attrp->posix_attr_flags & POSIX_SPAWN_SETSCHEDPARAM)
|
|
{
|
|
if (sched_setparam(0, &attrp->posix_attr_schedparam) == -1)
|
|
{
|
|
exit(127);
|
|
}
|
|
}
|
|
<br>
|
|
/* Now execute the program at path */
|
|
/* Any fd that still has FD_CLOEXEC set will be closed */
|
|
execve(path, argv, envp);
|
|
exit(127); /* exec failed */
|
|
}
|
|
else
|
|
{
|
|
/* This is the parent (calling) process */
|
|
if (*pid == (pid_t) - 1)
|
|
return errno;
|
|
return 0;
|
|
}
|
|
}
|
|
<br>
|
|
/*******************************************************/
|
|
/* Here is a crude but effective implementation of the */
|
|
/* file action object operators which store actions as */
|
|
/* concatenated token-separated strings. */
|
|
/*******************************************************/
|
|
/* Create object with no actions. */
|
|
int posix_spawn_file_actions_init(
|
|
posix_spawn_file_actions_t *file_actions)
|
|
{
|
|
*file_actions = malloc(sizeof(char));
|
|
if (*file_actions == NULL)
|
|
return ENOMEM;
|
|
strcpy(*file_actions, "");
|
|
return 0;
|
|
}
|
|
<br>
|
|
/* Free object storage and make invalid. */
|
|
int posix_spawn_file_actions_destroy(
|
|
posix_spawn_file_actions_t *file_actions)
|
|
{
|
|
free(*file_actions);
|
|
*file_actions = NULL;
|
|
return 0;
|
|
}
|
|
<br>
|
|
/* Add a new action string to object. */
|
|
static int add_to_file_actions(
|
|
posix_spawn_file_actions_t *file_actions, char *new_action)
|
|
{
|
|
*file_actions = realloc
|
|
(*file_actions, strlen(*file_actions) + strlen(new_action) + 1);
|
|
if (*file_actions == NULL)
|
|
return ENOMEM;
|
|
strcat(*file_actions, new_action);
|
|
return 0;
|
|
}
|
|
<br>
|
|
/* Add a close action to object. */
|
|
int posix_spawn_file_actions_addclose(
|
|
posix_spawn_file_actions_t *file_actions, int fildes)
|
|
{
|
|
char temp[100];
|
|
<br>
|
|
sprintf(temp, "close(%d)", fildes);
|
|
return add_to_file_actions(file_actions, temp);
|
|
}
|
|
<br>
|
|
/* Add a dup2 action to object. */
|
|
int posix_spawn_file_actions_adddup2(
|
|
posix_spawn_file_actions_t *file_actions, int fildes,
|
|
int newfildes)
|
|
{
|
|
char temp[100];
|
|
<br>
|
|
sprintf(temp, "dup2(%d,%d)", fildes, newfildes);
|
|
return add_to_file_actions(file_actions, temp);
|
|
}
|
|
<br>
|
|
/* Add an open action to object. */
|
|
int posix_spawn_file_actions_addopen(
|
|
posix_spawn_file_actions_t *file_actions, int fildes,
|
|
const char *path, int oflag, mode_t mode)
|
|
{
|
|
char temp[100];
|
|
<br>
|
|
sprintf(temp, "open(%d,%s*%o,%o)", fildes, path, oflag, mode);
|
|
return add_to_file_actions(file_actions, temp);
|
|
}
|
|
<br>
|
|
/*******************************************************/
|
|
/* Here is a crude but effective implementation of the */
|
|
/* spawn attributes object functions which manipulate */
|
|
/* the individual attributes. */
|
|
/*******************************************************/
|
|
/* Initialize object with default values. */
|
|
int posix_spawnattr_init(posix_spawnattr_t *attr)
|
|
{
|
|
attr->posix_attr_flags = 0;
|
|
attr->posix_attr_pgroup = 0;
|
|
/* Default value of signal mask is the parent's signal mask; */
|
|
/* other values are also allowed */
|
|
sigprocmask(0, NULL, &attr->posix_attr_sigmask);
|
|
sigemptyset(&attr->posix_attr_sigdefault);
|
|
/* Default values of scheduling attr inherited from the parent; */
|
|
/* other values are also allowed */
|
|
attr->posix_attr_schedpolicy = sched_getscheduler(0);
|
|
sched_getparam(0, &attr->posix_attr_schedparam);
|
|
return 0;
|
|
}
|
|
<br>
|
|
int posix_spawnattr_destroy(posix_spawnattr_t *attr)
|
|
{
|
|
/* No action needed */
|
|
return 0;
|
|
}
|
|
<br>
|
|
int posix_spawnattr_getflags(const posix_spawnattr_t *attr,
|
|
short *flags)
|
|
{
|
|
*flags = attr->posix_attr_flags;
|
|
return 0;
|
|
}
|
|
<br>
|
|
int posix_spawnattr_setflags(posix_spawnattr_t *attr, short flags)
|
|
{
|
|
attr->posix_attr_flags = flags;
|
|
return 0;
|
|
}
|
|
<br>
|
|
int posix_spawnattr_getpgroup(const posix_spawnattr_t *attr,
|
|
pid_t *pgroup)
|
|
{
|
|
*pgroup = attr->posix_attr_pgroup;
|
|
return 0;
|
|
}
|
|
<br>
|
|
int posix_spawnattr_setpgroup(posix_spawnattr_t *attr, pid_t pgroup)
|
|
{
|
|
attr->posix_attr_pgroup = pgroup;
|
|
return 0;
|
|
}
|
|
<br>
|
|
int posix_spawnattr_getschedpolicy(const posix_spawnattr_t *attr,
|
|
int *schedpolicy)
|
|
{
|
|
*schedpolicy = attr->posix_attr_schedpolicy;
|
|
return 0;
|
|
}
|
|
<br>
|
|
int posix_spawnattr_setschedpolicy(posix_spawnattr_t *attr,
|
|
int schedpolicy)
|
|
{
|
|
attr->posix_attr_schedpolicy = schedpolicy;
|
|
return 0;
|
|
}
|
|
<br>
|
|
int posix_spawnattr_getschedparam(const posix_spawnattr_t *attr,
|
|
struct sched_param *schedparam)
|
|
{
|
|
*schedparam = attr->posix_attr_schedparam;
|
|
return 0;
|
|
}
|
|
<br>
|
|
int posix_spawnattr_setschedparam(posix_spawnattr_t *attr,
|
|
const struct sched_param *schedparam)
|
|
{
|
|
attr->posix_attr_schedparam = *schedparam;
|
|
return 0;
|
|
}
|
|
<br>
|
|
int posix_spawnattr_getsigmask(const posix_spawnattr_t *attr,
|
|
sigset_t *sigmask)
|
|
{
|
|
*sigmask = attr->posix_attr_sigmask;
|
|
return 0;
|
|
}
|
|
<br>
|
|
int posix_spawnattr_setsigmask(posix_spawnattr_t *attr,
|
|
const sigset_t *sigmask)
|
|
{
|
|
attr->posix_attr_sigmask = *sigmask;
|
|
return 0;
|
|
}
|
|
<br>
|
|
int posix_spawnattr_getsigdefault(const posix_spawnattr_t *attr,
|
|
sigset_t *sigdefault)
|
|
{
|
|
*sigdefault = attr->posix_attr_sigdefault;
|
|
return 0;
|
|
}
|
|
<br>
|
|
int posix_spawnattr_setsigdefault(posix_spawnattr_t *attr,
|
|
const sigset_t *sigdefault)
|
|
{
|
|
attr->posix_attr_sigdefault = *sigdefault;
|
|
return 0;
|
|
}
|
|
</tt>
|
|
</pre>
|
|
|
|
<h5><a name="tag_03_03_01_02"></a>I/O Redirection with Spawn</h5>
|
|
|
|
<p>I/O redirection with <a href="../functions/posix_spawn.html"><i>posix_spawn</i>()</a> or <a href=
|
|
"../functions/posix_spawnp.html"><i>posix_spawnp</i>()</a> is accomplished by crafting a <i>file_actions</i> argument to effect the
|
|
desired redirection. Such a redirection follows the general outline of the following example:</p>
|
|
|
|
<pre>
|
|
<tt>/* To redirect new standard output (fd 1) to a file, */
|
|
/* and redirect new standard input (fd 0) from my fd socket_pair[1], */
|
|
/* and close my fd socket_pair[0] in the new process. */
|
|
posix_spawn_file_actions_t file_actions;
|
|
posix_spawn_file_actions_init(&file_actions);
|
|
posix_spawn_file_actions_addopen(&file_actions, 1, "newout", ...);
|
|
posix_spawn_file_actions_dup2(&file_actions, socket_pair[1], 0);
|
|
posix_spawn_file_actions_close(&file_actions, socket_pair[0]);
|
|
posix_spawn_file_actions_close(&file_actions, socket_pair[1]);
|
|
posix_spawn(..., &file_actions, ...);
|
|
posix_spawn_file_actions_destroy(&file_actions);
|
|
</tt>
|
|
</pre>
|
|
|
|
<h5><a name="tag_03_03_01_03"></a>Spawning a Process Under a New User ID</h5>
|
|
|
|
<p>Spawning a process under a new user ID follows the outline shown in the following example:</p>
|
|
|
|
<pre>
|
|
<tt>Save = getuid();
|
|
setuid(newid);
|
|
posix_spawn(...);
|
|
setuid(Save);
|
|
</tt>
|
|
</pre>
|
|
|
|
|
|
<hr size="2" noshade>
|
|
<center><font size="2"><!--footer start-->
|
|
UNIX ® is a registered Trademark of The Open Group.<br>
|
|
POSIX ® is a registered Trademark of The IEEE.<br>
|
|
[ <a href="../mindex.html">Main Index</a> | <a href="../basedefs/contents.html">XBD</a> | <a href=
|
|
"../utilities/contents.html">XCU</a> | <a href="../functions/contents.html">XSH</a> | <a href="../xrat/contents.html">XRAT</a>
|
|
]</font></center>
|
|
|
|
<!--footer end-->
|
|
<hr size="2" noshade>
|
|
</body>
|
|
</html>
|
|
|