/*****************************************************************************
* spawn.c
*****************************************************************************
* Copyright (C) 2008, 2020 Rémi Denis-Courmont
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <vlc_common.h>
#include <vlc_spawn.h>
#if (_POSIX_SPAWN >= 0)
#include <spawn.h>
extern char **environ;
static int vlc_spawn_inner(pid_t *restrict pid, const char *path,
const int *fdv, const char *const *argv,
bool search)
{
posix_spawnattr_t attr;
posix_spawn_file_actions_t fas;
char **vargv;
size_t argc = 0;
int err;
assert(pid != NULL);
assert(path != NULL);
assert(fdv != NULL);
assert(argv != NULL);
err = posix_spawn_file_actions_init(&fas);
if (unlikely(err != 0))
return err;
for (int newfd = 0; newfd < 3 || fdv[newfd] != -1; newfd++) {
int oldfd = fdv[newfd];
if (oldfd == -1)
err = posix_spawn_file_actions_addopen(&fas, newfd, "/dev/null",
O_RDWR, 0644);
else
err = posix_spawn_file_actions_adddup2(&fas, oldfd, newfd);
if (unlikely(err != 0)) {
posix_spawn_file_actions_destroy(&fas);
return err;
}
}
posix_spawnattr_init(&attr);
{
sigset_t set;
/* Unmask signals. */
sigemptyset(&set);
posix_spawnattr_setsigmask(&attr, &set);
/* Reset SIGPIPE handler (which VLC overrode). */
sigaddset(&set, SIGPIPE);
posix_spawnattr_setsigdefault(&attr, &set);
}
posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGDEF
| POSIX_SPAWN_SETSIGMASK);
/* For hysterical raisins, POSIX uses non-const character pointers.
* We need to copy manually due to aliasing rules.
*/
while (argv[argc++] != NULL);
vargv = malloc(sizeof (*argv) * argc);
if (unlikely(vargv == NULL)) {
err = errno;
goto out;
}
for (size_t i = 0; i < argc; i++)
vargv[i] = (char *)argv[i];
if (search)
err = posix_spawnp(pid, path, &fas, &attr, vargv, environ);
else
err = posix_spawn(pid, path, &fas, &attr, vargv, environ);
out:
free(vargv);
posix_spawnattr_destroy(&attr);
posix_spawn_file_actions_destroy(&fas);
return err;
}
#else /* _POSIX_SPAWN */
#include <vlc_fs.h>
static int vlc_spawn_inner(pid_t *restrict pid, const char *path,
const int *fdv, const char *const *argv,
bool search)
{
size_t argc = 0;
assert(pid != NULL);
assert(path != NULL);
assert(fdv != NULL);
assert(argv != NULL);
int nulfd = vlc_open("/dev/null", O_RDWR);
if (unlikely(nulfd == -1))
return errno;
while (argv[argc++] != NULL);
char **vargv = malloc(sizeof (*argv) * argc);
if (unlikely(vargv == NULL)) {
vlc_close(nulfd);
return errno;
}
for (size_t i = 0; i < argc; i++)
vargv[i] = (char *)argv[i];
*pid = fork();
switch (*pid) {
case -1:
return errno;
case 0:
break;
default:
free(vargv);
vlc_close(nulfd);
return 0;
}
for (int newfd = 0; newfd < 3 || fdv[newfd] != -1; newfd++) {
int oldfd = fdv[newfd];
if (oldfd == -1)
oldfd = nulfd;
if (oldfd == newfd)
fcntl(oldfd, F_SETFD, fcntl(oldfd, F_GETFD) & ~FD_CLOEXEC);
else
if (dup2(oldfd, newfd) < 0)
_exit(1);
}
sigset_t set;
sigemptyset(&set);
pthread_sigmask(SIG_SETMASK, &set, NULL);
signal(SIGPIPE, SIG_DFL);
if (search)
execvp(path, vargv);
else
execv(path, vargv);
_exit(1);
}
#endif /* _POSIX_SPAWN */
int vlc_spawnp(pid_t *restrict pid, const char *path,
const int *fdv, const char *const *argv)
{
return vlc_spawn_inner(pid, path, fdv, argv, true);
}
int vlc_spawn(pid_t *restrict pid, const char *file,
const int *fdv, const char *const *argv)
{
return vlc_spawn_inner(pid, file, fdv, argv, false);
}
int vlc_waitpid(pid_t pid)
{
int status;
while (waitpid(pid, &status, 0) == -1)
assert(errno != ECHILD && errno != EINVAL);
return status;
}
¤ Dauer der Verarbeitung: 0.3 Sekunden
¤
*© Formatika GbR, Deutschland
|
|