#include "orconfig.h"
#include "lib/process/daemon.h"
#ifndef _WIN32
#include "lib/fs/files.h"
#include "lib/log/log.h"
#include "lib/thread/threads.h"
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include <errno.h>
#include <stdlib.h>
#include <string.h>
static int start_daemon_called = 0;
static int finish_daemon_called = 0;
static int daemon_filedes[2];
bool
start_daemon_has_been_called(void)
{
return start_daemon_called != 0;
}
int
start_daemon(void)
{
pid_t pid;
if (start_daemon_called)
return 0;
start_daemon_called = 1;
if (pipe(daemon_filedes)) {
log_err(LD_GENERAL,"pipe failed; exiting. Error was %s", strerror(errno));
exit(1);
}
pid = fork();
if (pid < 0) {
log_err(LD_GENERAL,"fork failed. Exiting.");
exit(1);
}
if (pid) {
int ok;
char c;
close(daemon_filedes[1]);
ok = -1;
while (0 < read(daemon_filedes[0], &c, sizeof(char))) {
if (c == '.')
ok = 1;
}
fflush(stdout);
if (ok == 1)
exit(0); else
exit(1);
return 0; } else {
close(daemon_filedes[0]);
(void) setsid();
if (fork() != 0) {
exit(0); }
set_main_thread();
return 1;
}
}
int
finish_daemon(const char *desired_cwd)
{
int nullfd;
char c = '.';
if (finish_daemon_called)
return 0;
if (!start_daemon_called)
start_daemon();
finish_daemon_called = 1;
if (!desired_cwd)
desired_cwd = "/";
if (chdir(desired_cwd) < 0) {
log_err(LD_GENERAL,"chdir to \"%s\" failed. Exiting.",desired_cwd);
exit(1); }
nullfd = tor_open_cloexec("/dev/null", O_RDWR, 0);
if (nullfd < 0) {
log_err(LD_GENERAL,"/dev/null can't be opened. Exiting.");
exit(1);
}
if (dup2(nullfd,0) < 0 ||
dup2(nullfd,1) < 0 ||
dup2(nullfd,2) < 0) {
log_err(LD_GENERAL,"dup2 failed. Exiting.");
exit(1);
}
if (nullfd > 2)
close(nullfd);
if (write(daemon_filedes[1], &c, sizeof(char)) != sizeof(char)) {
log_err(LD_GENERAL,"write failed. Exiting.");
}
close(daemon_filedes[1]);
return 0;
}
#else
int
start_daemon(void)
{
return 0;
}
int
finish_daemon(const char *cp)
{
(void)cp;
return 0;
}
bool
start_daemon_has_been_called(void)
{
return false;
}
#endif