Ejemplo n.º 1
0
TEST(spawn, posix_spawnattr_setpgroup_posix_spawnattr_getpgroup) {
  posix_spawnattr_t sa;
  ASSERT_EQ(0, posix_spawnattr_init(&sa));

  ASSERT_EQ(0, posix_spawnattr_setpgroup(&sa, 123));
  pid_t g;
  ASSERT_EQ(0, posix_spawnattr_getpgroup(&sa, &g));
  ASSERT_EQ(123, g);

  ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
}
Ejemplo n.º 2
0
static int l_posix_spawnattr_setpgroup(lua_State *L) {
	int r;
	posix_spawnattr_t *attr = luaL_checkudata(L, 1, "posix_spawnattr_t");
	pid_t pgroup = luaL_checkinteger(L, 2);
	if (0 != (r = posix_spawnattr_setpgroup(attr, pgroup))) {
		lua_pushnil(L);
		lua_pushstring(L, strerror(r));
		lua_pushinteger(L, r);
		return 3;
	}
	lua_pushboolean(L, 1);
	return 1;
}
Ejemplo n.º 3
0
TEST(spawn, posix_spawn_POSIX_SPAWN_SETPGROUP_set) {
  pid_t parent_pgrp = getpgrp();

  posix_spawnattr_t sa;
  ASSERT_EQ(0, posix_spawnattr_init(&sa));
  ASSERT_EQ(0, posix_spawnattr_setpgroup(&sa, 0));
  ASSERT_EQ(0, posix_spawnattr_setflags(&sa, POSIX_SPAWN_SETPGROUP));

  ProcStat ps = {};
  GetChildStat(&sa, &ps);
  ASSERT_NE(parent_pgrp, ps.pgrp);
  // Setting pgid 0 means "the same as the caller's pid".
  ASSERT_EQ(ps.pid, ps.pgrp);
  ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
}
Ejemplo n.º 4
0
int main()
{
	int		ret_err = 0;
	pid_t	pid_child;
	char	buf_err[64];
	char	*argv_child[] = {
		"forkexec_child", NULL
	};
	printf("Parent[%d]: Start\n", getpid());

	posix_spawnattr_t	posix_attr;
	if ((ret_err = posix_spawnattr_init(&posix_attr)) != 0) {
		strerror_r(ret_err, buf_err, sizeof(buf_err));
		fprintf(stderr, "Fail: attr_init: %s\n", buf_err);
		exit(EXIT_FAILURE);
	}
	short posix_flags = POSIX_SPAWN_SETPGROUP;
	if ((ret_err = posix_spawnattr_setflags(&posix_attr, posix_flags)) != 0) {
		strerror_r(ret_err, buf_err, sizeof(buf_err));
		fprintf(stderr, "Fail: attr_setflags: %s\n", buf_err);
		exit(EXIT_FAILURE);
	}

	// set pgid
	pid_t	pid_pgid = 0; /* child process shall become process group reader */
	if ((ret_err = posix_spawnattr_setpgroup(&posix_attr, pid_pgid)) != 0) {
		strerror_r(ret_err, buf_err, sizeof(buf_err));
		fprintf(stderr, "Fail: attr_setpgroup: %s\n", buf_err);
		exit(EXIT_FAILURE);
	}

	ret_err = posix_spawn( &pid_child,
			argv_child[0],
			NULL,
			&posix_attr,		/* attribute */
			argv_child,
			NULL);
	if ((ret_err = posix_spawnattr_destroy(&posix_attr)) != 0) {
		strerror_r(ret_err, buf_err, sizeof(buf_err));
		fprintf(stderr, "Fail: attr_destroy: %s\n", buf_err);
		exit(EXIT_FAILURE);
	}
	printf("Parent[%d]: Wait for child(%d)\n", getpid(), (int)pid_child);
	(void)wait(NULL);	/* wait for child */
	printf("Parent[%d]: Exit\n", getpid());
	return 0;
}
Ejemplo n.º 5
0
pid_t VG_REPLACE_FUNCTION_ZU(libastZdsoZd1, spawnveg)(const char *command,
                                                      char **argv,
                                                      char **envp,
                                                      pid_t pgid)
{
   int err = 0;
   pid_t pid;
   posix_spawnattr_t attr;
   int attr_init_done = 0;

   err = posix_spawnattr_init(&attr);
   if (err != 0)
      goto out;
   attr_init_done = 1;

   err = posix_spawnattr_init(&attr);
   if (err != 0)
      goto out;

   if (pgid != 0) {
      if (pgid <= 1)
         pgid = 0;
      err = posix_spawnattr_setpgroup(&attr, pgid);
      if (err != 0)
         goto out;
      err = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETPGROUP);
      if (err != 0)
         goto out;
   }

   err = posix_spawn(&pid, command, NULL, &attr, argv, envp ? envp : environ);

out:
   if (attr_init_done)
      posix_spawnattr_destroy(&attr);
   if (err != 0) {
      errno = err;
      return -1;
   }
   return pid;
}
Ejemplo n.º 6
0
pid_t
spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid)
{
	int			err;
	pid_t			pid;
	posix_spawnattr_t	attr;

	if (err = posix_spawnattr_init(&attr))
		goto nope;
	if (pgid)
	{
		if (pgid <= 1)
			pgid = 0;
		if (err = posix_spawnattr_setpgroup(&attr, pgid))
			goto bad;
		if (err = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETPGROUP))
			goto bad;
	}
	if (err = posix_spawn(&pid, path, NiL, &attr, argv, envv ? envv : environ))
		goto bad;
	posix_spawnattr_destroy(&attr);
#if _lib_posix_spawn < 2
	if (waitpid(pid, &err, WNOHANG|WNOWAIT) == pid && EXIT_STATUS(err) == 127)
	{
		while (waitpid(pid, NiL, 0) == -1 && errno == EINTR);
		if (!access(path, X_OK))
			errno = ENOEXEC;
		pid = -1;
	}
