Files
oldlinux-files/Ref-docs/POSIX/susv3/xrat/xsh_chap03.html
2024-02-19 00:21:47 -05:00

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 &copy; 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&nbsp;Std&nbsp;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 &lt;sys/types.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;unistd.h&gt;
#include &lt;sched.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;signal.h&gt;
#include &lt;errno.h&gt;
#include &lt;string.h&gt;
#include &lt;signal.h&gt;
<br>
/* #include &lt;spawn.h&gt; */
/*******************************************/
/* 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-&gt;posix_attr_flags &amp; POSIX_SPAWN_SETPGROUP)
{
/* Override inherited process group */
if (setpgid(0, attrp-&gt;posix_attr_pgroup) != 0)
{
/* Failed */
exit(127);
}
}
<br>
/* Worry about process signal mask */
if (attrp-&gt;posix_attr_flags &amp; POSIX_SPAWN_SETSIGMASK)
{
/* Set the signal mask (can't fail) */
sigprocmask(SIG_SETMASK, &amp;attrp-&gt;posix_attr_sigmask, NULL);
}
<br>
/* Worry about resetting effective user and group IDs */
if (attrp-&gt;posix_attr_flags &amp; POSIX_SPAWN_RESETIDS)
{
/* None of these can fail for this case. */
setuid(getuid());
setgid(getgid());
}
<br>
/* Worry about defaulted signals */
if (attrp-&gt;posix_attr_flags &amp; 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(&amp;all_signals);
<br>
/* Loop for all signals */
for (s = 0; sigismember(&amp;all_signals, s); s++)
{
/* Signal to be defaulted? */
if (sigismember(&amp;attrp-&gt;posix_attr_sigdefault, s))
{
/* Yes; default this signal */
if (sigaction(s, &amp;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)", &amp;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)", &amp;fd, &amp;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,", &amp;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)", &amp;oflag, &amp;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-&gt;posix_attr_flags &amp; POSIX_SPAWN_SETSCHEDULER)
{
if (sched_setscheduler(0, attrp-&gt;posix_attr_schedpolicy,
&amp;attrp-&gt;posix_attr_schedparam) == -1)
{
exit(127);
}
}
<br>
/* Worry about setting only new scheduling parameters */
if (attrp-&gt;posix_attr_flags &amp; POSIX_SPAWN_SETSCHEDPARAM)
{
if (sched_setparam(0, &amp;attrp-&gt;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-&gt;posix_attr_flags = 0;
attr-&gt;posix_attr_pgroup = 0;
/* Default value of signal mask is the parent's signal mask; */
/* other values are also allowed */
sigprocmask(0, NULL, &amp;attr-&gt;posix_attr_sigmask);
sigemptyset(&amp;attr-&gt;posix_attr_sigdefault);
/* Default values of scheduling attr inherited from the parent; */
/* other values are also allowed */
attr-&gt;posix_attr_schedpolicy = sched_getscheduler(0);
sched_getparam(0, &amp;attr-&gt;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-&gt;posix_attr_flags;
return 0;
}
<br>
int posix_spawnattr_setflags(posix_spawnattr_t *attr, short flags)
{
attr-&gt;posix_attr_flags = flags;
return 0;
}
<br>
int posix_spawnattr_getpgroup(const posix_spawnattr_t *attr,
pid_t *pgroup)
{
*pgroup = attr-&gt;posix_attr_pgroup;
return 0;
}
<br>
int posix_spawnattr_setpgroup(posix_spawnattr_t *attr, pid_t pgroup)
{
attr-&gt;posix_attr_pgroup = pgroup;
return 0;
}
<br>
int posix_spawnattr_getschedpolicy(const posix_spawnattr_t *attr,
int *schedpolicy)
{
*schedpolicy = attr-&gt;posix_attr_schedpolicy;
return 0;
}
<br>
int posix_spawnattr_setschedpolicy(posix_spawnattr_t *attr,
int schedpolicy)
{
attr-&gt;posix_attr_schedpolicy = schedpolicy;
return 0;
}
<br>
int posix_spawnattr_getschedparam(const posix_spawnattr_t *attr,
struct sched_param *schedparam)
{
*schedparam = attr-&gt;posix_attr_schedparam;
return 0;
}
<br>
int posix_spawnattr_setschedparam(posix_spawnattr_t *attr,
const struct sched_param *schedparam)
{
attr-&gt;posix_attr_schedparam = *schedparam;
return 0;
}
<br>
int posix_spawnattr_getsigmask(const posix_spawnattr_t *attr,
sigset_t *sigmask)
{
*sigmask = attr-&gt;posix_attr_sigmask;
return 0;
}
<br>
int posix_spawnattr_setsigmask(posix_spawnattr_t *attr,
const sigset_t *sigmask)
{
attr-&gt;posix_attr_sigmask = *sigmask;
return 0;
}
<br>
int posix_spawnattr_getsigdefault(const posix_spawnattr_t *attr,
sigset_t *sigdefault)
{
*sigdefault = attr-&gt;posix_attr_sigdefault;
return 0;
}
<br>
int posix_spawnattr_setsigdefault(posix_spawnattr_t *attr,
const sigset_t *sigdefault)
{
attr-&gt;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(&amp;file_actions);
posix_spawn_file_actions_addopen(&amp;file_actions, 1, "newout", ...);
posix_spawn_file_actions_dup2(&amp;file_actions, socket_pair[1], 0);
posix_spawn_file_actions_close(&amp;file_actions, socket_pair[0]);
posix_spawn_file_actions_close(&amp;file_actions, socket_pair[1]);
posix_spawn(..., &amp;file_actions, ...);
posix_spawn_file_actions_destroy(&amp;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 &reg; is a registered Trademark of The Open Group.<br>
POSIX &reg; 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>