[haiku-commits] haiku: hrev51418 - src/system/libroot/posix headers/posix src/tests/system/libroot/posix

  • From: jerome.duval@xxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Tue, 12 Sep 2017 19:51:37 +0200 (CEST)

hrev51418 adds 1 changeset to branch 'master'
old head: 854c63b57b962410d51cf9f0880c848433fd7472
new head: ccd42320c45658052d620804bb8e05e5bc327706
overview: 
http://cgit.haiku-os.org/haiku/log/?qt=range&q=ccd42320c456+%5E854c63b57b96

----------------------------------------------------------------------------

ccd42320c456: libroot: add posix_spawn().

                                   [ Jérôme Duval <jerome.duval@xxxxxxxxx> ]

----------------------------------------------------------------------------

Revision:    hrev51418
Commit:      ccd42320c45658052d620804bb8e05e5bc327706
URL:         http://cgit.haiku-os.org/haiku/commit/?id=ccd42320c456
Author:      Jérôme Duval <jerome.duval@xxxxxxxxx>
Date:        Wed Sep  6 04:05:26 2017 UTC

----------------------------------------------------------------------------

5 files changed, 630 insertions(+)
headers/posix/spawn.h                            |  83 ++++
src/system/libroot/posix/Jamfile                 |   1 +
src/system/libroot/posix/spawn.cpp               | 495 +++++++++++++++++++
src/tests/system/libroot/posix/Jamfile           |   1 +
.../system/libroot/posix/posix_spawn_test.cpp    |  50 ++

----------------------------------------------------------------------------

diff --git a/headers/posix/spawn.h b/headers/posix/spawn.h
new file mode 100644
index 0000000..4726b53
--- /dev/null
+++ b/headers/posix/spawn.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2017 Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the Haiku License.
+ */
+#ifndef _SPAWN_H_
+#define _SPAWN_H_
+
+
+#include <sched.h>
+#include <signal.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+
+/*
+ * Flags for spawn attributes.
+ */
+#define POSIX_SPAWN_RESETIDS           0x01
+#define POSIX_SPAWN_SETPGROUP          0x02
+#if 0  /* Unimplemented flags: */
+#define POSIX_SPAWN_SETSCHEDPARAM      0x04
+#define POSIX_SPAWN_SETSCHEDULER       0x08
+#endif /* 0 */
+#define POSIX_SPAWN_SETSIGDEF          0x10
+#define POSIX_SPAWN_SETSIGMASK         0x20
+
+
+typedef struct _posix_spawnattr        *posix_spawnattr_t;
+typedef struct _posix_spawn_file_actions       *posix_spawn_file_actions_t;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+extern 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[]);
+extern 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[]);
+
+/* file actions functions */
+extern int posix_spawn_file_actions_init(
+       posix_spawn_file_actions_t *file_actions);
+extern int posix_spawn_file_actions_destroy(
+       posix_spawn_file_actions_t *file_actions);
+extern int posix_spawn_file_actions_addopen(
+       posix_spawn_file_actions_t *file_actions,
+       int fildes, const char *path, int oflag, mode_t mode);
+extern int posix_spawn_file_actions_addclose(
+       posix_spawn_file_actions_t *file_actions, int fildes);
+extern int posix_spawn_file_actions_adddup2(
+       posix_spawn_file_actions_t *file_actions, int fildes, int newfildes);
+
+/* spawn attribute functions */
+extern int posix_spawnattr_destroy(posix_spawnattr_t *attr);
+extern int posix_spawnattr_init(posix_spawnattr_t *attr);
+extern int posix_spawnattr_getflags(const posix_spawnattr_t *attr,
+       short *_flags);
+extern int posix_spawnattr_setflags(posix_spawnattr_t *attr, short flags);
+extern int posix_spawnattr_getpgroup(const posix_spawnattr_t *attr,
+       pid_t *_pgroup);
+extern int posix_spawnattr_setpgroup(posix_spawnattr_t *attr, pid_t pgroup);
+extern int posix_spawnattr_getsigdefault(const posix_spawnattr_t *attr,
+       sigset_t *sigdefault);
+extern int posix_spawnattr_setsigdefault(posix_spawnattr_t *attr,
+       const sigset_t *sigdefault);
+extern int posix_spawnattr_getsigmask(const posix_spawnattr_t *attr,
+       sigset_t *_sigmask);
+extern int posix_spawnattr_setsigmask(posix_spawnattr_t *attr,
+       const sigset_t *sigmask);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _SPAWN_H_ */
+
diff --git a/src/system/libroot/posix/Jamfile b/src/system/libroot/posix/Jamfile
index ac6f34c..2079067 100644
--- a/src/system/libroot/posix/Jamfile
+++ b/src/system/libroot/posix/Jamfile
@@ -34,6 +34,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
                        $(PWD_BACKEND)
                        scheduler.cpp
                        semaphore.cpp