#endif
	return pid;
 bad:
	posix_spawnattr_destroy(&attr);
 nope:
	errno = err;
	return -1;
}
Ejemplo n.º 7
0
bool fork_actions_make_spawn_properties(posix_spawnattr_t *attr, posix_spawn_file_actions_t *actions, job_t *j, process_t *p, const io_chain_t &io_chain)
{
    /* Initialize the output */
    if (posix_spawnattr_init(attr) != 0)
    {
        return false;
    }

    if (posix_spawn_file_actions_init(actions) != 0)
    {
        posix_spawnattr_destroy(attr);
        return false;
    }

    bool should_set_parent_group_id = false;
    int desired_parent_group_id = 0;
    if (job_get_flag(j, JOB_CONTROL))
    {
        should_set_parent_group_id = true;

        // PCA: I'm quite fuzzy on process groups,
        // but I believe that the default value of 0
        // means that the process becomes its own
        // group leader, which is what set_child_group did
        // in this case. So we want this to be 0 if j->pgid is 0.
        desired_parent_group_id = j->pgid;
    }

    /* Set the handling for job control signals back to the default.  */
    bool reset_signal_handlers = true;

    /* Remove all signal blocks */
    bool reset_sigmask = true;

    /* Set our flags */
    short flags = 0;
    if (reset_signal_handlers)
        flags |= POSIX_SPAWN_SETSIGDEF;
    if (reset_sigmask)
        flags |= POSIX_SPAWN_SETSIGMASK;
    if (should_set_parent_group_id)
        flags |= POSIX_SPAWN_SETPGROUP;

    int err = 0;
    if (! err)
        err = posix_spawnattr_setflags(attr, flags);

    if (! err && should_set_parent_group_id)
        err = posix_spawnattr_setpgroup(attr, desired_parent_group_id);

    /* Everybody gets default handlers */
    if (! err && reset_signal_handlers)
    {
        sigset_t sigdefault;
        get_signals_with_handlers(&sigdefault);
        err = posix_spawnattr_setsigdefault(attr, &sigdefault);
    }

    /* No signals blocked */
    sigset_t sigmask;
    sigemptyset(&sigmask);
    if (! err && reset_sigmask)
        err = posix_spawnattr_setsigmask(attr, &sigmask);
    
    for (size_t idx = 0; idx < io_chain.size(); idx++)
    {
        const shared_ptr<const io_data_t> io = io_chain.at(idx);

        if (io->io_mode == IO_FD)
        {
            CAST_INIT(const io_fd_t *, io_fd, io.get());
            if (io->fd == io_fd->old_fd)
                continue;
        }

        switch (io->io_mode)
        {
            case IO_CLOSE:
            {
                if (! err)
                    err = posix_spawn_file_actions_addclose(actions, io->fd);
                break;
            }

            case IO_FILE:
            {
                CAST_INIT(const io_file_t *, io_file, io.get());
                if (! err)
                    err = posix_spawn_file_actions_addopen(actions, io->fd, io_file->filename_cstr, io_file->flags /* mode */, OPEN_MASK);
                break;
            }

            case IO_FD:
            {
                CAST_INIT(const io_fd_t *, io_fd, io.get());
                if (! err)
                    err = posix_spawn_file_actions_adddup2(actions, io_fd->old_fd /* from */, io->fd /* to */);
                break;
            }

            case IO_BUFFER:
            case IO_PIPE:
            {
                CAST_INIT(const io_pipe_t *, io_pipe, io.get());
                unsigned int write_pipe_idx = (io_pipe->is_input ? 0 : 1);
                int from_fd = io_pipe->pipe_fd[write_pipe_idx];
                int to_fd = io->fd;
                if (! err)
                    err = posix_spawn_file_actions_adddup2(actions, from_fd, to_fd);


                if (write_pipe_idx > 0)
                {
                    if (! err)
                        err = posix_spawn_file_actions_addclose(actions, io_pipe->pipe_fd[0]);
                    if (! err)
                        err = posix_spawn_file_actions_addclose(actions, io_pipe->pipe_fd[1]);
                }
                else
                {
                    if (! err)
                        err = posix_spawn_file_actions_addclose(actions, io_pipe->pipe_fd[0]);

                }
                break;
            }
        }
    }
Ejemplo n.º 8
0
RTR3DECL(int)   RTProcCreateEx(const char *pszExec, const char * const *papszArgs, RTENV hEnv, uint32_t fFlags,
                               PCRTHANDLE phStdIn, PCRTHANDLE phStdOut, PCRTHANDLE phStdErr, const char *pszAsUser,
                               const char *pszPassword, PRTPROCESS phProcess)
{
    int rc;

    /*
     * Input validation
     */
    AssertPtrReturn(pszExec, VERR_INVALID_POINTER);
    AssertReturn(*pszExec, VERR_INVALID_PARAMETER);
    AssertReturn(!(fFlags & ~RTPROC_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
    AssertReturn(!(fFlags & RTPROC_FLAGS_DETACHED) || !phProcess, VERR_INVALID_PARAMETER);
    AssertReturn(hEnv != NIL_RTENV, VERR_INVALID_PARAMETER);
    AssertPtrReturn(papszArgs, VERR_INVALID_PARAMETER);
    AssertPtrNullReturn(pszAsUser, VERR_INVALID_POINTER);
    AssertReturn(!pszAsUser || *pszAsUser, VERR_INVALID_PARAMETER);
    AssertReturn(!pszPassword || pszAsUser, VERR_INVALID_PARAMETER);
    AssertPtrNullReturn(pszPassword, VERR_INVALID_POINTER);
#if defined(RT_OS_OS2)
    if (fFlags & RTPROC_FLAGS_DETACHED)
        return VERR_PROC_DETACH_NOT_SUPPORTED;
#endif

    /*
     * Get the file descriptors for the handles we've been passed.
     */
    PCRTHANDLE  paHandles[3] = { phStdIn, phStdOut, phStdErr };
    int         aStdFds[3]   = {      -1,       -1,       -1 };
    for (int i = 0; i < 3; i++)
    {
        if (paHandles[i])
        {
            AssertPtrReturn(paHandles[i], VERR_INVALID_POINTER);
            switch (paHandles[i]->enmType)
            {
                case RTHANDLETYPE_FILE:
                    aStdFds[i] = paHandles[i]->u.hFile != NIL_RTFILE
                               ? (int)RTFileToNative(paHandles[i]->u.hFile)
                               : -2 /* close it */;
                    break;

                case RTHANDLETYPE_PIPE:
                    aStdFds[i] = paHandles[i]->u.hPipe != NIL_RTPIPE
                               ? (int)RTPipeToNative(paHandles[i]->u.hPipe)
                               : -2 /* close it */;
                    break;

                case RTHANDLETYPE_SOCKET:
                    aStdFds[i] = paHandles[i]->u.hSocket != NIL_RTSOCKET
                               ? (int)RTSocketToNative(paHandles[i]->u.hSocket)
                               : -2 /* close it */;
                    break;

                default:
                    AssertMsgFailedReturn(("%d: %d\n", i, paHandles[i]->enmType), VERR_INVALID_PARAMETER);
            }
            /** @todo check the close-on-execness of these handles?  */
        }
    }

    for (int i = 0; i < 3; i++)
        if (aStdFds[i] == i)
            aStdFds[i] = -1;

    for (int i = 0; i < 3; i++)
        AssertMsgReturn(aStdFds[i] < 0 || aStdFds[i] > i,
                        ("%i := %i not possible because we're lazy\n", i, aStdFds[i]),
                        VERR_NOT_SUPPORTED);

    /*
     * Resolve the user id if specified.
     */
    uid_t uid = ~(uid_t)0;
    gid_t gid = ~(gid_t)0;
    if (pszAsUser)
    {
        rc = rtCheckCredentials(pszAsUser, pszPassword, &gid, &uid);
        if (RT_FAILURE(rc))
            return rc;
    }

    /*
     * Create the child environment if either RTPROC_FLAGS_PROFILE or
     * RTPROC_FLAGS_ENV_CHANGE_RECORD are in effect.
     */
    RTENV hEnvToUse = hEnv;
    if (   (fFlags & (RTPROC_FLAGS_ENV_CHANGE_RECORD | RTPROC_FLAGS_PROFILE))
        && (   (fFlags & RTPROC_FLAGS_ENV_CHANGE_RECORD)
            || hEnv == RTENV_DEFAULT) )
    {
        if (fFlags & RTPROC_FLAGS_PROFILE)
            rc = rtProcPosixCreateProfileEnv(&hEnvToUse, pszAsUser);
        else
            rc = RTEnvClone(&hEnvToUse, RTENV_DEFAULT);
        if (RT_SUCCESS(rc))
        {
            if ((fFlags & RTPROC_FLAGS_ENV_CHANGE_RECORD) && hEnv != RTENV_DEFAULT)
                rc = RTEnvApplyChanges(hEnvToUse, hEnv);
            if (RT_FAILURE(rc))
                RTEnvDestroy(hEnvToUse);
        }
        if (RT_FAILURE(rc))
            return rc;
    }

    /*
     * Check for execute access to the file.
     */
    char szRealExec[RTPATH_MAX];
    if (access(pszExec, X_OK))
    {
        rc = errno;
        if (   !(fFlags & RTPROC_FLAGS_SEARCH_PATH)
            || rc != ENOENT
            || RTPathHavePath(pszExec) )
            rc = RTErrConvertFromErrno(rc);
        else
        {
            /* search */
            char *pszPath = RTEnvDupEx(hEnvToUse, "PATH");
            rc = RTPathTraverseList(pszPath, ':', rtPathFindExec, (void *)pszExec, &szRealExec[0]);
            RTStrFree(pszPath);
            if (RT_SUCCESS(rc))
                pszExec = szRealExec;
            else
                rc = rc == VERR_END_OF_STRING ? VERR_FILE_NOT_FOUND : rc;
        }

        if (RT_FAILURE(rc))
            return rtProcPosixCreateReturn(rc, hEnvToUse, hEnv);
    }

    pid_t pid = -1;
    const char * const *papszEnv = RTEnvGetExecEnvP(hEnvToUse);
    AssertPtrReturn(papszEnv, rtProcPosixCreateReturn(VERR_INVALID_HANDLE, hEnvToUse, hEnv));


    /*
     * Take care of detaching the process.
     *
     * HACK ALERT! Put the process into a new process group with pgid = pid
     * to make sure it differs from that of the parent process to ensure that
     * the IPRT waitpid call doesn't race anyone (read XPCOM) doing group wide
     * waits. setsid() includes the setpgid() functionality.
     * 2010-10-11 XPCOM no longer waits for anything, but it cannot hurt.
     */
#ifndef RT_OS_OS2
    if (fFlags & RTPROC_FLAGS_DETACHED)
    {
# ifdef RT_OS_SOLARIS
        int templateFd = -1;
        if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT))
        {
            templateFd = rtSolarisContractPreFork();
            if (templateFd == -1)
                return rtProcPosixCreateReturn(VERR_OPEN_FAILED, hEnvToUse, hEnv);
        }
# endif /* RT_OS_SOLARIS */
        pid = fork();
        if (!pid)
        {
# ifdef RT_OS_SOLARIS
            if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT))
                rtSolarisContractPostForkChild(templateFd);
# endif
            setsid(); /* see comment above */

            pid = -1;
            /* Child falls through to the actual spawn code below. */
        }
        else
        {
# ifdef RT_OS_SOLARIS
            if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT))
                rtSolarisContractPostForkParent(templateFd, pid);
