|
Packit |
ab56a9 |
/***
|
|
Packit |
ab56a9 |
This file is part of libdaemon.
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
Copyright 2003-2008 Lennart Poettering
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
libdaemon is free software; you can redistribute it and/or modify
|
|
Packit |
ab56a9 |
it under the terms of the GNU Lesser General Public License as
|
|
Packit |
ab56a9 |
published by the Free Software Foundation, either version 2.1 of the
|
|
Packit |
ab56a9 |
License, or (at your option) any later version.
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
libdaemon is distributed in the hope that it will be useful, but
|
|
Packit |
ab56a9 |
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
ab56a9 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
ab56a9 |
Lesser General Public License for more details.
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
You should have received a copy of the GNU Lesser General Public
|
|
Packit |
ab56a9 |
License along with libdaemon. If not, see
|
|
Packit |
ab56a9 |
<http://www.gnu.org/licenses/>.
|
|
Packit |
ab56a9 |
***/
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
ab56a9 |
#include <config.h>
|
|
Packit |
ab56a9 |
#endif
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
#include <sys/types.h>
|
|
Packit |
ab56a9 |
#include <unistd.h>
|
|
Packit |
ab56a9 |
#include <string.h>
|
|
Packit |
ab56a9 |
#include <errno.h>
|
|
Packit |
ab56a9 |
#include <sys/stat.h>
|
|
Packit |
ab56a9 |
#include <stdlib.h>
|
|
Packit |
ab56a9 |
#include <signal.h>
|
|
Packit |
ab56a9 |
#include <sys/wait.h>
|
|
Packit |
ab56a9 |
#include <limits.h>
|
|
Packit |
ab56a9 |
#include <fcntl.h>
|
|
Packit |
ab56a9 |
#include <stdio.h>
|
|
Packit |
ab56a9 |
#include <stdarg.h>
|
|
Packit |
ab56a9 |
#include <assert.h>
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
#include "dlog.h"
|
|
Packit |
ab56a9 |
#include "dsignal.h"
|
|
Packit |
ab56a9 |
#include "dfork.h"
|
|
Packit |
ab56a9 |
#include "dexec.h"
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
#define MAX_ARGS 64
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
int daemon_execv(const char *dir, int *ret, const char *prog, va_list ap) {
|
|
Packit |
ab56a9 |
pid_t pid;
|
|
Packit |
ab56a9 |
int p[2];
|
|
Packit |
ab56a9 |
unsigned n = 0;
|
|
Packit |
ab56a9 |
static char buf[256];
|
|
Packit |
ab56a9 |
int sigfd, r;
|
|
Packit |
ab56a9 |
fd_set fds;
|
|
Packit |
ab56a9 |
int saved_errno;
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
assert(daemon_signal_fd() >= 0);
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
if (pipe(p) < 0) {
|
|
Packit |
ab56a9 |
daemon_log(LOG_ERR, "pipe() failed: %s", strerror(errno));
|
|
Packit |
ab56a9 |
return -1;
|
|
Packit |
ab56a9 |
}
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
if ((pid = fork()) < 0) {
|
|
Packit |
ab56a9 |
daemon_log(LOG_ERR, "fork() failed: %s", strerror(errno));
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
saved_errno = errno;
|
|
Packit |
ab56a9 |
close(p[0]);
|
|
Packit |
ab56a9 |
close(p[1]);
|
|
Packit |
ab56a9 |
errno = saved_errno;
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
return -1;
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
} else if (pid == 0) {
|
|
Packit |
ab56a9 |
char *args[MAX_ARGS];
|
|
Packit |
ab56a9 |
int i;
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
if (p[1] != 1)
|
|
Packit |
ab56a9 |
if (dup2(p[1], 1) < 0) {
|
|
Packit |
ab56a9 |
daemon_log(LOG_ERR, "dup2: %s", strerror(errno));
|
|
Packit |
ab56a9 |
goto fail;
|
|
Packit |
ab56a9 |
}
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
if (p[1] != 2)
|
|
Packit |
ab56a9 |
if (dup2(p[1], 2) < 0) {
|
|
Packit |
ab56a9 |
daemon_log(LOG_ERR, "dup2: %s", strerror(errno));
|
|
Packit |
ab56a9 |
goto fail;
|
|
Packit |
ab56a9 |
}
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
if (p[0] > 2)
|
|
Packit |
ab56a9 |
close(p[0]);
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
if (p[1] > 2)
|
|
Packit |
ab56a9 |
close(p[1]);
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
close(0);
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
if (open("/dev/null", O_RDONLY) != 0) {
|
|
Packit |
ab56a9 |
daemon_log(LOG_ERR, "Unable to open /dev/null as STDIN");
|
|
Packit |
ab56a9 |
goto fail;
|
|
Packit |
ab56a9 |
}
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
daemon_close_all(-1);
|
|
Packit |
ab56a9 |
daemon_reset_sigs(-1);
|
|
Packit |
ab56a9 |
daemon_unblock_sigs(-1);
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
umask(0022); /* Set up a sane umask */
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
if (dir && chdir(dir) < 0) {
|
|
Packit |
ab56a9 |
daemon_log(LOG_WARNING, "Failed to change to directory '%s'", dir);
|
|
Packit |
ab56a9 |
chdir("/");
|
|
Packit |
ab56a9 |
}
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
for (i = 0; i < MAX_ARGS-1; i++)
|
|
Packit |
ab56a9 |
if (!(args[i] = va_arg(ap, char*)))
|
|
Packit |
ab56a9 |
break;
|
|
Packit |
ab56a9 |
args[i] = NULL;
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
execv(prog, args);
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
daemon_log(LOG_ERR, "execv(%s) failed: %s", prog, strerror(errno));
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
fail:
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
_exit(EXIT_FAILURE);
|
|
Packit |
ab56a9 |
}
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
close(p[1]);
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
FD_ZERO(&fds);
|
|
Packit |
ab56a9 |
FD_SET(p[0], &fds);
|
|
Packit |
ab56a9 |
sigfd = daemon_signal_fd();
|
|
Packit |
ab56a9 |
FD_SET(sigfd, &fds);
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
n = 0;
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
for (;;) {
|
|
Packit |
ab56a9 |
fd_set qfds = fds;
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
if (select(FD_SETSIZE, &qfds, NULL, NULL, NULL) < 0) {
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
if (errno == EINTR)
|
|
Packit |
ab56a9 |
continue;
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
daemon_log(LOG_ERR, "select() failed: %s", strerror(errno));
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
saved_errno = errno;
|
|
Packit |
ab56a9 |
close(p[0]);
|
|
Packit |
ab56a9 |
errno = saved_errno;
|
|
Packit |
ab56a9 |
return -1;
|
|
Packit |
ab56a9 |
}
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
if (FD_ISSET(p[0], &qfds)) {
|
|
Packit |
ab56a9 |
char c;
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
if (read(p[0], &c, 1) != 1)
|
|
Packit |
ab56a9 |
break;
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
buf[n] = c;
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
if (c == '\n' || n >= sizeof(buf) - 2) {
|
|
Packit |
ab56a9 |
if (c != '\n') n++;
|
|
Packit |
ab56a9 |
buf[n] = 0;
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
if (buf[0])
|
|
Packit |
ab56a9 |
daemon_log(LOG_INFO, "client: %s", buf);
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
n = 0;
|
|
Packit |
ab56a9 |
} else
|
|
Packit |
ab56a9 |
n++;
|
|
Packit |
ab56a9 |
}
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
if (FD_ISSET(sigfd, &qfds)) {
|
|
Packit |
ab56a9 |
int sig;
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
if ((sig = daemon_signal_next()) < 0) {
|
|
Packit |
ab56a9 |
saved_errno = errno;
|
|
Packit |
ab56a9 |
close(p[0]);
|
|
Packit |
ab56a9 |
errno = saved_errno;
|
|
Packit |
ab56a9 |
return -1;
|
|
Packit |
ab56a9 |
}
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
if (sig != SIGCHLD) {
|
|
Packit |
ab56a9 |
daemon_log(LOG_WARNING, "Killing child.");
|
|
Packit |
ab56a9 |
kill(pid, SIGTERM);
|
|
Packit |
ab56a9 |
}
|
|
Packit |
ab56a9 |
}
|
|
Packit |
ab56a9 |
}
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
if (n > 0) {
|
|
Packit |
ab56a9 |
buf[n] = 0;
|
|
Packit |
ab56a9 |
daemon_log(LOG_WARNING, "client: %s", buf);
|
|
Packit |
ab56a9 |
}
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
close(p[0]);
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
for (;;) {
|
|
Packit |
ab56a9 |
if (waitpid(pid, &r, 0) < 0) {
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
if (errno == EINTR)
|
|
Packit |
ab56a9 |
continue;
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
daemon_log(LOG_ERR, "waitpid(): %s", strerror(errno));
|
|
Packit |
ab56a9 |
return -1;
|
|
Packit |
ab56a9 |
} else {
|
|
Packit |
ab56a9 |
if (!WIFEXITED(r)) {
|
|
Packit |
ab56a9 |
errno = ECANCELED;
|
|
Packit |
ab56a9 |
return -1;
|
|
Packit |
ab56a9 |
}
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
if (ret)
|
|
Packit |
ab56a9 |
*ret = WEXITSTATUS(r);
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
return 0;
|
|
Packit |
ab56a9 |
}
|
|
Packit |
ab56a9 |
}
|
|
Packit |
ab56a9 |
}
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
int daemon_exec(const char *dir, int *ret, const char *prog, ...) {
|
|
Packit |
ab56a9 |
va_list ap;
|
|
Packit |
ab56a9 |
int r;
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
va_start(ap, prog);
|
|
Packit |
ab56a9 |
r = daemon_execv(dir, ret, prog, ap);
|
|
Packit |
ab56a9 |
va_end(ap);
|
|
Packit |
ab56a9 |
|
|
Packit |
ab56a9 |
return r;
|
|
Packit |
ab56a9 |
}
|