/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
#include "lint.h"
#include "thr_uberdata.h"
#include <sys/libc_kernel.h>
#include <dirent.h>
#include <alloca.h>
#include <spawn.h>
#define ALL_POSIX_SPAWN_FLAGS \
(POSIX_SPAWN_RESETIDS | \
typedef struct {
int sa_priority;
int sa_schedpolicy;
} spawn_attr_t;
typedef struct file_attr {
} file_attr_t;
#if defined(_LP64)
#else
#endif
/*
* Support function:
* Close all open file descriptors greater than or equal to lowfd.
* This is executed in the child of vfork(), so we must not call
* opendir() / readdir() because that would alter the parent's
* address space. We use the low-level getdents64() system call.
* Return non-zero on error.
*/
static int
{
int procfd;
int fd;
int buflen;
if (lowfd < 0)
lowfd = 0;
/*
* Close lowfd right away as a hedge against failing
* to open the /proc file descriptor directory due
* all file descriptors being currently used up.
*/
/*
* We could not open the /proc file descriptor directory.
* Just fail and be done with it.
*/
return (-1);
}
for (;;) {
/*
* Collect a bunch of open file descriptors and close them.
* Repeat until the directory is exhausted.
*/
break;
}
do {
/* skip '.', '..' and procfd */
}
return (0);
}
static int
{
int sig;
}
}
}
}
}
return (errno);
}
return (errno);
}
return (errno);
return (errno);
}
return (0);
}
static int
{
int fd;
do {
case FA_OPEN:
if (fd < 0)
return (errno);
return (errno);
}
break;
case FA_CLOSE:
return (errno);
break;
case FA_DUP2:
fap->fa_newfiledes);
if (fd < 0)
return (errno);
break;
case FA_CLOSEFROM:
return (errno);
break;
}
return (0);
}
static int
{
int flags = 0;
flags |= FORK_NOSIGCHLD;
flags |= FORK_WAITPID;
}
return (flags);
}
/*
* set_error() / get_error() are used to guarantee that the local variable
* 'error' is set correctly in memory on return from vfork() in the parent.
*/
static int
{
}
static int
{
return (*errp);
}
/*
* For MT safety, do not invoke the dynamic linker after calling vfork().
* If some other thread was in the dynamic linker when this thread's parent
* called vfork() then the dynamic linker's lock would still be held here
* (with a defunct owner) and we would deadlock ourself if we invoked it.
*
* Therefore, all of the functions we call here after returning from
* vforkx() in the child are not and must never be exported from libc
* as global symbols. To do so would risk invoking the dynamic linker.
*/
int
const char *path,
const posix_spawnattr_t *attrp,
char *const argv[],
char *const envp[])
{
return (EINVAL);
/*
* Preallocate the buffer for the call to getdents64() in
* spawn_closefrom() since we can't do it in the vfork() child.
*/
return (ENOMEM);
}
case 0: /* child */
break;
case -1: /* parent, failure */
if (dirbuf)
return (errno);
default: /* parent, success */
/*
* We don't get here until the child exec()s or exit()s
*/
if (dirbuf)
}
_exit(127);
/* NOTREACHED */
return (0);
}
/*
*/
extern int libc__xpg4;
static const char *
{
char *s;
char c;
if (cnt > 0) {
*s++ = c;
cnt--;
}
}
*s++ = '/';
cnt--;
}
*s++ = c;
cnt--;
}
*s = '\0';
}
/* ARGSUSED */
int
const char *file,
const posix_spawnattr_t *attrp,
char *const argv[],
char *const envp[])
{
const char *cp;
char **newargs;
int argc;
int i;
return (EINVAL);
if (*file == '\0')
return (EACCES);
/*
* Preallocate the buffer for the call to getdents64() in
* spawn_closefrom() since we can't do it in the vfork() child.
*/
return (ENOMEM);
}
/*
* We may need to invoke the shell with a slightly modified
* argv[] array. To do this we need to preallocate the array.
* We must call alloca() before calling vfork() because doing
* it after vfork() (in the child) would corrupt the parent.
*/
continue;
case 0: /* child */
break;
case -1: /* parent, failure */
if (dirbuf)
return (errno);
default: /* parent, success */
/*
* We don't get here until the child exec()s or exit()s
*/
if (dirbuf)
}
/*
* XPG4: pathstr is equivalent to _CS_PATH, except that
* with a colon when not root. Keep these paths in sync
* with _CS_PATH in confstr.c. Note that pathstr must end
* with a colon when not root so that when file doesn't
* contain '/', the last call to execat() will result in an
* attempt to execv file from the current directory.
*/
if (!xpg4)
else
} else {
if (!xpg4)
else
}
}
do {
/*
* 4025035 and 4038378
* if a filename begins with a "-" prepend "./" so that
* the shell can't interpret it as an option
*/
if (*path == '-') {
char *s;
for (s = path; *s != '\0'; s++)
continue;
for (; s >= path; s--)
*(s + 2) = *s;
path[0] = '.';
}
for (i = 1; i <= argc; i++)
_exit(127);
}
} while (cp);
_exit(127);
}
/* NOTREACHED */
return (0);
}
int
{
return (0);
}
int
{
do {
}
return (0);
}
static void
{
} else {
}
/*
* Once set, __file_attrp no longer changes, so this assignment
* always goes into the first element in the list, as required.
*/
}
int
int filedes,
const char *path,
int oflag,
{
if (filedes < 0)
return (EBADF);
return (ENOMEM);
return (ENOMEM);
}
return (0);
}
int
int filedes)
{
if (filedes < 0)
return (EBADF);
return (ENOMEM);
return (0);
}
int
int filedes,
int newfiledes)
{
if (filedes < 0 || newfiledes < 0)
return (EBADF);
return (ENOMEM);
return (0);
}
int
int lowfiledes)
{
if (lowfiledes < 0)
return (EBADF);
return (ENOMEM);
return (0);
}
int
{
return (ENOMEM);
/*
* Add default stuff here?
*/
return (0);
}
int
{
return (EINVAL);
/*
* deallocate stuff here?
*/
return (0);
}
int
short flags)
{
(flags & ~ALL_POSIX_SPAWN_FLAGS))
return (EINVAL);
return (0);
}
int
const posix_spawnattr_t *attr,
short *flags)
{
return (EINVAL);
return (0);
}
int
{
return (EINVAL);
return (0);
}
int
const posix_spawnattr_t *attr,
{
return (EINVAL);
return (0);
}
int
const struct sched_param *schedparam)
{
return (EINVAL);
/*
* Check validity?
*/
return (0);
}
int
const posix_spawnattr_t *attr,
struct sched_param *schedparam)
{
return (EINVAL);
return (0);
}
int
int schedpolicy)
{
return (EINVAL);
/*
* Cache the policy information for later use
* by the vfork() child of posix_spawn().
*/
return (errno);
return (0);
}
int
const posix_spawnattr_t *attr,
int *schedpolicy)
{
return (EINVAL);
return (0);
}
int
const sigset_t *sigdefault)
{
return (EINVAL);
return (0);
}
int
const posix_spawnattr_t *attr,
{
return (EINVAL);
return (0);
}
int
{
return (EINVAL);
return (0);
}
int
const posix_spawnattr_t *attr,
{
return (EINVAL);
return (0);
}
int
{
return (EINVAL);
return (0);
}
int
const posix_spawnattr_t *attr,
{
return (EINVAL);
return (0);
}