# endif
            if (pid > 0)
            {
                /* Must wait for the temporary process to avoid a zombie. */
                int status = 0;
                pid_t pidChild = 0;

                /* Restart if we get interrupted. */
                do
                {
                    pidChild = waitpid(pid, &status, 0);
                } while (   pidChild == -1
                         && errno == EINTR);

                /* Assume that something wasn't found. No detailed info. */
                if (status)
                    return rtProcPosixCreateReturn(VERR_PROCESS_NOT_FOUND, hEnvToUse, hEnv);
                if (phProcess)
                    *phProcess = 0;
                return rtProcPosixCreateReturn(VINF_SUCCESS, hEnvToUse, hEnv);
            }
            return rtProcPosixCreateReturn(RTErrConvertFromErrno(errno), hEnvToUse, hEnv);
        }
    }
#endif

    /*
     * Spawn the child.
     *
     * Any spawn code MUST not execute any atexit functions if it is for a
     * detached process. It would lead to running the atexit functions which
     * make only sense for the parent. libORBit e.g. gets confused by multiple
     * execution. Remember, there was only a fork() so far, and until exec()
     * is successfully run there is nothing which would prevent doing anything
     * silly with the (duplicated) file descriptors.
     */
#ifdef HAVE_POSIX_SPAWN
    /** @todo OS/2: implement DETACHED (BACKGROUND stuff), see VbglR3Daemonize.  */
    if (   uid == ~(uid_t)0
        && gid == ~(gid_t)0)
    {
        /* Spawn attributes. */
        posix_spawnattr_t Attr;
        rc = posix_spawnattr_init(&Attr);
        if (!rc)
        {
            /* Indicate that process group and signal mask are to be changed,
               and that the child should use default signal actions. */
            rc = posix_spawnattr_setflags(&Attr, POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF);
            Assert(rc == 0);

            /* The child starts in its own process group. */
            if (!rc)
            {
                rc = posix_spawnattr_setpgroup(&Attr, 0 /* pg == child pid */);
                Assert(rc == 0);
            }

            /* Unmask all signals. */
            if (!rc)
            {
                sigset_t SigMask;
                sigemptyset(&SigMask);
                rc = posix_spawnattr_setsigmask(&Attr, &SigMask); Assert(rc == 0);
            }

            /* File changes. */
            posix_spawn_file_actions_t  FileActions;
            posix_spawn_file_actions_t *pFileActions = NULL;
            if ((aStdFds[0] != -1 || aStdFds[1] != -1 || aStdFds[2] != -1) && !rc)
            {
                rc = posix_spawn_file_actions_init(&FileActions);
                if (!rc)
                {
                    pFileActions = &FileActions;
                    for (int i = 0; i < 3; i++)
                    {
                        int fd = aStdFds[i];
                        if (fd == -2)
                            rc = posix_spawn_file_actions_addclose(&FileActions, i);
                        else if (fd >= 0 && fd != i)
                        {
                            rc = posix_spawn_file_actions_adddup2(&FileActions, fd, i);
                            if (!rc)
                            {
                                for (int j = i + 1; j < 3; j++)
                                    if (aStdFds[j] == fd)
                                    {
                                        fd = -1;
                                        break;
                                    }
                                if (fd >= 0)
                                    rc = posix_spawn_file_actions_addclose(&FileActions, fd);
                            }
                        }
                        if (rc)
                            break;
                    }
                }
            }

            if (!rc)
                rc = posix_spawn(&pid, pszExec, pFileActions, &Attr, (char * const *)papszArgs,
                                 (char * const *)papszEnv);

            /* cleanup */
            int rc2 = posix_spawnattr_destroy(&Attr); Assert(rc2 == 0); NOREF(rc2);
            if (pFileActions)
            {
                rc2 = posix_spawn_file_actions_destroy(pFileActions);
                Assert(rc2 == 0);
            }

            /* return on success.*/
            if (!rc)
            {
                /* For a detached process this happens in the temp process, so
                 * it's not worth doing anything as this process must exit. */
                if (fFlags & RTPROC_FLAGS_DETACHED)
                    _Exit(0);
                if (phProcess)
                    *phProcess = pid;
                return rtProcPosixCreateReturn(VINF_SUCCESS, hEnvToUse, hEnv);
            }
        }
        /* For a detached process this happens in the temp process, so
         * it's not worth doing anything as this process must exit. */
        if (fFlags & RTPROC_FLAGS_DETACHED)
            _Exit(124);
    }
    else
#endif
    {
#ifdef RT_OS_SOLARIS
        int templateFd = -1;
        if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT))
        {
            templateFd = rtSolarisContractPreFork();
            if (templateFd == -1)
                return rtProcPosixCreateReturn(VERR_OPEN_FAILED, hEnvToUse, hEnv);
        }
#endif /* RT_OS_SOLARIS */
        pid = fork();
        if (!pid)
        {
#ifdef RT_OS_SOLARIS
            if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT))
                rtSolarisContractPostForkChild(templateFd);
#endif /* RT_OS_SOLARIS */
            if (!(fFlags & RTPROC_FLAGS_DETACHED))
                setpgid(0, 0); /* see comment above */

            /*
             * Change group and user if requested.
             */
#if 1 /** @todo This needs more work, see suplib/hardening. */
            if (pszAsUser)
            {
                int ret = initgroups(pszAsUser, gid);
                if (ret)
                {
                    if (fFlags & RTPROC_FLAGS_DETACHED)
                        _Exit(126);
                    else
                        exit(126);
                }
            }
            if (gid != ~(gid_t)0)
            {
                if (setgid(gid))
                {
                    if (fFlags & RTPROC_FLAGS_DETACHED)
                        _Exit(126);
                    else
                        exit(126);
                }
            }

            if (uid != ~(uid_t)0)
            {
                if (setuid(uid))
                {
                    if (fFlags & RTPROC_FLAGS_DETACHED)
                        _Exit(126);
                    else
                        exit(126);
                }
            }
