Ticket #13446: 0001-libroot-add-posix_spawn.patch

File 0001-libroot-add-posix_spawn.patch, 16.0 KB (added by korli, 7 years ago)

Library implementation of posix_spawn

  • new file headers/posix/spawn.h

    From a0ceda72d9a516694cc78c214d712b3913d4d540 Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= <jerome.duval@gmail.com>
    Date: Wed, 6 Sep 2017 06:05:26 +0200
    Subject: [PATCH] libroot: add posix_spawn().
    
    ---
     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 +++
     5 files changed, 630 insertions(+)
     create mode 100644 headers/posix/spawn.h
     create mode 100644 src/system/libroot/posix/spawn.cpp
     create mode 100644 src/tests/system/libroot/posix/posix_spawn_test.cpp
    
    diff --git a/headers/posix/spawn.h b/headers/posix/spawn.h
    new file mode 100644
    index 0000000..4726b53
    - +  
     1/*
     2 * Copyright 2017 Haiku, Inc. All Rights Reserved.
     3 * Distributed under the terms of the Haiku License.
     4 */
     5#ifndef _SPAWN_H_
     6#define _SPAWN_H_
     7
     8
     9#include <sched.h>
     10#include <signal.h>
     11#include <stdint.h>
     12#include <sys/types.h>
     13
     14
     15/*
     16 * Flags for spawn attributes.
     17 */
     18#define POSIX_SPAWN_RESETIDS        0x01
     19#define POSIX_SPAWN_SETPGROUP       0x02
     20#if 0   /* Unimplemented flags: */
     21#define POSIX_SPAWN_SETSCHEDPARAM   0x04
     22#define POSIX_SPAWN_SETSCHEDULER    0x08
     23#endif  /* 0 */
     24#define POSIX_SPAWN_SETSIGDEF       0x10
     25#define POSIX_SPAWN_SETSIGMASK      0x20
     26
     27
     28typedef struct _posix_spawnattr *posix_spawnattr_t;
     29typedef struct _posix_spawn_file_actions    *posix_spawn_file_actions_t;
     30
     31
     32#ifdef __cplusplus
     33extern "C" {
     34#endif
     35
     36
     37extern int posix_spawn(pid_t *pid, const char *path,
     38    const posix_spawn_file_actions_t *file_actions,
     39    const posix_spawnattr_t *attrp, char *const argv[], char *const envp[]);
     40extern int posix_spawnp(pid_t *pid, const char *file,
     41    const posix_spawn_file_actions_t *file_actions,
     42    const posix_spawnattr_t *attrp, char *const argv[],
     43    char *const envp[]);
     44
     45/* file actions functions */
     46extern int posix_spawn_file_actions_init(
     47    posix_spawn_file_actions_t *file_actions);
     48extern int posix_spawn_file_actions_destroy(
     49    posix_spawn_file_actions_t *file_actions);
     50extern int posix_spawn_file_actions_addopen(
     51    posix_spawn_file_actions_t *file_actions,
     52    int fildes, const char *path, int oflag, mode_t mode);
     53extern int posix_spawn_file_actions_addclose(
     54    posix_spawn_file_actions_t *file_actions, int fildes);
     55extern int posix_spawn_file_actions_adddup2(
     56    posix_spawn_file_actions_t *file_actions, int fildes, int newfildes);
     57
     58/* spawn attribute functions */
     59extern int posix_spawnattr_destroy(posix_spawnattr_t *attr);
     60extern int posix_spawnattr_init(posix_spawnattr_t *attr);
     61extern int posix_spawnattr_getflags(const posix_spawnattr_t *attr,
     62    short *_flags);
     63extern int posix_spawnattr_setflags(posix_spawnattr_t *attr, short flags);
     64extern int posix_spawnattr_getpgroup(const posix_spawnattr_t *attr,
     65    pid_t *_pgroup);
     66extern int posix_spawnattr_setpgroup(posix_spawnattr_t *attr, pid_t pgroup);
     67extern int posix_spawnattr_getsigdefault(const posix_spawnattr_t *attr,
     68    sigset_t *sigdefault);
     69extern int posix_spawnattr_setsigdefault(posix_spawnattr_t *attr,
     70    const sigset_t *sigdefault);
     71extern int posix_spawnattr_getsigmask(const posix_spawnattr_t *attr,
     72    sigset_t *_sigmask);
     73extern int posix_spawnattr_setsigmask(posix_spawnattr_t *attr,
     74    const sigset_t *sigmask);
     75
     76
     77#ifdef __cplusplus
     78}
     79#endif
     80
     81
     82#endif  /* _SPAWN_H_ */
     83
  • src/system/libroot/posix/Jamfile

    diff --git a/src/system/libroot/posix/Jamfile b/src/system/libroot/posix/Jamfile
    index ac6f34c..2079067 100644
    a b for architectureObject in [ MultiArchSubDirSetup ] {  
    3434            $(PWD_BACKEND)
    3535            scheduler.cpp
    3636            semaphore.cpp
     37            spawn.cpp
    3738            syslog.cpp
    3839            termios.c
    3940            utime.c
  • new file src/system/libroot/posix/spawn.cpp

    diff --git a/src/system/libroot/posix/spawn.cpp b/src/system/libroot/posix/spawn.cpp
    new file mode 100644
    index 0000000..b667d2c
    - +  
     1/*
     2 * Copyright 2017, Jérôme Duval, jerome.Duval@gmail.com
     3 * Distributed under the terms of the MIT license.
     4 */
     5
     6
     7#include <spawn.h>
     8
     9#include <errno.h>
     10#include <signal.h>
     11#include <stdio.h>
     12#include <stdlib.h>
     13#include <string.h>
     14#include <unistd.h>
     15
     16#include <syscalls.h>
     17
     18
     19enum action_type {
     20    file_action_open,
     21    file_action_close,
     22    file_action_dup2
     23};
     24
     25struct _file_action {
     26    enum action_type type;
     27    int fd;
     28    union {
     29        struct {
     30            char* path;
     31            int oflag;
     32            mode_t mode;
     33        } open_action;
     34        struct {
     35            int srcfd;
     36        } dup2_action;
     37    } action;
     38};
     39
     40struct _posix_spawnattr {
     41    short   flags;
     42    pid_t   pgroup;
     43    sigset_t    sigdefault;
     44    sigset_t    sigmask;
     45};
     46
     47struct _posix_spawn_file_actions {
     48    int     size;
     49    int     count;
     50    _file_action *actions;
     51};
     52
     53
     54static int
     55posix_spawn_file_actions_extend(struct _posix_spawn_file_actions *actions)
     56{
     57    int newsize = actions->size + 4;
     58    void *newactions = realloc(actions->actions,
     59        newsize * sizeof(struct _file_action));
     60    if (newactions == NULL)
     61        return ENOMEM;
     62    actions->actions = (struct _file_action*)newactions;
     63    actions->size = newsize;
     64    return 0;
     65}
     66
     67
     68int
     69posix_spawn_file_actions_init(posix_spawn_file_actions_t *_file_actions)
     70{
     71    posix_spawn_file_actions_t actions = (posix_spawn_file_actions_t)malloc(
     72        sizeof(struct _posix_spawn_file_actions));
     73
     74    if (actions == NULL)
     75        return ENOMEM;
     76
     77    memset(actions, 0, sizeof(*actions));
     78    *_file_actions = actions;
     79
     80    return 0;
     81}
     82
     83
     84int
     85posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *_actions)
     86{
     87    struct _posix_spawn_file_actions* actions = _actions != NULL ? *_actions : NULL;
     88
     89    if (actions == NULL)
     90        return EINVAL;
     91
     92    free(actions);
     93
     94    return 0;
     95}
     96
     97
     98int
     99posix_spawn_file_actions_addopen(posix_spawn_file_actions_t *_actions,
     100    int fildes, const char *path, int oflag, mode_t mode)
     101{
     102    struct _posix_spawn_file_actions* actions = _actions != NULL ? *_actions : NULL;
     103
     104    if (actions == NULL)
     105        return EINVAL;
     106
     107    if (fildes < 0 || fildes >= sysconf(_SC_OPEN_MAX))
     108        return EBADF;
     109
     110    char* npath = strdup(path);
     111    if (npath == NULL)
     112        return ENOMEM;
     113    if (actions->count == actions->size
     114        && posix_spawn_file_actions_extend(actions) != 0) {
     115        free(npath);
     116        return ENOMEM;
     117    }
     118
     119    struct _file_action *action = &actions->actions[actions->count];
     120    action->type = file_action_open;
     121    action->fd = fildes;
     122    action->action.open_action.path = npath;
     123    action->action.open_action.oflag = oflag;
     124    action->action.open_action.mode = mode;
     125    actions->count++;
     126    return 0;
     127}
     128
     129
     130int
     131posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *_actions,
     132    int fildes)
     133{
     134    struct _posix_spawn_file_actions* actions = _actions != NULL ? *_actions : NULL;
     135
     136    if (actions == NULL)
     137        return EINVAL;
     138
     139    if (fildes < 0 || fildes >= sysconf(_SC_OPEN_MAX))
     140        return EBADF;
     141
     142    if (actions->count == actions->size
     143        && posix_spawn_file_actions_extend(actions) != 0) {
     144        return ENOMEM;
     145    }
     146
     147    struct _file_action *action = &actions->actions[actions->count];
     148    action->type = file_action_close;
     149    action->fd = fildes;
     150    actions->count++;
     151    return 0;
     152}
     153
     154
     155int
     156posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *_actions,
     157    int fildes, int newfildes)
     158{
     159    struct _posix_spawn_file_actions* actions = _actions != NULL ? *_actions : NULL;
     160
     161    if (actions == NULL)
     162        return EINVAL;
     163
     164    if (fildes < 0 || fildes >= sysconf(_SC_OPEN_MAX))
     165        return EBADF;
     166
     167    if (actions->count == actions->size
     168        && posix_spawn_file_actions_extend(actions) != 0) {
     169        return ENOMEM;
     170    }
     171
     172    struct _file_action *action = &actions->actions[actions->count];
     173    action->type = file_action_dup2;
     174    action->fd = newfildes;
     175    action->action.dup2_action.srcfd = fildes;
     176    actions->count++;
     177    return 0;
     178}
     179
     180
     181int
     182posix_spawnattr_init(posix_spawnattr_t *_attr)
     183{
     184    posix_spawnattr_t attr = (posix_spawnattr_t)malloc(
     185        sizeof(struct _posix_spawnattr));
     186
     187    if (attr == NULL)
     188        return ENOMEM;
     189
     190    memset(attr, 0, sizeof(*attr));
     191    *_attr = attr;
     192
     193    return 0;
     194}
     195
     196
     197int
     198posix_spawnattr_destroy(posix_spawnattr_t *_attr)
     199{
     200    struct _posix_spawnattr* attr = _attr != NULL ? *_attr : NULL;
     201
     202    if (attr == NULL)
     203        return EINVAL;
     204
     205    free(attr);
     206
     207    return 0;
     208}
     209
     210
     211int
     212posix_spawnattr_getflags(const posix_spawnattr_t *_attr, short *flags)
     213{
     214    struct _posix_spawnattr *attr;
     215
     216    if (_attr == NULL || (attr = *_attr) == NULL || flags == NULL)
     217        return EINVAL;
     218
     219    *flags = attr->flags;
     220
     221    return 0;
     222}
     223
     224
     225int
     226posix_spawnattr_setflags(posix_spawnattr_t *_attr, short flags)
     227{
     228    struct _posix_spawnattr *attr;
     229
     230    if (_attr == NULL || (attr = *_attr) == NULL)
     231        return EINVAL;
     232
     233    if ((flags & ~(POSIX_SPAWN_RESETIDS | POSIX_SPAWN_SETPGROUP
     234            | POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK)) != 0) {
     235        return EINVAL;
     236    }
     237
     238    attr->flags = flags;
     239
     240    return 0;
     241}
     242
     243
     244int
     245posix_spawnattr_getpgroup(const posix_spawnattr_t *_attr, pid_t *pgroup)
     246{
     247    struct _posix_spawnattr *attr;
     248
     249    if (_attr == NULL || (attr = *_attr) == NULL || pgroup == NULL)
     250        return EINVAL;
     251
     252    *pgroup = attr->pgroup;
     253
     254    return 0;
     255}
     256
     257
     258int
     259posix_spawnattr_setpgroup(posix_spawnattr_t *_attr, pid_t pgroup)
     260{
     261    struct _posix_spawnattr *attr;
     262
     263    if (_attr == NULL || (attr = *_attr) == NULL)
     264        return EINVAL;
     265
     266    attr->pgroup = pgroup;
     267
     268    return 0;
     269}
     270
     271
     272int
     273posix_spawnattr_getsigdefault(const posix_spawnattr_t *_attr, sigset_t *sigdefault)
     274{
     275    struct _posix_spawnattr *attr;
     276
     277    if (_attr == NULL || (attr = *_attr) == NULL || sigdefault == NULL)
     278        return EINVAL;
     279
     280    memcpy(sigdefault, &attr->sigdefault, sizeof(sigset_t));
     281
     282    return 0;
     283}
     284
     285
     286int
     287posix_spawnattr_setsigdefault(posix_spawnattr_t *_attr,
     288    const sigset_t *sigdefault)
     289{
     290    struct _posix_spawnattr *attr;
     291
     292    if (_attr == NULL || (attr = *_attr) == NULL || sigdefault == NULL)
     293        return EINVAL;
     294
     295    memcpy(&attr->sigdefault, sigdefault, sizeof(sigset_t));
     296
     297    return 0;
     298}
     299
     300
     301int
     302posix_spawnattr_getsigmask(const posix_spawnattr_t *_attr, sigset_t *sigmask)
     303{
     304    struct _posix_spawnattr *attr;
     305
     306    if (_attr == NULL || (attr = *_attr) == NULL || sigmask == NULL)
     307        return EINVAL;
     308
     309    memcpy(sigmask, &attr->sigmask, sizeof(sigset_t));
     310
     311    return 0;
     312}
     313
     314
     315int
     316posix_spawnattr_setsigmask(posix_spawnattr_t *_attr, const sigset_t *sigmask)
     317{
     318    struct _posix_spawnattr *attr;
     319
     320    if (_attr == NULL || (attr = *_attr) == NULL || sigmask == NULL)
     321        return EINVAL;
     322
     323    memcpy(&attr->sigmask, sigmask, sizeof(sigset_t));
     324
     325    return 0;
     326}
     327
     328
     329static int
     330process_spawnattr(const posix_spawnattr_t *_attr)
     331{
     332    if (_attr == NULL)
     333        return 0;
     334
     335    struct _posix_spawnattr *attr = *_attr;
     336    if (attr == NULL)
     337        return EINVAL;
     338
     339    if ((attr->flags & POSIX_SPAWN_SETSIGMASK) != 0)
     340        sigprocmask(SIG_SETMASK, &attr->sigmask, NULL);
     341
     342    if ((attr->flags & POSIX_SPAWN_SETSIGDEF) != 0) {
     343        struct sigaction action;
     344        action.sa_handler = SIG_DFL;
     345        action.sa_flags = 0;
     346        action.sa_userdata = NULL;
     347        sigemptyset(&action.sa_mask);
     348        for (int i = 1; i <= NSIG; i++) {
     349            if (sigismember(&attr->sigdefault, i) == 1
     350                && sigaction(i, &action, NULL) != 0) {
     351                return errno;
     352            }
     353        }
     354    }
     355
     356    if ((attr->flags & POSIX_SPAWN_RESETIDS) != 0) {
     357        if (setegid(getgid()) != 0)
     358            return errno;
     359        if (seteuid(getuid()) != 0)
     360            return errno;
     361    }
     362
     363    if ((attr->flags & POSIX_SPAWN_SETPGROUP) != 0) {
     364        if (setpgid(0, attr->pgroup) != 0)
     365            return errno;
     366    }
     367
     368    return 0;
     369}
     370
     371
     372static int
     373process_file_actions(const posix_spawn_file_actions_t *_actions, int *errfd)
     374{
     375    if (_actions == NULL)
     376        return 0;
     377
     378    struct _posix_spawn_file_actions* actions = *_actions;
     379    if (actions == NULL)
     380        return EINVAL;
     381
     382    for (int i = 0; i < actions->count; i++) {
     383        struct _file_action *action = &actions->actions[i];
     384
     385        if (action->fd == *errfd) {
     386            int newfd = dup(action->fd);
     387            if (newfd == -1)
     388                return errno;
     389            close(action->fd);
     390            *errfd = newfd;
     391        }
     392
     393        if (action->type == file_action_close) {
     394            if (close(action->fd) != 0)
     395                return errno;
     396        } else if (action->type == file_action_open) {
     397            int fd = open(action->action.open_action.path,
     398                action->action.open_action.oflag,
     399                action->action.open_action.mode);
     400            if (fd == -1)
     401                return errno;
     402            if (fd != action->fd) {
     403                if (dup2(action->fd, fd) != 0)
     404                    return errno;
     405                if (close(fd) != 0)
     406                    return errno;
     407            }
     408        } else if (action->type == file_action_dup2) {
     409            if (dup2(action->action.dup2_action.srcfd, action->fd) != 0)
     410                return errno;
     411        }
     412    }
     413
     414    return 0;
     415}
     416
     417
     418static int
     419do_posix_spawn(pid_t *_pid, const char *path,
     420    const posix_spawn_file_actions_t *actions,
     421    const posix_spawnattr_t *attrp, char *const argv[], char *const envp[],
     422    bool envpath)
     423{
     424    int err = 0;
     425    int fds[2];
     426    pid_t pid;
     427
     428    if (pipe(fds) != 0)
     429        return errno;
     430    if (fcntl(fds[0], F_SETFD, FD_CLOEXEC) != 0
     431        || fcntl(fds[1], F_SETFD, FD_CLOEXEC) != 0) {
     432        goto fail;
     433    }
     434    pid = vfork();
     435    if (pid == -1)
     436        goto fail;
     437
     438    if (pid != 0) {
     439        // parent
     440        if (_pid != NULL)
     441            *_pid = pid;
     442        close(fds[1]);
     443        read(fds[0], &err, sizeof(err));
     444        if (err != 0)
     445            waitpid(pid, NULL, WNOHANG);
     446        return err;
     447    }
     448
     449    // child
     450    close(fds[0]);
     451
     452    err = process_spawnattr(attrp);
     453    if (err == 0)
     454        err = process_file_actions(actions, &fds[1]);
     455    if (err != 0)
     456        goto fail_child;
     457
     458    if (envpath)
     459        execvpe(path, argv, envp != NULL ? envp : environ);
     460    else
     461        execve(path, argv, envp != NULL ? envp : environ);
     462
     463    err = errno;
     464
     465fail_child:
     466    write(fds[1], &err, sizeof(err));
     467    close(fds[1]);
     468    _exit(127);
     469
     470fail:
     471    err = errno;
     472    close(fds[0]);
     473    close(fds[1]);
     474    return err;
     475}
     476
     477
     478int
     479posix_spawn(pid_t *pid, const char *path,
     480    const posix_spawn_file_actions_t *file_actions,
     481    const posix_spawnattr_t *attrp, char *const argv[], char *const envp[])
     482{
     483    return do_posix_spawn(pid, path, file_actions, attrp, argv, envp, false);
     484}
     485
     486
     487int
     488posix_spawnp(pid_t *pid, const char *file,
     489    const posix_spawn_file_actions_t *file_actions,
     490    const posix_spawnattr_t *attrp, char *const argv[],
     491    char *const envp[])
     492{
     493    return do_posix_spawn(pid, file, file_actions, attrp, argv, envp, true);
     494}
     495
  • src/tests/system/libroot/posix/Jamfile

    diff --git a/src/tests/system/libroot/posix/Jamfile b/src/tests/system/libroot/posix/Jamfile
    index fbd2c4f..3736add 100644
    a b SimpleTest <test>truncate : truncate.cpp ;  
    3838SimpleTest init_rld_after_fork_test : init_rld_after_fork_test.cpp ;
    3939SimpleTest user_thread_fork_test : user_thread_fork_test.cpp ;
    4040SimpleTest pthread_barrier_test : pthread_barrier_test.cpp ;
     41SimpleTest posix_spawn_test : posix_spawn_test.cpp ;
    4142
    4243# XSI tests
    4344SimpleTest xsi_msg_queue_test1 : xsi_msg_queue_test1.cpp ;
  • new file src/tests/system/libroot/posix/posix_spawn_test.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
    - +  
     1#include <errno.h>
     2#include <spawn.h>
     3#include <stdio.h>
     4#include <stdlib.h>
     5#include <unistd.h>
     6
     7
     8int main()
     9{
     10
     11    char* _args[4];
     12    char* _env[] = { "myenv=5", NULL };
     13
     14    _args[0] = "bash";
     15    _args[1] = "-c";
     16    _args[2] = "exit $myenv";
     17    _args[3] = NULL;
     18
     19    pid_t pid;
     20    int err = posix_spawnp(&pid, _args[0], NULL, NULL, _args, _env);
     21    printf("posix_spawnp: %d, %d\n", err, pid);
     22
     23    int status;
     24    pid_t waitpid_res = waitpid(pid, &status, 0);
     25    if (waitpid_res != pid)
     26        printf("posix_spawnp: waitpid didn't return pid\n");
     27
     28    printf("posix_spawnp: WIFEXITED(): %d, WEXITSTATUS() %d => 5\n",
     29        WIFEXITED(status), WEXITSTATUS(status));
     30
     31    _args[0] = "/tmp/toto";
     32    _args[1] = NULL;
     33
     34    err = posix_spawn(&pid, _args[0], NULL, NULL, _args, _env);
     35    printf("posix_spawn: %d, %d\n", err, pid);
     36
     37    if (err == 0) {
     38        waitpid_res = waitpid(pid, &status, 0);
     39        if (waitpid_res != pid)
     40            printf("posix_spawn: waitpid didn't return pid\n");
     41        printf("posix_spawn: WIFEXITED(): %d, WEXITSTATUS() %d => 127\n",
     42            WIFEXITED(status), WEXITSTATUS(status));
     43    } else {
     44        waitpid_res = waitpid(-1, NULL, 0);
     45        printf("posix_spawn: waitpid %d, %d\n", waitpid_res, errno);
     46    }
     47
     48    return 0;
     49}
     50