int Cmd::Start()

in ExecUtil.cpp [67:210]


int Cmd::Start() {
    if (_pid > 0) {
        return -EBUSY;
    }

    cleanup();

    int sigpipe[2];
    int inpipe[2] = {-1, -1};
    int outpipe[2] = {-1, -1};
    int errpipe[2] = {-1, -1};
    int ret = 0;

    ret = pipe2(sigpipe, O_CLOEXEC);
    if (ret != 0) {
        _fail_reason = FAILED_PIPE2;
        _errno = errno;
        return -errno;
    }

    if (STDIN_FLAGS(_flags) == PIPE_STDIN) {
        ret = pipe(inpipe);
        if (ret != 0) {
            _fail_reason = FAILED_PIPE;
            _errno = errno;
            return -errno;
        }
    }

    if (STDOUT_FLAGS(_flags) & PIPE_STDOUT) {
        ret = pipe(outpipe);
        if (ret != 0) {
            _fail_reason = FAILED_PIPE;
            _errno = errno;
            return -errno;
        }
    }

    if (STDERR_FLAGS(_flags) == PIPE_STDERR) {
        ret = pipe(errpipe);
        if (ret != 0) {
            _fail_reason = FAILED_PIPE;
            _errno = errno;
            return -errno;
        }
    }

    if ((_flags & COMBINE_OUTPUT) == COMBINE_OUTPUT) {
        errpipe[0] = outpipe[0];
        errpipe[1] = outpipe[1];
    }

    auto pid = fork();
    if (pid < 0) {
        _fail_reason = FAILED_FORK;
        _errno = errno;
        return -errno;
    }

    if (pid == 0) {
        close(sigpipe[_PIPE_READ]);
        char *args[_args.size()+2];
        args[0] = new char[_path.size()+1];
        _path.copy(args[0], _path.size());
        args[0][_path.size()] = 0;

        int idx = 1;
        for(auto& arg: _args) {
            args[idx] = new char[arg.size()+1];
            arg.copy(args[idx], arg.size());
            args[idx][arg.size()] = 0;
            idx++;
        }
        args[idx] = nullptr;

        if (inpipe[_PIPE_READ] != -1) {
            ret = dup2(inpipe[_PIPE_READ], 0);
            if (ret != 0) {
                write_error(FAILED_DUP2, errno, sigpipe[_PIPE_WRITE]);
                exit(1);
            }
        } else if (STDIN_FLAGS(_flags) == NULL_STDIN) {
            int in = open("/dev/null", O_RDONLY);
            if (in < 0) {
                write_error(FAILED_OPEN, errno, sigpipe[_PIPE_WRITE]);
                exit(1);
            }

            ret = dup2(in, 0);
            if (ret != 0) {
                write_error(FAILED_DUP2, errno, sigpipe[_PIPE_WRITE]);
                exit(1);
            }
        }

        if (outpipe[_PIPE_WRITE] != -1) {
            ret = dup2(outpipe[_PIPE_WRITE], 1);
            if (ret != 1) {
                write_error(FAILED_DUP2, errno, sigpipe[_PIPE_WRITE]);
                exit(1);
            }
        }

        if (errpipe[_PIPE_WRITE] != -1) {
            ret = dup2(errpipe[_PIPE_WRITE], 2);
            if (ret != 2) {
                write_error(FAILED_DUP2, errno, sigpipe[_PIPE_WRITE]);
                exit(1);
            }
        }

        ::execve(_path.c_str(), args, environ);
        write_error(FAILED_EXECVE, errno, sigpipe[_PIPE_WRITE]);
        exit(1);
    } else {
        _pid = pid;
        close(sigpipe[_PIPE_WRITE]);
        _stdin = inpipe[_PIPE_WRITE];
        _stdout = outpipe[_PIPE_READ];
        _stderr = errpipe[_PIPE_READ];
        if (inpipe[_PIPE_READ] != -1) {
            close(inpipe[_PIPE_READ]);
        }
        if (outpipe[_PIPE_WRITE] != -1) {
            close(outpipe[_PIPE_WRITE]);
        }
        if (errpipe[_PIPE_WRITE] != -1) {
            close(errpipe[_PIPE_WRITE]);
        }

        uint32_t code;
        // The return code is unimportant, the read will return once the child process exits or execs
        auto nr = read(sigpipe[_PIPE_READ], &code, sizeof(code));
        if (nr == sizeof(code)) {
            _fail_reason = static_cast<int>(code>>16);
            _errno = static_cast<int>(code&0xFFFF);
        } else {
            _fail_reason = 0;
            _errno = 0;
        }
        close(sigpipe[_PIPE_READ]);
        return (-_errno);
    }
}