#endif

            /*
             * Some final profile environment tweaks, if running as user.
             */
            if (   (fFlags & RTPROC_FLAGS_PROFILE)
                && pszAsUser
                && (   (fFlags & RTPROC_FLAGS_ENV_CHANGE_RECORD)
                    || hEnv == RTENV_DEFAULT) )
            {
                rc = rtProcPosixAdjustProfileEnvFromChild(hEnvToUse, fFlags, hEnv);
                papszEnv = RTEnvGetExecEnvP(hEnvToUse);
                if (RT_FAILURE(rc) || !papszEnv)
                {
                    if (fFlags & RTPROC_FLAGS_DETACHED)
                        _Exit(126);
                    else
                        exit(126);
                }
            }

            /*
             * Unset the signal mask.
             */
            sigset_t SigMask;
            sigemptyset(&SigMask);
            rc = sigprocmask(SIG_SETMASK, &SigMask, NULL);
            Assert(rc == 0);

            /*
             * Apply changes to the standard file descriptor and stuff.
             */
            for (int i = 0; i < 3; i++)
            {
                int fd = aStdFds[i];
                if (fd == -2)
                    close(i);
                else if (fd >= 0)
                {
                    int rc2 = dup2(fd, i);
                    if (rc2 != i)
                    {
                        if (fFlags & RTPROC_FLAGS_DETACHED)
                            _Exit(125);
                        else
                            exit(125);
                    }
                    for (int j = i + 1; j < 3; j++)
                        if (aStdFds[j] == fd)
                        {
                            fd = -1;
                            break;
                        }
                    if (fd >= 0)
                        close(fd);
                }
            }

            /*
             * Finally, execute the requested program.
             */
            rc = execve(pszExec, (char * const *)papszArgs, (char * const *)papszEnv);
            if (errno == ENOEXEC)
            {
                /* This can happen when trying to start a shell script without the magic #!/bin/sh */
                RTAssertMsg2Weak("Cannot execute this binary format!\n");
            }
            else
                RTAssertMsg2Weak("execve returns %d errno=%d\n", rc, errno);
            RTAssertReleasePanic();
            if (fFlags & RTPROC_FLAGS_DETACHED)
                _Exit(127);
            else
                exit(127);
        }
#ifdef RT_OS_SOLARIS
        if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT))
            rtSolarisContractPostForkParent(templateFd, pid);
#endif /* RT_OS_SOLARIS */
        if (pid > 0)
        {
            /* For a detached process this happens in the temp process, so
             * it's not worth doing anything as this process must exit. */
            if (fFlags & RTPROC_FLAGS_DETACHED)
                _Exit(0);
            if (phProcess)
                *phProcess = pid;
            return rtProcPosixCreateReturn(VINF_SUCCESS, hEnvToUse, hEnv);
        }
        /* For a detached process this happens in the temp process, so
         * it's not worth doing anything as this process must exit. */
        if (fFlags & RTPROC_FLAGS_DETACHED)
            _Exit(124);
        return rtProcPosixCreateReturn(RTErrConvertFromErrno(errno), hEnvToUse, hEnv);
    }

    return rtProcPosixCreateReturn(VERR_NOT_IMPLEMENTED, hEnvToUse, hEnv);
}
Ejemplo n.º 9
0
int					/* O - Process ID or 0 */
cupsdStartProcess(
    const char  *command,		/* I - Full path to command */
    char        *argv[],		/* I - Command-line arguments */
    char        *envp[],		/* I - Environment */
    int         infd,			/* I - Standard input file descriptor */
    int         outfd,			/* I - Standard output file descriptor */
    int         errfd,			/* I - Standard error file descriptor */
    int         backfd,			/* I - Backchannel file descriptor */
    int         sidefd,			/* I - Sidechannel file descriptor */
    int         root,			/* I - Run as root? */
    void        *profile,		/* I - Security profile to use */
    cupsd_job_t *job,			/* I - Job associated with process */
    int         *pid)			/* O - Process ID */
{
  int		i;			/* Looping var */
  const char	*exec_path = command;	/* Command to be exec'd */
  char		*real_argv[110],	/* Real command-line arguments */
		cups_exec[1024],	/* Path to "cups-exec" program */
		user_str[16],		/* User string */
		group_str[16],		/* Group string */
		nice_str[16];		/* FilterNice string */
  uid_t		user;			/* Command UID */
  cupsd_proc_t	*proc;			/* New process record */
#if USE_POSIX_SPAWN
  posix_spawn_file_actions_t actions;	/* Spawn file actions */
  posix_spawnattr_t attrs;		/* Spawn attributes */
  sigset_t	defsignals;		/* Default signals */
#elif defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
  struct sigaction action;		/* POSIX signal handler */
#endif /* USE_POSIX_SPAWN */
#if defined(__APPLE__)
  char		processPath[1024],	/* CFProcessPath environment variable */
		linkpath[1024];		/* Link path for symlinks... */
  int		linkbytes;		/* Bytes for link path */
#endif /* __APPLE__ */


  *pid = 0;

 /*
  * Figure out the UID for the child process...
  */

  if (RunUser)
    user = RunUser;
  else if (root)
    user = 0;
  else
    user = User;

 /*
  * Check the permissions of the command we are running...
  */

  if (_cupsFileCheck(command, _CUPS_FILE_CHECK_PROGRAM, !RunUser,
                     cupsdLogFCMessage, job ? job->printer : NULL))
    return (0);

#if defined(__APPLE__)
  if (envp)
  {
   /*
    * Add special voodoo magic for OS X - this allows OS X programs to access
    * their bundle resources properly...
    */

    if ((linkbytes = readlink(command, linkpath, sizeof(linkpath) - 1)) > 0)
    {
     /*
      * Yes, this is a symlink to the actual program, nul-terminate and
      * use it...
      */

      linkpath[linkbytes] = '\0';

      if (linkpath[0] == '/')
	snprintf(processPath, sizeof(processPath), "CFProcessPath=%s",
		 linkpath);
      else
	snprintf(processPath, sizeof(processPath), "CFProcessPath=%s/%s",
		 dirname((char *)command), linkpath);
    }
    else
      snprintf(processPath, sizeof(processPath), "CFProcessPath=%s", command);

    envp[0] = processPath;		/* Replace <CFProcessPath> string */
  }
#endif	/* __APPLE__ */

 /*
  * Use helper program when we have a sandbox profile...
  */

#if !USE_POSIX_SPAWN
  if (profile)
#endif /* !USE_POSIX_SPAWN */
  {
    snprintf(cups_exec, sizeof(cups_exec), "%s/daemon/cups-exec", ServerBin);
    snprintf(user_str, sizeof(user_str), "%d", user);
    snprintf(group_str, sizeof(group_str), "%d", Group);
    snprintf(nice_str, sizeof(nice_str), "%d", FilterNice);

    real_argv[0] = cups_exec;
    real_argv[1] = (char *)"-g";
    real_argv[2] = group_str;
    real_argv[3] = (char *)"-n";
    real_argv[4] = nice_str;
    real_argv[5] = (char *)"-u";
    real_argv[6] = user_str;
    real_argv[7] = profile ? profile : "none";
    real_argv[8] = (char *)command;

    for (i = 0;
         i < (int)(sizeof(real_argv) / sizeof(real_argv[0]) - 10) && argv[i];
	 i ++)
      real_argv[i + 9] = argv[i];

    real_argv[i + 9] = NULL;

    argv      = real_argv;
    exec_path = cups_exec;
  }

  if (LogLevel == CUPSD_LOG_DEBUG2)
  {
    cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartProcess: Preparing to start \"%s\", arguments:", command);

    for (i = 0; argv[i]; i ++)
      cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartProcess: argv[%d] = \"%s\"", i, argv[i]);
  }