+                       spawn.cpp
                        syslog.cpp
                        termios.c
                        utime.c
diff --git a/src/system/libroot/posix/spawn.cpp 
b/src/system/libroot/posix/spawn.cpp
new file mode 100644
index 0000000..171e531
--- /dev/null
+++ b/src/system/libroot/posix/spawn.cpp
@@ -0,0 +1,495 @@
+/*
+ * Copyright 2017, Jérôme Duval, jerome.Duval@xxxxxxxxx
+ * Distributed under the terms of the MIT license.
+ */
+
+
+#include <spawn.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <syscalls.h>
+
+
+enum action_type {
+       file_action_open,
+       file_action_close,
+       file_action_dup2
+};
+
+struct _file_action {
+       enum action_type type;
+       int fd;
+       union {
+               struct {
+                       char* path;
+                       int     oflag;
+                       mode_t mode;
+               } open_action;
+               struct {
+                       int srcfd;
+               } dup2_action;
+       } action;
+};
+
+struct _posix_spawnattr {
+       short   flags;
+       pid_t   pgroup;
+       sigset_t        sigdefault;
+       sigset_t        sigmask;
+};
+
+struct _posix_spawn_file_actions {
+       int             size;
+       int             count;
+       _file_action *actions;
+};
+
+
+static int
+posix_spawn_file_actions_extend(struct _posix_spawn_file_actions *actions)
+{
+       int newsize = actions->size + 4;
+       void *newactions = realloc(actions->actions,
+               newsize * sizeof(struct _file_action));
+       if (newactions == NULL)
+               return ENOMEM;
+       actions->actions = (struct _file_action*)newactions;
+       actions->size = newsize;
+       return 0;
+}
+
+
+int
+posix_spawn_file_actions_init(posix_spawn_file_actions_t *_file_actions)
+{
+       posix_spawn_file_actions_t actions = (posix_spawn_file_actions_t)malloc(
+               sizeof(struct _posix_spawn_file_actions));
+
+       if (actions == NULL)
+               return ENOMEM;
+
+       memset(actions, 0, sizeof(*actions));
+       *_file_actions = actions;
+
+       return 0;
+}
+
+
+int
+posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *_actions)
+{
+       struct _posix_spawn_file_actions* actions = _actions != NULL ? 
*_actions : NULL;
+
+       if (actions == NULL)
+               return EINVAL;
+
+       free(actions);
+
+       return 0;
+}
+
+
+int
+posix_spawn_file_actions_addopen(posix_spawn_file_actions_t *_actions,
+       int fildes, const char *path, int oflag, mode_t mode)
+{
+       struct _posix_spawn_file_actions* actions = _actions != NULL ? 
*_actions : NULL;
+
+       if (actions == NULL)
+               return EINVAL;
+
+       if (fildes < 0 || fildes >= sysconf(_SC_OPEN_MAX))
+               return EBADF;
+
+       char* npath = strdup(path);
+       if (npath == NULL)
+               return ENOMEM;
+       if (actions->count == actions->size
+               && posix_spawn_file_actions_extend(actions) != 0) {
+               free(npath);
+               return ENOMEM;
+       }
+
+       struct _file_action *action = &actions->actions[actions->count];
+       action->type = file_action_open;
+       action->fd = fildes;
+       action->action.open_action.path = npath;
+       action->action.open_action.oflag = oflag;
+       action->action.open_action.mode = mode;
+       actions->count++;
+       return 0;
+}
+
+
+int
+posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *_actions,
+       int fildes)
+{
+       struct _posix_spawn_file_actions* actions = _actions != NULL ? 
*_actions : NULL;
+
+       if (actions == NULL)
+               return EINVAL;
+
+       if (fildes < 0 || fildes >= sysconf(_SC_OPEN_MAX))
+               return EBADF;
+
+       if (actions->count == actions->size
+               && posix_spawn_file_actions_extend(actions) != 0) {
+               return ENOMEM;
+       }
+
+       struct _file_action *action = &actions->actions[actions->count];
+       action->type = file_action_close;
+       action->fd = fildes;
+       actions->count++;
+       return 0;
+}
+
+
+int
+posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *_actions,
+       int fildes, int newfildes)
+{
+       struct _posix_spawn_file_actions* actions = _actions != NULL ? 
*_actions : NULL;
+
+       if (actions == NULL)
+               return EINVAL;
+
+       if (fildes < 0 || fildes >= sysconf(_SC_OPEN_MAX))
+               return EBADF;
+
+       if (actions->count == actions->size
+               && posix_spawn_file_actions_extend(actions) != 0) {
+               return ENOMEM;
+       }
+
+       struct _file_action *action = &actions->actions[actions->count];
+       action->type = file_action_dup2;
+       action->fd = newfildes;
+       action->action.dup2_action.srcfd = fildes;
+       actions->count++;
+       return 0;
+}
+
+
+int
+posix_spawnattr_init(posix_spawnattr_t *_attr)
+{
+       posix_spawnattr_t attr = (posix_spawnattr_t)malloc(
+               sizeof(struct _posix_spawnattr));
+
+       if (attr == NULL)
+               return ENOMEM;
+
+       memset(attr, 0, sizeof(*attr));
+       *_attr = attr;
+
+       return 0;
+}
+
+
+int
+posix_spawnattr_destroy(posix_spawnattr_t *_attr)
+{
+       struct _posix_spawnattr* attr = _attr != NULL ? *_attr : NULL;
+
+       if (attr == NULL)
+               return EINVAL;
+
+       free(attr);
+
+       return 0;
+}
+
+
+int
+posix_spawnattr_getflags(const posix_spawnattr_t *_attr, short *flags)
+{
+       struct _posix_spawnattr *attr;
+
+       if (_attr == NULL || (attr = *_attr) == NULL || flags == NULL)
+               return EINVAL;
+
+       *flags = attr->flags;
+
+       return 0;
+}
+
+
+int
+posix_spawnattr_setflags(posix_spawnattr_t *_attr, short flags)
+{
+       struct _posix_spawnattr *attr;
+
+       if (_attr == NULL || (attr = *_attr) == NULL)
+               return EINVAL;
+
+       if ((flags & ~(POSIX_SPAWN_RESETIDS | POSIX_SPAWN_SETPGROUP
+                       | POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK)) != 
0) {
+               return EINVAL;
+       }
+
+       attr->flags = flags;
+
+       return 0;
+}
+
+
+int
+posix_spawnattr_getpgroup(const posix_spawnattr_t *_attr, pid_t *pgroup)
+{
+       struct _posix_spawnattr *attr;
+
+       if (_attr == NULL || (attr = *_attr) == NULL || pgroup == NULL)
+               return EINVAL;
+
+       *pgroup = attr->pgroup;
+
+       return 0;
+}
+
+
+int
+posix_spawnattr_setpgroup(posix_spawnattr_t *_attr, pid_t pgroup)
+{
+       struct _posix_spawnattr *attr;
+
+       if (_attr == NULL || (attr = *_attr) == NULL)
+               return EINVAL;
+
+       attr->pgroup = pgroup;
+
+       return 0;
+}
+
+
+int
+posix_spawnattr_getsigdefault(const posix_spawnattr_t *_attr, sigset_t 
*sigdefault)
+{
+       struct _posix_spawnattr *attr;
+
+       if (_attr == NULL || (attr = *_attr) == NULL || sigdefault == NULL)
+               return EINVAL;
+
+       memcpy(sigdefault, &attr->sigdefault, sizeof(sigset_t));
+
+       return 0;
+}
+
+
+int
+posix_spawnattr_setsigdefault(posix_spawnattr_t *_attr,
+       const sigset_t *sigdefault)
+{
+       struct _posix_spawnattr *attr;
+
+       if (_attr == NULL || (attr = *_attr) == NULL || sigdefault == NULL)
+               return EINVAL;
+
+       memcpy(&attr->sigdefault, sigdefault, sizeof(sigset_t));
+
+       return 0;
+}
+
+
+int
+posix_spawnattr_getsigmask(const posix_spawnattr_t *_attr, sigset_t *sigmask)
+{
+       struct _posix_spawnattr *attr;
+
+       if (_attr == NULL || (attr = *_attr) == NULL || sigmask == NULL)
+               return EINVAL;
+
+       memcpy(sigmask, &attr->sigmask, sizeof(sigset_t));
+
+       return 0;
+}
+
+
+int
+posix_spawnattr_setsigmask(posix_spawnattr_t *_attr, const sigset_t *sigmask)
+{
+       struct _posix_spawnattr *attr;
+
+       if (_attr == NULL || (attr = *_attr) == NULL || sigmask == NULL)
+               return EINVAL;
+
+       memcpy(&attr->sigmask, sigmask, sizeof(sigset_t));
+
+       return 0;
+}
+
+
+static int
+process_spawnattr(const posix_spawnattr_t *_attr)
+{
+       if (_attr == NULL)
+               return 0;
+
+       struct _posix_spawnattr *attr = *_attr;
+       if (attr == NULL)
+               return EINVAL;
+
+       if ((attr->flags & POSIX_SPAWN_SETSIGMASK) != 0)
+               sigprocmask(SIG_SETMASK, &attr->sigmask, NULL);
+
+       if ((attr->flags & POSIX_SPAWN_SETSIGDEF) != 0) {
+               struct sigaction action;
+               action.sa_handler = SIG_DFL;
+               action.sa_flags = 0;
+               action.sa_userdata = NULL;
+               sigemptyset(&action.sa_mask);
+               for (int i = 1; i <= NSIG; i++) {
+                       if (sigismember(&attr->sigdefault, i) == 1
+                               && sigaction(i, &action, NULL) != 0) {
+                               return errno;
+                       }
+               }
+       }
+
+       if ((attr->flags & POSIX_SPAWN_RESETIDS) != 0) {
+               if (setegid(getgid()) != 0)
+                       return errno;
+               if (seteuid(getuid()) != 0)
+                       return errno;
+       }
+
+       if ((attr->flags & POSIX_SPAWN_SETPGROUP) != 0) {
+               if (setpgid(0, attr->pgroup) != 0)
+                       return errno;
+       }
+
+       return 0;
+}
+
+
+static int
+process_file_actions(const posix_spawn_file_actions_t *_actions, int *errfd)
+{
+       if (_actions == NULL)
+               return 0;
+
+       struct _posix_spawn_file_actions* actions = *_actions;
+       if (actions == NULL)
+               return EINVAL;
+
+       for (int i = 0; i < actions->count; i++) {
+               struct _file_action *action = &actions->actions[i];
+
+               if (action->fd == *errfd) {
+                       int newfd = dup(action->fd);
+                       if (newfd == -1)
+                               return errno;
+                       close(action->fd);
+                       *errfd = newfd;
+               }
+
+               if (action->type == file_action_close) {
+                       if (close(action->fd) != 0)
+                               return errno;
+               } else if (action->type == file_action_open) {
+                       int fd = open(action->action.open_action.path,
+                               action->action.open_action.oflag,
+                               action->action.open_action.mode);
+                       if (fd == -1)
+                               return errno;
+                       if (fd != action->fd) {
+                               if (dup2(action->fd, fd) != 0)
+                                       return errno;
+                               if (close(fd) != 0)
+                                       return errno;
+                       }
+               } else if (action->type == file_action_dup2) {
+                       if (dup2(action->action.dup2_action.srcfd, action->fd) 
!= 0)
+                               return errno;
+               }
+       }
+
+       return 0;
+}
+
+
+static int
+do_posix_spawn(pid_t *_pid, const char *path,
+       const posix_spawn_file_actions_t *actions,
+       const posix_spawnattr_t *attrp, char *const argv[], char *const envp[],
+       bool envpath)
+{
+       int err = 0;
+       int fds[2];
+       pid_t pid;
+
+       if (pipe(fds) != 0)
+               return errno;
+       if (fcntl(fds[0], F_SETFD, FD_CLOEXEC) != 0
+               || fcntl(fds[1], F_SETFD, FD_CLOEXEC) != 0) {
+               goto fail;
+       }
+       pid = vfork();
+       if (pid == -1)
+               goto fail;
+
+       if (pid != 0) {
+               // parent
+               if (_pid != NULL)
+                       *_pid = pid;
+               close(fds[1]);
+               read(fds[0], &err, sizeof(err));
+               if (err != 0)
+                       waitpid(pid, NULL, WNOHANG);
+               return err;
+       }
+
+       // child
+       close(fds[0]);
+
+       err = process_spawnattr(attrp);
+       if (err == 0)
+               err = process_file_actions(actions, &fds[1]);
+       if (err != 0)
+               goto fail_child;
+
+       if (envpath)
+               execvpe(path, argv, envp != NULL ? envp : environ);
+       else
+               execve(path, argv, envp != NULL ? envp : environ);
+
+       err = errno;
+
+fail_child:
+       write(fds[1], &err, sizeof(err));
+       close(fds[1]);
+       _exit(127);
+
+fail:
+       err = errno;
+       close(fds[0]);
+       close(fds[1]);
+       return err;
+}
+
+
+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[])
+{
+       return do_posix_spawn(pid, path, file_actions, attrp, argv, envp, 
false);
+}
+
+
+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[])
+{
+       return do_posix_spawn(pid, file, file_actions, attrp, argv, envp, true);
+}
+
diff --git a/src/tests/system/libroot/posix/Jamfile 
b/src/tests/system/libroot/posix/Jamfile
index fbd2c4f..3736add 100644
--- a/src/tests/system/libroot/posix/Jamfile
+++ b/src/tests/system/libroot/posix/Jamfile
@@ -38,6 +38,7 @@ SimpleTest <test>truncate : truncate.cpp ;
 SimpleTest init_rld_after_fork_test : init_rld_after_fork_test.cpp ;
 SimpleTest user_thread_fork_test : user_thread_fork_test.cpp ;
 SimpleTest pthread_barrier_test : pthread_barrier_test.cpp ;
