libc: add posix_spawn family of functions
The implementation is taken from newlib (BSD licensed) and test84 is based on NetBSD's t_spawn.c Change-Id: Ia4e9dd5204a0b4ef241a451978057e11fb29e3d6
This commit is contained in:
parent
7b2da7b2c7
commit
1facb0487c
10 changed files with 773 additions and 6 deletions
|
@ -6219,6 +6219,9 @@
|
|||
./usr/tests/minix-posix/t67b minix-sys
|
||||
./usr/tests/minix-posix/t68a minix-sys
|
||||
./usr/tests/minix-posix/t68b minix-sys
|
||||
./usr/tests/minix-posix/t84_h_nonexec.sh minix-sys
|
||||
./usr/tests/minix-posix/t84_h_spawn minix-sys
|
||||
./usr/tests/minix-posix/t84_h_spawnattr minix-sys
|
||||
./usr/tests/minix-posix/test10 minix-sys
|
||||
./usr/tests/minix-posix/test1 minix-sys
|
||||
./usr/tests/minix-posix/test11 minix-sys
|
||||
|
@ -6293,11 +6296,12 @@
|
|||
./usr/tests/minix-posix/test77 minix-sys
|
||||
./usr/tests/minix-posix/test78 minix-sys
|
||||
./usr/tests/minix-posix/test79 minix-sys
|
||||
./usr/tests/minix-posix/test8 minix-sys
|
||||
./usr/tests/minix-posix/test80 minix-sys
|
||||
./usr/tests/minix-posix/test8 minix-sys
|
||||
./usr/tests/minix-posix/test81 minix-sys
|
||||
./usr/tests/minix-posix/test82 minix-sys
|
||||
./usr/tests/minix-posix/test83 minix-sys
|
||||
./usr/tests/minix-posix/test84 minix-sys
|
||||
./usr/tests/minix-posix/test9 minix-sys
|
||||
./usr/tests/minix-posix/testinterp minix-sys
|
||||
./usr/tests/minix-posix/testisofs minix-sys
|
||||
|
|
|
@ -42,7 +42,8 @@ SRCS+= _errno.c alarm.c alphasort.c arc4random.c assert.c basename.c clock.c \
|
|||
getusershell.c glob.c humanize_number.c initdir.c initgroups.c \
|
||||
isascii.c isatty.c isctype.c lockf.c nftw.c \
|
||||
nice.c \
|
||||
opendir.c pause.c popen.c \
|
||||
opendir.c pause.c popen.c posix_spawn_sched.c \
|
||||
posix_spawn_fileactions.c posix_spawnp.c \
|
||||
psignal.c \
|
||||
ptree.c pwcache.c pw_scan.c raise.c randomid.c rb.c readdir.c \
|
||||
rewinddir.c scandir.c seekdir.c \
|
||||
|
|
|
@ -12,7 +12,7 @@ SRCS+= accept.c access.c adjtime.c bind.c brk.c sbrk.c m_closefrom.c getsid.c \
|
|||
getvfsstat.c \
|
||||
ioctl.c issetugid.c kill.c link.c listen.c loadname.c lseek.c \
|
||||
minix_rs.c mkdir.c mkfifo.c mknod.c mmap.c mount.c nanosleep.c \
|
||||
open.c pathconf.c pipe.c poll.c pread.c ptrace.c pwrite.c \
|
||||
open.c pathconf.c pipe.c poll.c posix_spawn.c pread.c ptrace.c pwrite.c \
|
||||
read.c readlink.c reboot.c recvfrom.c recvmsg.c rename.c \
|
||||
rmdir.c select.c sem.c sendmsg.c sendto.c setgroups.c setsid.c \
|
||||
setgid.c settimeofday.c setuid.c shmat.c shmctl.c shmget.c stime.c \
|
||||
|
|
277
minix/lib/libc/sys/posix_spawn.c
Normal file
277
minix/lib/libc/sys/posix_spawn.c
Normal file
|
@ -0,0 +1,277 @@
|
|||
/*
|
||||
* Taken from newlib/libc/posix/posix_spawn.c
|
||||
*/
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/queue.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sched.h>
|
||||
#include <spawn.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
extern char **environ;
|
||||
|
||||
/* Only deal with a pointer to environ, to work around subtle bugs with shared
|
||||
libraries and/or small data systems where the user declares his own
|
||||
'environ'. */
|
||||
static char ***p_environ = &environ;
|
||||
|
||||
/*
|
||||
* Spawn routines
|
||||
*/
|
||||
|
||||
static int
|
||||
process_spawnattr(const posix_spawnattr_t * sa)
|
||||
{
|
||||
struct sigaction sigact = { .sa_flags = 0, .sa_handler = SIG_DFL };
|
||||
int i;
|
||||
|
||||
/*
|
||||
* POSIX doesn't really describe in which order everything
|
||||
* should be set. We'll just set them in the order in which they
|
||||
* are mentioned.
|
||||
*/
|
||||
|
||||
/* Set process group */
|
||||
if (sa->sa_flags & POSIX_SPAWN_SETPGROUP) {
|
||||
if (setpgid(0, sa->sa_pgroup) != 0)
|
||||
return errno;
|
||||
}
|
||||
|
||||
/* Set scheduler policy */
|
||||
/* XXX: We don't have scheduler policy for now */
|
||||
#if 0
|
||||
if (sa->sa_flags & POSIX_SPAWN_SETSCHEDULER) {
|
||||
if (sched_setscheduler(0, sa->sa_schedpolicy,
|
||||
&sa->sa_schedparam) != 0)
|
||||
return errno;
|
||||
} else if (sa->sa_flags & POSIX_SPAWN_SETSCHEDPARAM) {
|
||||
if (sched_setparam(0, &sa->sa_schedparam) != 0)
|
||||
return errno;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Reset user ID's */
|
||||
if (sa->sa_flags & POSIX_SPAWN_RESETIDS) {
|
||||
if (setegid(getgid()) != 0)
|
||||
return errno;
|
||||
if (seteuid(getuid()) != 0)
|
||||
return errno;
|
||||
}
|
||||
|
||||
/* Set signal masks/defaults */
|
||||
if (sa->sa_flags & POSIX_SPAWN_SETSIGMASK) {
|
||||
sigprocmask(SIG_SETMASK, &sa->sa_sigmask, NULL);
|
||||
}
|
||||
|
||||
if (sa->sa_flags & POSIX_SPAWN_SETSIGDEF) {
|
||||
for (i = 1; i < NSIG; i++) {
|
||||
if (sigismember(&sa->sa_sigdefault, i))
|
||||
if (sigaction(i, &sigact, NULL) != 0)
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
move_fd_up(int * statusfd)
|
||||
{
|
||||
/*
|
||||
* Move given file descriptor on a higher fd number.
|
||||
*
|
||||
* This is used to hide the status file descriptor from the application
|
||||
* by pushing it out of the way if it tries to use its number.
|
||||
*/
|
||||
int newstatusfd;
|
||||
|
||||
newstatusfd = fcntl(*statusfd, F_DUPFD, *statusfd+1);
|
||||
if (newstatusfd == -1)
|
||||
return -1;
|
||||
|
||||
close(*statusfd);
|
||||
*statusfd = newstatusfd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
process_file_actions_entry(posix_spawn_file_actions_entry_t * fae,
|
||||
int * statusfd)
|
||||
{
|
||||
int fd;
|
||||
|
||||
switch (fae->fae_action) {
|
||||
case FAE_OPEN:
|
||||
/* Perform an open(), make it use the right fd */
|
||||
fd = open(fae->fae_path, fae->fae_oflag, fae->fae_mode);
|
||||
if (fd < 0)
|
||||
return errno;
|
||||
if (fd != fae->fae_fildes) {
|
||||
if (fae->fae_fildes == *statusfd) {
|
||||
/* Move the status fd out of the way */
|
||||
if (move_fd_up(statusfd) == -1)
|
||||
return errno;
|
||||
}
|
||||
if (dup2(fd, fae->fae_fildes) == -1)
|
||||
return errno;
|
||||
if (close(fd) != 0) {
|
||||
if (errno == EBADF)
|
||||
return EBADF;
|
||||
}
|
||||
}
|
||||
if (fcntl(fae->fae_fildes, F_SETFD, 0) == -1)
|
||||
return errno;
|
||||
break;
|
||||
|
||||
case FAE_DUP2:
|
||||
if (fae->fae_fildes == *statusfd) {
|
||||
/* Nice try */
|
||||
return EBADF;
|
||||
}
|
||||
if (fae->fae_newfildes == *statusfd) {
|
||||
/* Move the status file descriptor out of the way */
|
||||
if (move_fd_up(statusfd) == -1)
|
||||
return errno;
|
||||
}
|
||||
/* Perform a dup2() */
|
||||
if (dup2(fae->fae_fildes, fae->fae_newfildes) == -1)
|
||||
return errno;
|
||||
if (fcntl(fae->fae_newfildes, F_SETFD, 0) == -1)
|
||||
return errno;
|
||||
break;
|
||||
|
||||
case FAE_CLOSE:
|
||||
/* Perform a close(), do not fail if already closed */
|
||||
if (fae->fae_fildes != *statusfd)
|
||||
(void)close(fae->fae_fildes);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
process_file_actions(const posix_spawn_file_actions_t * fa, int * statusfd)
|
||||
{
|
||||
posix_spawn_file_actions_entry_t *fae;
|
||||
int error;
|
||||
|
||||
/* Replay all file descriptor modifications */
|
||||
for (unsigned i = 0; i < fa->len; i++) {
|
||||
fae = &fa->fae[i];
|
||||
error = process_file_actions_entry(fae, statusfd);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
posix_spawn(pid_t * __restrict pid, const char * __restrict path,
|
||||
const posix_spawn_file_actions_t * fa,
|
||||
const posix_spawnattr_t * __restrict sa,
|
||||
char * const * __restrict argv, char * const * __restrict envp)
|
||||
{
|
||||
pid_t p;
|
||||
int r, error, pfd[2];
|
||||
|
||||
/*
|
||||
* Due to the lack of vfork() in Minix, an alternative solution with
|
||||
* pipes is used. The writing end is set to close on exec() and the
|
||||
* parent performs a read() on it.
|
||||
*
|
||||
* On success, a successful 0-length read happens.
|
||||
* On failure, the child writes the errno to the pipe before exiting,
|
||||
* the error is thus transmitted to the parent.
|
||||
*
|
||||
* This solution was taken from stackoverflow.com question 3703013.
|
||||
*/
|
||||
if (pipe(pfd) == -1)
|
||||
return errno;
|
||||
|
||||
p = fork();
|
||||
switch (p) {
|
||||
case -1:
|
||||
close(pfd[0]);
|
||||
close(pfd[1]);
|
||||
|
||||
return errno;
|
||||
|
||||
case 0:
|
||||
close(pfd[0]);
|
||||
|
||||
if (fcntl(pfd[1], F_SETFD, FD_CLOEXEC) != 0) {
|
||||
error = errno;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sa != NULL) {
|
||||
error = process_spawnattr(sa);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
if (fa != NULL) {
|
||||
error = process_file_actions(fa, &pfd[1]);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
|
||||
(void)execve(path, argv, envp != NULL ? envp : *p_environ);
|
||||
|
||||
error = errno;
|
||||
break;
|
||||
|
||||
default:
|
||||
close(pfd[1]);
|
||||
|
||||
/* Retrieve child process status through pipe. */
|
||||
r = read(pfd[0], &error, sizeof(error));
|
||||
if (r == 0)
|
||||
error = 0;
|
||||
else if (r == -1)
|
||||
error = errno;
|
||||
close(pfd[0]);
|
||||
|
||||
if (pid != NULL)
|
||||
*pid = p;
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Child failed somewhere, propagate error through pipe and exit. */
|
||||
write(pfd[1], &error, sizeof(error));
|
||||
close(pfd[1]);
|
||||
_exit(127);
|
||||
}
|
|
@ -59,7 +59,9 @@ MINIX_TESTS= \
|
|||
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
|
||||
41 42 43 44 45 46 48 49 50 52 53 54 55 56 58 59 60 \
|
||||
61 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 \
|
||||
81 82 83
|
||||
81 82 83 84
|
||||
|
||||
FILES += t84_h_nonexec.sh
|
||||
|
||||
.if ${MACHINE_ARCH} == "i386"
|
||||
MINIX_TESTS+= \
|
||||
|
@ -72,7 +74,7 @@ PROGS+= test${t}
|
|||
.endfor
|
||||
|
||||
PROGS+= t10a t11a t11b t40a t40b t40c t40d t40e t40f t40g t60a t60b \
|
||||
t67a t67b t68a t68b tvnd
|
||||
t67a t67b t68a t68b tvnd t84_h_spawn t84_h_spawnattr
|
||||
|
||||
SCRIPTS+= run check-install testinterp.sh testsh1.sh testsh2.sh testmfs.sh \
|
||||
testisofs.sh testvnd.sh testkyua.sh testrelpol.sh
|
||||
|
|
|
@ -30,7 +30,7 @@ alltests="1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
|
|||
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
|
||||
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
|
||||
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 \
|
||||
81 82 83 sh1 sh2 interp mfs isofs vnd"
|
||||
81 82 83 84 sh1 sh2 interp mfs isofs vnd"
|
||||
tests_no=`expr 0`
|
||||
|
||||
# If root, make sure the setuid tests have the correct permissions
|
||||
|
|
3
minix/tests/t84_h_nonexec.sh
Normal file
3
minix/tests/t84_h_nonexec.sh
Normal file
|
@ -0,0 +1,3 @@
|
|||
#! /nonexistent
|
||||
|
||||
# this is just a dummy script, trying to be non-executable
|
51
minix/tests/t84_h_spawn.c
Normal file
51
minix/tests/t84_h_spawn.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
/* $NetBSD: h_spawn.c,v 1.1 2012/02/13 21:03:08 martin Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2012 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Charles Zhang <charles@NetBSD.org> and
|
||||
* Martin Husemann <martin@NetBSD.org>.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
unsigned long ret;
|
||||
char *endp;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "usage:\n\t%s (retcode)\n", getprogname());
|
||||
exit(255);
|
||||
}
|
||||
ret = strtoul(argv[1], &endp, 10);
|
||||
#if DEBUG
|
||||
fprintf(stderr, "%s exiting with status %lu\n", getprogname(), ret);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
94
minix/tests/t84_h_spawnattr.c
Normal file
94
minix/tests/t84_h_spawnattr.c
Normal file
|
@ -0,0 +1,94 @@
|
|||
/* $NetBSD: h_spawnattr.c,v 1.1 2012/02/13 21:03:08 martin Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2012 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Charles Zhang <charles@NetBSD.org> and
|
||||
* Martin Husemann <martin@NetBSD.org>.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*
|
||||
* Helper to test the hardcoded assumptions from t_spawnattr.c
|
||||
* Exit with apropriate exit status and print diagnostics to
|
||||
* stderr explaining what is wrong.
|
||||
*/
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int parent_pipe, res = EXIT_SUCCESS;
|
||||
sigset_t sig;
|
||||
struct sigaction act;
|
||||
ssize_t rd;
|
||||
char tmp;
|
||||
|
||||
sigemptyset(&sig);
|
||||
if (sigprocmask(0, NULL, &sig) < 0) {
|
||||
fprintf(stderr, "%s: sigprocmask error\n", getprogname());
|
||||
res = EXIT_FAILURE;
|
||||
}
|
||||
if (!sigismember(&sig, SIGUSR1)) {
|
||||
fprintf(stderr, "%s: SIGUSR not in procmask\n", getprogname());
|
||||
res = EXIT_FAILURE;
|
||||
}
|
||||
if (sigaction(SIGUSR1, NULL, &act) < 0) {
|
||||
fprintf(stderr, "%s: sigaction error\n", getprogname());
|
||||
res = EXIT_FAILURE;
|
||||
}
|
||||
if (act.sa_sigaction != (void *)SIG_DFL) {
|
||||
fprintf(stderr, "%s: SIGUSR1 action != SIG_DFL\n",
|
||||
getprogname());
|
||||
res = EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (argc >= 2) {
|
||||
parent_pipe = atoi(argv[1]);
|
||||
if (parent_pipe > 2) {
|
||||
#if DEBUG
|
||||
printf("%s: waiting for command from parent on pipe "
|
||||
"%d\n", getprogname(), parent_pipe);
|
||||
#endif
|
||||
rd = read(parent_pipe, &tmp, 1);
|
||||
if (rd == 1) {
|
||||
#if DEBUG
|
||||
printf("%s: got command %c from parent\n",
|
||||
getprogname(), tmp);
|
||||
#endif
|
||||
} else if (rd == -1) {
|
||||
printf("%s: %d is no pipe, errno %d\n",
|
||||
getprogname(), parent_pipe, errno);
|
||||
res = EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
335
minix/tests/test84.c
Normal file
335
minix/tests/test84.c
Normal file
|
@ -0,0 +1,335 @@
|
|||
/*
|
||||
* Based off tests/lib/libc/gen/posix_spawn/t_spawn.c
|
||||
*/
|
||||
|
||||
/* $NetBSD: t_spawn.c,v 1.1 2012/02/13 21:03:08 martin Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2012 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Charles Zhang <charles@NetBSD.org> and
|
||||
* Martin Husemann <martin@NetBSD.org>.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <spawn.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/* reroute stdout to /dev/null while returning another fd for the old stdout */
|
||||
/* this is just for aesthetics: we don't want to see the output of 'ls' */
|
||||
static int
|
||||
sink_stdout(void)
|
||||
{
|
||||
int fd, fd2;
|
||||
|
||||
if ((fd = fcntl(1, F_DUPFD, 3)) == -1 || close(1) == -1) {
|
||||
e(0);
|
||||
quit();
|
||||
}
|
||||
|
||||
if ((fd2 = open("/dev/null", O_WRONLY)) != 1) {
|
||||
if (fd2 == -1 || dup2(fd2, 1) != 1) {
|
||||
dup2(fd, 1);
|
||||
e(0);
|
||||
quit();
|
||||
}
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* restore stdout */
|
||||
static void
|
||||
restore_stdout(int fd)
|
||||
{
|
||||
|
||||
dup2(fd, 1);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/* tests a simple posix_spawn executing /bin/ls */
|
||||
static void
|
||||
test_posix_spawn_ls(void)
|
||||
{
|
||||
char * const args[] = { "ls", "-la", NULL };
|
||||
int err;
|
||||
|
||||
err = posix_spawn(NULL, "/bin/ls", NULL, NULL, args, NULL);
|
||||
if (err != 0)
|
||||
e(1);
|
||||
}
|
||||
|
||||
/* tests a simple posix_spawnp executing ls via $PATH */
|
||||
static void
|
||||
test_posix_spawnp_ls(void)
|
||||
{
|
||||
char * const args[] = { "ls", "-la", NULL };
|
||||
int err;
|
||||
|
||||
err = posix_spawnp(NULL, "ls", NULL, NULL, args, NULL);
|
||||
if(err != 0)
|
||||
e(2);
|
||||
}
|
||||
|
||||
/* posix_spawn a non existant binary */
|
||||
static void
|
||||
test_posix_spawn_missing(void)
|
||||
{
|
||||
char * const args[] = { "t84_h_nonexist", NULL };
|
||||
int err;
|
||||
|
||||
err = posix_spawn(NULL, "../t84_h_nonexist", NULL, NULL, args, NULL);
|
||||
if (err != ENOENT)
|
||||
e(4);
|
||||
}
|
||||
|
||||
/* posix_spawn a script with non existing interpreter */
|
||||
static void
|
||||
test_posix_spawn_nonexec(void)
|
||||
{
|
||||
char * const args[] = { "t84_h_nonexec", NULL };
|
||||
int err;
|
||||
|
||||
err = posix_spawn(NULL, "../t84_h_nonexec", NULL, NULL, args, NULL);
|
||||
if (err != ENOENT)
|
||||
e(5);
|
||||
}
|
||||
|
||||
/* posix_spawn a child and get it's return code */
|
||||
static void
|
||||
test_posix_spawn_child(void)
|
||||
{
|
||||
char * const args0[] = { "t84_h_spawn", "0", NULL };
|
||||
char * const args1[] = { "t84_h_spawn", "1", NULL };
|
||||
char * const args7[] = { "t84_h_spawn", "7", NULL };
|
||||
int err, status;
|
||||
pid_t pid;
|
||||
|
||||
err = posix_spawn(&pid, "../t84_h_spawn", NULL, NULL, args0, NULL);
|
||||
if (err != 0 || pid < 1)
|
||||
e(1);
|
||||
waitpid(pid, &status, 0);
|
||||
if (! (WIFEXITED(status) && WEXITSTATUS(status) == 0))
|
||||
e(2);
|
||||
|
||||
err = posix_spawn(&pid, "../t84_h_spawn", NULL, NULL, args1, NULL);
|
||||
if (err != 0 || pid < 1)
|
||||
e(3);
|
||||
waitpid(pid, &status, 0);
|
||||
if (! (WIFEXITED(status) && WEXITSTATUS(status) == 1))
|
||||
e(4);
|
||||
|
||||
err = posix_spawn(&pid, "../t84_h_spawn", NULL, NULL, args7, NULL);
|
||||
if (err != 0 || pid < 1)
|
||||
e(5);
|
||||
waitpid(pid, &status, 0);
|
||||
if (! (WIFEXITED(status) && WEXITSTATUS(status) == 7))
|
||||
e(6);
|
||||
}
|
||||
|
||||
/* test spawn attributes */
|
||||
static void
|
||||
test_posix_spawnattr(void)
|
||||
{
|
||||
int pid, status, err, pfd[2];
|
||||
char helper_arg[128];
|
||||
char * const args[] = { "t84_h_spawnattr", helper_arg, NULL };
|
||||
sigset_t sig;
|
||||
posix_spawnattr_t attr;
|
||||
|
||||
/*
|
||||
* create a pipe to controll the child
|
||||
*/
|
||||
err = pipe(pfd);
|
||||
if (err != 0)
|
||||
e(1);
|
||||
sprintf(helper_arg, "%d", pfd[0]);
|
||||
|
||||
posix_spawnattr_init(&attr);
|
||||
|
||||
sigemptyset(&sig);
|
||||
sigaddset(&sig, SIGUSR1);
|
||||
|
||||
posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSCHEDULER |
|
||||
POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETPGROUP |
|
||||
POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF |
|
||||
POSIX_SPAWN_SETSIGDEF);
|
||||
posix_spawnattr_setpgroup(&attr, 0);
|
||||
#if 0
|
||||
posix_spawnattr_setschedparam(&attr, &sp);
|
||||
posix_spawnattr_setschedpolicy(&attr, scheduler);
|
||||
#endif
|
||||
posix_spawnattr_setsigmask(&attr, &sig);
|
||||
posix_spawnattr_setsigdefault(&attr, &sig);
|
||||
|
||||
err = posix_spawn(&pid, "../t84_h_spawnattr", NULL, &attr, args, NULL);
|
||||
if (err != 0)
|
||||
e(2);
|
||||
|
||||
/* ready, let child go */
|
||||
write(pfd[1], "q", 1);
|
||||
close(pfd[0]);
|
||||
close(pfd[1]);
|
||||
|
||||
/* wait and check result from child */
|
||||
waitpid(pid, &status, 0);
|
||||
if (! (WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS))
|
||||
e(3);
|
||||
|
||||
posix_spawnattr_destroy(&attr);
|
||||
}
|
||||
|
||||
/* tests a simple posix_spawn executing /bin/ls with file actions */
|
||||
static void
|
||||
test_posix_spawn_file_actions(void)
|
||||
{
|
||||
char * const args[] = { "ls", "-la", NULL };
|
||||
int err;
|
||||
posix_spawn_file_actions_t file_actions;
|
||||
|
||||
/*
|
||||
* Just do a bunch of random operations which should leave console
|
||||
* output intact.
|
||||
*/
|
||||
posix_spawn_file_actions_init(&file_actions);
|
||||
posix_spawn_file_actions_adddup2(&file_actions, 1, 3);
|
||||
posix_spawn_file_actions_adddup2(&file_actions, 1, 4);
|
||||
posix_spawn_file_actions_adddup2(&file_actions, 1, 6);
|
||||
posix_spawn_file_actions_adddup2(&file_actions, 1, 5);
|
||||
posix_spawn_file_actions_addclose(&file_actions, 3);
|
||||
posix_spawn_file_actions_addclose(&file_actions, 4);
|
||||
posix_spawn_file_actions_addclose(&file_actions, 6);
|
||||
posix_spawn_file_actions_addclose(&file_actions, 5);
|
||||
|
||||
posix_spawn_file_actions_addclose(&file_actions, 0);
|
||||
posix_spawn_file_actions_addclose(&file_actions, 2);
|
||||
posix_spawn_file_actions_addopen(&file_actions, 0, "/dev/null",
|
||||
O_RDONLY, 0);
|
||||
posix_spawn_file_actions_adddup2(&file_actions, 1, 2);
|
||||
posix_spawn_file_actions_addclose(&file_actions, 1);
|
||||
posix_spawn_file_actions_adddup2(&file_actions, 2, 1);
|
||||
|
||||
err = posix_spawn(NULL, "/bin/ls", &file_actions, NULL, args, NULL);
|
||||
posix_spawn_file_actions_destroy(&file_actions);
|
||||
|
||||
if (err != 0)
|
||||
e(1);
|
||||
}
|
||||
|
||||
/* tests failures with file actions */
|
||||
static void
|
||||
test_posix_spawn_file_actions_failures(void)
|
||||
{
|
||||
char * const args[] = { "ls", "-la", NULL };
|
||||
int err, i;
|
||||
posix_spawn_file_actions_t file_actions;
|
||||
|
||||
/* Test bogus open */
|
||||
posix_spawn_file_actions_init(&file_actions);
|
||||
posix_spawn_file_actions_addclose(&file_actions, 0);
|
||||
posix_spawn_file_actions_addopen(&file_actions, 0, "t84_h_nonexist",
|
||||
O_RDONLY, 0);
|
||||
|
||||
err = posix_spawn(NULL, "/bin/ls", &file_actions, NULL, args, NULL);
|
||||
posix_spawn_file_actions_destroy(&file_actions);
|
||||
|
||||
if (err == 0)
|
||||
e(1);
|
||||
|
||||
/* Test bogus dup2 */
|
||||
for (i = 3; i < 10; i++) {
|
||||
posix_spawn_file_actions_init(&file_actions);
|
||||
posix_spawn_file_actions_adddup2(&file_actions, i, i+1);
|
||||
|
||||
err = posix_spawn(NULL, "/bin/ls", &file_actions, NULL, args,
|
||||
NULL);
|
||||
posix_spawn_file_actions_destroy(&file_actions);
|
||||
|
||||
if (err == 0)
|
||||
e(i-2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test bogus exec with dup2 (to mess with the pipe error reporting in
|
||||
* posix_spawn.c)
|
||||
*/
|
||||
posix_spawn_file_actions_init(&file_actions);
|
||||
posix_spawn_file_actions_adddup2(&file_actions, 1, 3);
|
||||
posix_spawn_file_actions_adddup2(&file_actions, 1, 4);
|
||||
posix_spawn_file_actions_adddup2(&file_actions, 1, 6);
|
||||
posix_spawn_file_actions_adddup2(&file_actions, 1, 5);
|
||||
posix_spawn_file_actions_adddup2(&file_actions, 1, 7);
|
||||
|
||||
err = posix_spawn(NULL, "t84_h_nonexist", &file_actions, NULL, args,
|
||||
NULL);
|
||||
posix_spawn_file_actions_destroy(&file_actions);
|
||||
|
||||
if (err == 0)
|
||||
e(9);
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int fd;
|
||||
|
||||
start(84);
|
||||
|
||||
subtest = 1;
|
||||
fd = sink_stdout();
|
||||
test_posix_spawn_ls();
|
||||
test_posix_spawnp_ls();
|
||||
restore_stdout(fd);
|
||||
|
||||
test_posix_spawn_missing();
|
||||
test_posix_spawn_nonexec();
|
||||
|
||||
subtest = 2;
|
||||
test_posix_spawn_child();
|
||||
|
||||
subtest = 3;
|
||||
test_posix_spawnattr();
|
||||
subtest = 4;
|
||||
fd = sink_stdout();
|
||||
test_posix_spawn_file_actions();
|
||||
restore_stdout(fd);
|
||||
subtest = 5;
|
||||
test_posix_spawn_file_actions_failures();
|
||||
|
||||
/* TODO: Write/port more tests */
|
||||
|
||||
quit();
|
||||
|
||||
/* Not reached */
|
||||
return -1;
|
||||
}
|
Loading…
Reference in a new issue