#if USE_POSIX_SPAWN
 /*
  * Setup attributes and file actions for the spawn...
  */

  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartProcess: Setting spawn attributes.");
  sigemptyset(&defsignals);
  sigaddset(&defsignals, SIGTERM);
  sigaddset(&defsignals, SIGCHLD);
  sigaddset(&defsignals, SIGPIPE);

  posix_spawnattr_init(&attrs);
  posix_spawnattr_setflags(&attrs, POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_SETSIGDEF);
  posix_spawnattr_setpgroup(&attrs, 0);
  posix_spawnattr_setsigdefault(&attrs, &defsignals);

  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartProcess: Setting file actions.");
  posix_spawn_file_actions_init(&actions);
  if (infd != 0)
  {
    if (infd < 0)
      posix_spawn_file_actions_addopen(&actions, 0, "/dev/null", O_RDONLY, 0);
    else
      posix_spawn_file_actions_adddup2(&actions, infd, 0);
  }

  if (outfd != 1)
  {
    if (outfd < 0)
      posix_spawn_file_actions_addopen(&actions, 1, "/dev/null", O_WRONLY, 0);
    else
      posix_spawn_file_actions_adddup2(&actions, outfd, 1);
  }

  if (errfd != 2)
  {
    if (errfd < 0)
      posix_spawn_file_actions_addopen(&actions, 2, "/dev/null", O_WRONLY, 0);
    else
      posix_spawn_file_actions_adddup2(&actions, errfd, 2);
  }

  if (backfd != 3 && backfd >= 0)
    posix_spawn_file_actions_adddup2(&actions, backfd, 3);

  if (sidefd != 4 && sidefd >= 0)
    posix_spawn_file_actions_adddup2(&actions, sidefd, 4);

  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartProcess: Calling posix_spawn.");

  if (posix_spawn(pid, exec_path, &actions, &attrs, argv, envp ? envp : environ))
  {
    cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to fork %s - %s.", command, strerror(errno));

    *pid = 0;
  }
  else
    cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartProcess: pid=%d", (int)*pid);

  posix_spawn_file_actions_destroy(&actions);
  posix_spawnattr_destroy(&attrs);

#else
 /*
  * Block signals before forking...
  */

  cupsdHoldSignals();

  if ((*pid = fork()) == 0)
  {
   /*
    * Child process goes here; update stderr as needed...
    */

    if (errfd != 2)
    {
      if (errfd < 0)
        errfd = open("/dev/null", O_WRONLY);

      if (errfd != 2)
      {
        dup2(errfd, 2);
	close(errfd);
      }
    }

   /*
    * Put this process in its own process group so that we can kill any child
    * processes it creates.
    */

#  ifdef HAVE_SETPGID
    if (!RunUser && setpgid(0, 0))
      exit(errno + 100);
#  else
    if (!RunUser && setpgrp())
      exit(errno + 100);
#  endif /* HAVE_SETPGID */

   /*
    * Update the remaining file descriptors as needed...
    */

    if (infd != 0)
    {
      if (infd < 0)
        infd = open("/dev/null", O_RDONLY);

      if (infd != 0)
      {
        dup2(infd, 0);
	close(infd);
      }
    }

    if (outfd != 1)
    {
      if (outfd < 0)
        outfd = open("/dev/null", O_WRONLY);

      if (outfd != 1)
      {
        dup2(outfd, 1);
	close(outfd);
      }
    }

    if (backfd != 3 && backfd >= 0)
    {
      dup2(backfd, 3);
      close(backfd);
      fcntl(3, F_SETFL, O_NDELAY);
    }

    if (sidefd != 4 && sidefd >= 0)
    {
      dup2(sidefd, 4);
      close(sidefd);
      fcntl(4, F_SETFL, O_NDELAY);
    }

   /*
    * Change the priority of the process based on the FilterNice setting.
    * (this is not done for root processes...)
    */

    if (!root)
      nice(FilterNice);

   /*
    * Reset group membership to just the main one we belong to.
    */

    if (!RunUser && setgid(Group))
      exit(errno + 100);

    if (!RunUser && setgroups(1, &Group))
      exit(errno + 100);

   /*
    * Change user to something "safe"...
    */

    if (!RunUser && user && setuid(user))
      exit(errno + 100);

   /*
    * Change umask to restrict permissions on created files...
    */

    umask(077);

   /*
    * Unblock signals before doing the exec...
    */

#  ifdef HAVE_SIGSET
    sigset(SIGTERM, SIG_DFL);
    sigset(SIGCHLD, SIG_DFL);
    sigset(SIGPIPE, SIG_DFL);
#  elif defined(HAVE_SIGACTION)
    memset(&action, 0, sizeof(action));

    sigemptyset(&action.sa_mask);
    action.sa_handler = SIG_DFL;

    sigaction(SIGTERM, &action, NULL);
    sigaction(SIGCHLD, &action, NULL);
    sigaction(SIGPIPE, &action, NULL);
#  else
    signal(SIGTERM, SIG_DFL);
    signal(SIGCHLD, SIG_DFL);
    signal(SIGPIPE, SIG_DFL);
#  endif /* HAVE_SIGSET */

    cupsdReleaseSignals();

   /*
    * Execute the command; if for some reason this doesn't work, log an error
    * exit with a non-zero value...
    */

    if (envp)
      execve(exec_path, argv, envp);
    else
      execv(exec_path, argv);

    exit(errno + 100);
  }
  else if (*pid < 0)
  {
   /*
    * Error - couldn't fork a new process!
    */

    cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to fork %s - %s.", command,
                    strerror(errno));

    *pid = 0;
  }

  cupsdReleaseSignals();