+SimpleTest posix_spawn_test : posix_spawn_test.cpp ;
 
 # XSI tests
 SimpleTest xsi_msg_queue_test1 : xsi_msg_queue_test1.cpp ;
diff --git a/src/tests/system/libroot/posix/posix_spawn_test.cpp 
b/src/tests/system/libroot/posix/posix_spawn_test.cpp
new file mode 100644
index 0000000..957a4ab
--- /dev/null
+++ b/src/tests/system/libroot/posix/posix_spawn_test.cpp
@@ -0,0 +1,50 @@
+#include <errno.h>
+#include <spawn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+int main()
+{
+
+       char* _args[4];
+       char* _env[] = { "myenv=5", NULL };
+
+       _args[0] = "bash";
+       _args[1] = "-c";
+       _args[2] = "exit $myenv";
+       _args[3] = NULL;
+
+       pid_t pid;
+       int err = posix_spawnp(&pid, _args[0], NULL, NULL, _args, _env);
+       printf("posix_spawnp: %d, %d\n", err, pid);
+
+       int status;
+       pid_t waitpid_res = waitpid(pid, &status, 0);
+       if (waitpid_res != pid)
+               printf("posix_spawnp: waitpid didn't return pid\n");
+
+       printf("posix_spawnp: WIFEXITED(): %d, WEXITSTATUS() %d => 5\n",
+               WIFEXITED(status), WEXITSTATUS(status));
+
+       _args[0] = "/tmp/toto";
+       _args[1] = NULL;
+
+       err = posix_spawn(&pid, _args[0], NULL, NULL, _args, _env);
+       printf("posix_spawn: %d, %d\n", err, pid);
+
+       if (err == 0) {
+               waitpid_res = waitpid(pid, &status, 0);
+               if (waitpid_res != pid)
+                       printf("posix_spawn: waitpid didn't return pid\n");
+               printf("posix_spawn: WIFEXITED(): %d, WEXITSTATUS() %d => 
127\n",
+                       WIFEXITED(status), WEXITSTATUS(status));
+       } else {
+               waitpid_res = waitpid(-1, NULL, 0);
+               printf("posix_spawn: waitpid %d, %d\n", waitpid_res, errno);
+       }
+
+       return 0;
+}
+


Other related posts:

  • » [haiku-commits] haiku: hrev51418 - src/system/libroot/posix headers/posix src/tests/system/libroot/posix - jerome . duval