#endif /* USE_POSIX_SPAWN */

  if (*pid)
  {
    if (!process_array)
      process_array = cupsArrayNew((cups_array_func_t)compare_procs, NULL);

    if (process_array)
    {
      if ((proc = calloc(1, sizeof(cupsd_proc_t) + strlen(command))) != NULL)
      {
        proc->pid    = *pid;
	proc->job_id = job ? job->id : 0;
	_cups_strcpy(proc->name, command);

	cupsArrayAdd(process_array, proc);
      }
    }
  }

  cupsdLogMessage(CUPSD_LOG_DEBUG2,
		  "cupsdStartProcess(command=\"%s\", argv=%p, envp=%p, "
		  "infd=%d, outfd=%d, errfd=%d, backfd=%d, sidefd=%d, root=%d, "
		  "profile=%p, job=%p(%d), pid=%p) = %d",
		  command, argv, envp, infd, outfd, errfd, backfd, sidefd,
		  root, profile, job, job ? job->id : 0, pid, *pid);

  return (*pid);
}
int main(void)
{
  posix_spawnattr_setpgroup(0, 0);
  return 0;
}
Ejemplo n.º 11
0
Archivo: spawnvex.c Proyecto: att/ast
pid_t spawnvex(const char *path, char *const argv[], char *const envv[], Spawnvex_t *vex) {
    int i;
    int op;
    unsigned int flags = 0;
    pid_t pid;
    int arg;
    int err;
    int fd;
    posix_spawnattr_t ax;
    posix_spawn_file_actions_t fx;
    Spawnvex_t *xev = NULL;
#if _lib_spawn_mode || _lib_spawn && _mem_pgroup_inheritance
    pid_t pgid;
    int arg;
    int j;
    int k;
    int m;
    int ic;
    int jc;
    Spawnvex_t *xev;
#if !_lib_spawn_mode
    int *map;
    int a;
    struct inheritance inherit;
#endif
#endif

    if (vex && vex->debug >= 0) {
        error(ERROR_OUTPUT, vex->debug, "spawnvex exe %4d %8d %p %4d \"%s\"", __LINE__, getpid(),
              vex, vex->cur, path);
    }
#if _lib_spawn_mode || _lib_spawn && _mem_pgroup_inheritance
    if (!envv) envv = environ;
    pid = -1;
    m = 0;
    if (vex) {
        vex->noexec = -1;
        vex->pgrp = -1;
        flags = vex->flags;
        if (!(xev = spawnvex_open(0))) goto bad;
        j = -1;
        for (i = 0; i < vex->cur;) {
            op = vex->op[i++].number;
            arg = vex->op[i++].number;
            if (op & 1) i += 2;
            op /= 2;
            if (op >= 0) {
                if (m < op) m = op + 1;
                if (m < arg) m = arg + 1;
            } else if (op == SPAWN_cwd)
                j = arg;
        }
        if (j >= 0) {
            if ((i = open(".", O_RDONLY)) < 0) goto bad;
            if ((i = save(i, &ic, m)) < 0) goto bad;
            if (spawnvex_add(xev, SPAWN_cwd, i, 0, 0) < 0 || restore(xev, i, -1, 0) < 0) {
                close(i);
                goto bad;
            }
            if (fchdir(j) < 0) goto bad;
            if ((i = save(j, &jc, m)) < 0) goto bad;
            if (restore(xev, i, j, jc) < 0) {
                close(i);
                goto bad;
            }
        }
    } else {
        flags = 0;
        xev = NULL;
    }
#if _lib_spawn_mode
    if (vex)
        for (i = 0; i < vex->cur;) {
            op = vex->op[i++].number;
            arg = vex->op[i++].number;
            if (op & 1) i += 2;
            switch (op /= 2) {
                case SPAWN_frame:
                    vex->frame = (unsigned int)arg;
                    break;
                case SPAWN_pgrp:
                    vex->pgrp = (pid_t)arg;
                    break;
                default:
                    if (op >= 0) {
                        if (arg < 0) {
                            if ((i = save(op, &ic, m)) < 0) {
                                if (i < -1) goto bad;
                            } else if (restore(xev, i, op, ic) < 0) {
                                close(i);
                                goto bad;
                            } else
                                close(op);
                        } else if (arg == op) {
                            if (spawnvex_add(xev, SPAWN_cloexec, arg, 0, 0) < 0) goto bad;
                            if (fcntl(arg, F_SETFD, 0) < 0) goto bad;
                        } else if ((j = save(arg, &jc, m)) < -1)
                            goto bad;
                        else {
                            close(arg);
                            if (fcntl(op, F_DUPFD, arg) >= 0) {
                                if ((i = save(op, &ic, m)) >= 0) {
                                    if (restore(xev, i, op, ic) >= 0) {
                                        close(op);
                                        if (j < 0 || restore(xev, j, arg, jc) >= 0) continue;
                                    }
                                    close(i);
                                }
                            }
                            if (j >= 0) {
                                fcntl(j, F_DUPFD, arg);
                                close(j);
                            }
                            goto bad;
                        }
                    }
                    break;
            }
        }
    pid = spawnve(vex && vex->pgrp >= 0 ? P_DETACH : P_NOWAIT, path, argv, envv);
#else
    inherit.flags = 0;
    map = 0;
    if (vex) {
        if (m) {
            map = calloc(1, m * sizeof(int));
            if (!map) goto bad;
            for (i = 0; i < m; i++) map[i] = i;
        }
        for (i = 0; i < vex->cur;) {
            op = vex->op[i++].number;
            a = i;
            arg = vex->op[i++].number;
            if (op & 1) i += 2;
            switch (op /= 2) {
                case SPAWN_noop:
                    break;
                case SPAWN_noexec:
                    break;
                case SPAWN_frame:
                    vex->frame = (unsigned int)arg;
                    break;
                case SPAWN_pgrp:
                    inherit.flags |= SPAWN_SETGROUP;
                    inherit.pgroup = arg ? arg : SPAWN_NEWPGROUP;
                    break;
                case SPAWN_sigdef:
                    inherit.flags |= SPAWN_SETSIGDEF;
                    sigemptyset(&inherit.sigdefault);
                    for (j = 1; j < 8 * sizeof(vex->op[a].number); j++)
                        if (vex->op[a].number & (1 << j)) sigaddset(&inherit.sigdefault, j);
                    break;
                case SPAWN_sigmask:
                    inherit.flags |= SPAWN_SETSIGMASK;
                    sigemptyset(&inherit.sigmask);
                    for (j = 1; j < 8 * sizeof(vex->op[a].number); j++)
                        if (vex->op[a].number & (1 << j)) sigaddset(&inherit.sigmask, j);
                    break;
                default:
                    if (op < 0) {
                        errno = EINVAL;
                        goto bad;
                    } else if (arg < 0)
                        map[op] = SPAWN_FDCLOSED;
                    else
                        map[op] = arg;
                    break;
            }
        }
    }
    pid = spawn(path, m, map, &inherit, (const char **)argv, (const char **)envv);
#endif
    if (pid >= 0 && vex) VEXINIT(vex);
bad:
    if (xev) {
        spawnvex_apply(xev, 0, SPAWN_FLUSH | SPAWN_NOCALL);
        spawnvex_close(xev);
    }
#if !_lib_spawn_mode
    if (map) free(map);
#endif
    return pid;

#else

#if _lib_spawnve
    if (!vex || !vex->cur && !vex->flags) return spawnve(path, argv, envv);
#endif
    if (vex && ((vex->set & (0
#if !_lib_posix_spawnattr_setfchdir
                             | VEXFLAG(SPAWN_cwd)
#endif
#if !_lib_posix_spawnattr_setsid
                             | VEXFLAG(SPAWN_sid)
#endif
#if !_lib_posix_spawnattr_setumask
                             | VEXFLAG(SPAWN_umask)
#endif
                                 ))
#if !_lib_posix_spawn
                || !(vex->flags & SPAWN_EXEC)
#endif
                    )) {
        int n;
        int m;
        Spawnvex_noexec_t nx;
        int msg[2];

        if (!envv) envv = environ;
        n = errno;
        if (pipe(msg) < 0) {
            msg[0] = msg[1] = -1;
        } else {
            (void)fcntl(msg[0], F_SETFD, FD_CLOEXEC);
            (void)fcntl(msg[1], F_SETFD, FD_CLOEXEC);
        }
        if (!(flags & SPAWN_FOREGROUND)) sigcritical(SIG_REG_EXEC | SIG_REG_PROC);
        pid = fork();
        if (pid == -1) {
            n = errno;
        } else if (!pid) {
            if (!(flags & SPAWN_FOREGROUND)) sigcritical(SIG_REG_POP);
            if (vex && (n = spawnvex_apply(vex, 0, SPAWN_FRAME | SPAWN_NOCALL))) {
                errno = n;
            } else {
                if (vex && vex->debug >= 0) {
                    error(ERROR_OUTPUT, vex->debug, "spawnvex exe %4d %8d %p %4d \"%s\"", __LINE__,
                          getpid(), vex, vex->cur, path);
                }
                execve(path, argv, envv);
                if (vex && vex->debug >= 0) {
                    error(ERROR_OUTPUT, vex->debug, "spawnvex exe %4d %8d %p %4d \"%s\" FAILED",
                          __LINE__, getpid(), vex, vex->cur, path);
                }
                if (vex && (i = vex->noexec) >= 0) {
                    nx.vex = vex;
                    nx.handle = vex->op[i + 3].handle;
                    nx.path = path;
                    nx.argv = argv;
                    nx.envv = envv;
#if _use_spawn_exec
                    /*
                     * setting SPAWN_EXEC here means that it is more efficient to
                     * exec(interpreter) on script than to fork() initialize and
                     * read script -- highly subjective, based on some ksh
                     * implementaions, and probably won't be set unless its a
                     * noticable win
                     */

                    nx.flags |= SPAWN_EXEC;
#endif
                    nx.msgfd = msg[1];
                    errno = (*vex->op[i + 2].callback)(&nx, SPAWN_noexec, errno);
                }
            }
            if (msg[1] != -1) {
                m = errno;
                write(msg[1], &m, sizeof(m));
            }
            _exit(errno == ENOENT ? EXIT_NOTFOUND : EXIT_NOEXEC);
        }
        if (msg[0] != -1) {
            close(msg[1]);
            if (pid != -1) {
                m = 0;
                while (read(msg[0], &m, sizeof(m)) == -1) {
                    if (errno != EINTR) {
                        m = errno;
                        break;
                    }
                }
                if (m) {
                    while (waitpid(pid, &n, 0) && errno == EINTR) {
                        ;
                    }
                    pid = -1;
                    n = m;
                }
            }
            close(msg[0]);
        }
        if (!(flags & SPAWN_FOREGROUND)) sigcritical(SIG_REG_POP);
        if (pid != -1 && vex) VEXINIT(vex);
        errno = n;
        return pid;
    }
    if (vex) {
        err = posix_spawnattr_init(&ax);
        if (err) goto nope;
        err = posix_spawn_file_actions_init(&fx);
        if (err) {
            posix_spawnattr_destroy(&ax);
            goto nope;
        }
        for (i = 0; i < vex->cur;) {
            op = vex->op[i++].number;
            arg = vex->op[i++].number;
            if (op & 1) i += 2;
            switch (op /= 2) {
                case SPAWN_noop:
                    break;
                case SPAWN_noexec:
                    break;
                case SPAWN_frame:
                    break;
#if _lib_posix_spawnattr_setfchdir
                case SPAWN_cwd:
                    err = posix_spawnattr_setfchdir(&ax, arg);
                    if (err) goto bad;
                    break;
#endif
                case SPAWN_pgrp:
                    err = posix_spawnattr_setpgroup(&ax, arg);
                    if (err) goto bad;
                    err = posix_spawnattr_setflags(&ax, POSIX_SPAWN_SETPGROUP);
                    if (err) goto bad;
                    break;
                case SPAWN_resetids:
                    err = posix_spawnattr_setflags(&ax, POSIX_SPAWN_RESETIDS);
                    if (err) goto bad;
                    break;
#if _lib_posix_spawnattr_setsid
                case SPAWN_sid:
                    err = posix_spawnattr_setsid(&ax, arg);
                    if (err) goto bad;
                    break;
#endif
                case SPAWN_sigdef:
                    break;
                case SPAWN_sigmask:
                    break;
#if _lib_posix_spawnattr_setumask
                case SPAWN_umask:
                    if (err = posix_spawnattr_setumask(&ax, arg)) goto bad;
                    break;
#endif
                default:
                    if (op < 0) {
                        err = EINVAL;
                        goto bad;
                    } else if (arg < 0) {
                        err = posix_spawn_file_actions_addclose(&fx, op);
                        if (err) goto bad;
                    } else if (arg == op) {
#ifdef F_DUPFD_CLOEXEC
                        if ((fd = fcntl(op, F_DUPFD_CLOEXEC, 0)) < 0)
#else
                        if ((fd = fcntl(op, F_DUPFD, 0)) < 0 ||
                            fcntl(fd, F_SETFD, FD_CLOEXEC) < 0 && (close(fd), 1))
#endif
                        {
                            err = errno;
                            goto bad;
                        }
                        if (!xev && !(xev = spawnvex_open(0))) goto bad;
                        spawnvex_add(xev, fd, -1, 0, 0);
                        err = posix_spawn_file_actions_adddup2(&fx, fd, op);
                        if (err) goto bad;
                    } else {
                        err = posix_spawn_file_actions_adddup2(&fx, op, arg);
                        if (err) goto bad;
                    }
                    break;
            }
        }

        // Ensure stdin, stdout, stderr are open in the child process.
        // See https://github.com/att/ast/issues/1117.
        for (int fd = 0; fd < 3; ++fd) {
            errno = 0;
            if (fcntl(fd, F_GETFD, NULL) == -1 || errno == EBADF) {
                err = posix_spawn_file_actions_addopen(&fx, fd, "/dev/null", O_RDWR, 0);
                if (err) goto bad;
            }
        }

        err = posix_spawn(&pid, path, &fx, &ax, argv, envv ? envv : environ);
        if (err) goto bad;
        posix_spawnattr_destroy(&ax);
        posix_spawn_file_actions_destroy(&fx);
        if (xev) {
            spawnvex_apply(xev, 0, SPAWN_NOCALL);
            spawnvex_close(xev);
        }
        if (vex->flags & SPAWN_CLEANUP) spawnvex_apply(vex, 0, SPAWN_FRAME | SPAWN_CLEANUP);
        VEXINIT(vex);
    } else {
        err = posix_spawn(&pid, path, NULL, NULL, argv, envv ? envv : environ);
        if (err) goto nope;
    }
    if (vex && vex->debug >= 0) {
        error(ERROR_OUTPUT, vex->debug, "spawnvex exe %4d %8d %p %4d \"%s\" %8d posix_spawn",
              __LINE__, getpid(), vex, vex->cur, path, pid);
    }
    return pid;
bad:
    posix_spawnattr_destroy(&ax);
    posix_spawn_file_actions_destroy(&fx);
    if (xev) {
        spawnvex_apply(xev, 0, SPAWN_NOCALL);
        spawnvex_close(xev);
    }
nope:
    errno = err;
    if (vex && vex->debug >= 0) {
        error(ERROR_OUTPUT, vex->debug, "spawnvex exe %4d %8d %p %4d \"%s\" %8d posix_spawn FAILED",
              __LINE__, getpid(), vex, vex->cur, path, -1);
    }
    return -1;
#endif
}
Ejemplo n.º 12
0
N_NIMCALL(pid_t, startprocessauxspawn_145001)(Tstartprocessdata144948* data) {
	pid_t result;
	posix_spawnattr_t attr;
	posix_spawn_file_actions_t fops;
	sigset_t mask;
	int res;
	pid_t pid;
	int LOC98;
	int LOC99;
{	result = 0;
	memset((void*)(&attr), 0, sizeof(attr));
	memset((void*)(&fops), 0, sizeof(fops));
	{
		int LOC3;
		NI32 LOC6;
		LOC3 = 0;
		LOC3 = posix_spawn_file_actions_init((&fops));
		if (!!((LOC3 == ((NI32) 0)))) goto LA4;
		LOC6 = 0;
		LOC6 = oslasterror_117033();
		raiseoserror_117009(LOC6);
	}
	LA4: ;
	{
		int LOC9;
		NI32 LOC12;
		LOC9 = 0;
		LOC9 = posix_spawnattr_init((&attr));
		if (!!((LOC9 == ((NI32) 0)))) goto LA10;
		LOC12 = 0;
		LOC12 = oslasterror_117033();
		raiseoserror_117009(LOC12);
	}
	LA10: ;
	memset((void*)(&mask), 0, sizeof(mask));
	{
		int LOC15;
		NI32 LOC18;
		LOC15 = 0;
		LOC15 = sigemptyset((&mask));
		if (!!((LOC15 == ((NI32) 0)))) goto LA16;
		LOC18 = 0;
		LOC18 = oslasterror_117033();
		raiseoserror_117009(LOC18);
	}
	LA16: ;
	{
		int LOC21;
		NI32 LOC24;
		LOC21 = 0;
		LOC21 = posix_spawnattr_setsigmask((&attr), (&mask));
		if (!!((LOC21 == ((NI32) 0)))) goto LA22;
		LOC24 = 0;
		LOC24 = oslasterror_117033();
		raiseoserror_117009(LOC24);
	}
	LA22: ;
	{
		int LOC27;
		NI32 LOC30;
		LOC27 = 0;
		LOC27 = posix_spawnattr_setpgroup((&attr), ((pid_t) 0));
		if (!!((LOC27 == ((NI32) 0)))) goto LA28;
		LOC30 = 0;
		LOC30 = oslasterror_117033();
		raiseoserror_117009(LOC30);
	}
	LA28: ;
	{
		int LOC33;
		NI32 LOC36;
		LOC33 = 0;
		LOC33 = posix_spawnattr_setflags((&attr), (NI32)((NI32)(((int) 0) | POSIX_SPAWN_SETSIGMASK) | POSIX_SPAWN_SETPGROUP));
		if (!!((LOC33 == ((NI32) 0)))) goto LA34;
		LOC36 = 0;
		LOC36 = oslasterror_117033();
		raiseoserror_117009(LOC36);
	}
	LA34: ;
	{
		if (!!((*data).optionpoparentstreams)) goto LA39;
		{
			int LOC43;
			NI32 LOC46;
			LOC43 = 0;
			LOC43 = posix_spawn_file_actions_addclose((&fops), (*data).pstdin[(((NI) 1))- 0]);
			if (!!((LOC43 == ((NI32) 0)))) goto LA44;
			LOC46 = 0;
			LOC46 = oslasterror_117033();
			raiseoserror_117009(LOC46);
		}
		LA44: ;
		{
			int LOC49;
			NI32 LOC52;
			LOC49 = 0;
			LOC49 = posix_spawn_file_actions_adddup2((&fops), (*data).pstdin[(((NI) 0))- 0], ((int) 0));
			if (!!((LOC49 == ((NI32) 0)))) goto LA50;
			LOC52 = 0;
			LOC52 = oslasterror_117033();
			raiseoserror_117009(LOC52);
		}
		LA50: ;
		{
			int LOC55;
			NI32 LOC58;
			LOC55 = 0;
			LOC55 = posix_spawn_file_actions_addclose((&fops), (*data).pstdout[(((NI) 0))- 0]);
			if (!!((LOC55 == ((NI32) 0)))) goto LA56;
			LOC58 = 0;
			LOC58 = oslasterror_117033();
			raiseoserror_117009(LOC58);
		}
		LA56: ;
		{
			int LOC61;
			NI32 LOC64;
			LOC61 = 0;
			LOC61 = posix_spawn_file_actions_adddup2((&fops), (*data).pstdout[(((NI) 1))- 0], ((int) 1));
			if (!!((LOC61 == ((NI32) 0)))) goto LA62;
			LOC64 = 0;
			LOC64 = oslasterror_117033();
			raiseoserror_117009(LOC64);
		}
		LA62: ;
		{
			int LOC67;
			NI32 LOC70;
			LOC67 = 0;
			LOC67 = posix_spawn_file_actions_addclose((&fops), (*data).pstderr[(((NI) 0))- 0]);
			if (!!((LOC67 == ((NI32) 0)))) goto LA68;
			LOC70 = 0;
			LOC70 = oslasterror_117033();
			raiseoserror_117009(LOC70);
		}
		LA68: ;
		{
			if (!(*data).optionpostderrtostdout) goto LA73;
			{
				int LOC77;
				NI32 LOC80;
				LOC77 = 0;
				LOC77 = posix_spawn_file_actions_adddup2((&fops), (*data).pstdout[(((NI) 1))- 0], ((int) 2));
				if (!!((LOC77 == ((NI32) 0)))) goto LA78;
				LOC80 = 0;
				LOC80 = oslasterror_117033();
				raiseoserror_117009(LOC80);
			}
			LA78: ;
		}
		goto LA71;
		LA73: ;
		{
			{
				int LOC84;
				NI32 LOC87;
				LOC84 = 0;
				LOC84 = posix_spawn_file_actions_adddup2((&fops), (*data).pstderr[(((NI) 1))- 0], ((int) 2));
				if (!!((LOC84 == ((NI32) 0)))) goto LA85;
				LOC87 = 0;
				LOC87 = oslasterror_117033();
				raiseoserror_117009(LOC87);
			}
			LA85: ;
		}
		LA71: ;
	}
	LA39: ;
	res = 0;
	{
		NimStringDesc* LOC92;
		if (!(((NI) 0) < ((*data).workingdir ? strlen((*data).workingdir) : 0))) goto LA90;
		LOC92 = 0;
		LOC92 = cstrToNimstr((*data).workingdir);
		setcurrentdir_119207(LOC92);
	}
	LA90: ;
	pid = 0;
	{
		if (!(*data).optionpousepath) goto LA95;
		res = posix_spawnp((&pid), (*data).syscommand, (&fops), (&attr), (*data).sysargs, (*data).sysenv);
	}
	goto LA93;
	LA95: ;
	{
		res = posix_spawn((&pid), (*data).syscommand, (&fops), (&attr), (*data).sysargs, (*data).sysenv);
	}
	LA93: ;
	LOC98 = 0;
	LOC98 = posix_spawn_file_actions_destroy((&fops));
	LOC99 = 0;
	LOC99 = posix_spawnattr_destroy((&attr));
	{
		NI32 LOC104;
		if (!!((res == ((NI32) 0)))) goto LA102;
		LOC104 = 0;
		LOC104 = oslasterror_117033();
		raiseoserror_117009(LOC104);
	}
	LA102: ;
	result = pid;
	goto BeforeRet;
	}BeforeRet: ;
	return result;
}
Ejemplo n.º 13
0
// Exits with status 0 if posix_spawn works, non-zero otherwise
int main(int argc, char **argv) {
#if __CYGWIN__
    // Not only does it not work it causes the meson configure step to
    // take tens or minutes to complete and results in a huge cascade
    // of child processes.
    printf("Cygwin doesn't have a working posix_spawn()\n");
    exit(30);
#else   // __CYGWIN__
    char *s;
    pid_t pid;
    posix_spawnattr_t attr;
    int n;
    int status;
    char *cmd[3];
    char tmp[1024];
    if (argc > 1) {
        exit(signal(SIGHUP, SIG_DFL) != SIG_IGN);
    }
    signal(SIGHUP, SIG_IGN);
    if (posix_spawnattr_init(&attr)) {
        printf("posix_spawnattr_init() FAILED\n");
        exit(2);
    }
    if (posix_spawnattr_setpgroup(&attr, 0)) {
        printf("posix_spawnattr_setpgroup() FAILED\n");
        exit(3);
    }
    if (posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETPGROUP)) {
        printf("posix_spawnattr_setflags() FAILED\n");
        exit(4);
    }
    /* first try an a.out and verify that SIGHUP is ignored */
    cmd[0] = argv[0];
    cmd[1] = "test";
    cmd[2] = 0;
    if (posix_spawn(&pid, cmd[0], 0, &attr, cmd, 0)) {
        printf("posix_spawn() FAILED\n");
        exit(5);
    }
    status = 1;
    if (wait(&status) < 0) {
        printf("wait() FAILED\n");
        exit(6);
    }
    if (status != 0) {
        printf("SIGHUP ignored in parent not ignored in child\n");
        exit(7);
    }
    /* must return exec-type errors or its useless to us *unless* there is no [v]fork() */
    n = strlen(cmd[0]);
    if (n >= (sizeof(tmp) - 3)) {
        printf("test executable path too long\n");
        exit(8);
    }
    strcpy(tmp, cmd[0]);
    tmp[n] = '.';
    tmp[n + 1] = 's';
    tmp[n + 2] = 'h';
    tmp[n + 3] = 0;
    if ((n = open(tmp, O_CREAT | O_WRONLY, S_IRWXU | S_IRWXG | S_IRWXO)) < 0 ||
        chmod(tmp, S_IRWXU | S_IRWXG | S_IRWXO) < 0 || write(n, "exit 99\n", 8) != 8 ||
        close(n) < 0) {
        printf("test script create FAILED\n");
        exit(9);
    }
    cmd[0] = tmp;
    pid = -1;
    if (posix_spawn(&pid, cmd[0], 0, &attr, cmd, 0)) {
        printf("ENOEXEC produces posix_spawn() error (BEST)\n");
        exit(0);
    } else if (pid == -1) {
        printf("ENOEXEC returns pid == -1\n");
        exit(10);
    } else if (wait(&status) != pid) {
        printf("ENOEXEC produces no child process\n");
        exit(11);
    } else if (!WIFEXITED(status)) {
        printf("ENOEXEC produces signal exit\n");
        exit(12);
    } else {
        status = WEXITSTATUS(status);
        if (status == 127) {
            printf("ENOEXEC produces exit status 127 (GOOD)\n");
            exit(1);
        } else if (status == 99) {
            printf("ENOEXEC invokes sh\n");
            exit(13);
        } else if (status == 0) {
            printf("ENOEXEC reports no error\n");
            exit(14);
        } else {
            printf("ENOEXEC produces non-zero exit status\n");
            exit(15);
        }
    }
    exit(20);
#endif  // __CYGWIN__
}