diff --git a/btpd/main.c b/btpd/main.c index c43c223..089929d 100644 --- a/btpd/main.c +++ b/btpd/main.c @@ -1,73 +1,93 @@ #include "btpd.h" -#include -#include #include #include +int btpd_daemon_phase = 2; +int first_btpd_comm[2]; + +void +first_btpd_exit(char code) +{ + write(first_btpd_comm[1], &code, 1); + close(first_btpd_comm[0]); + close(first_btpd_comm[1]); +} + static void writepid(int pidfd) { - FILE *fp = fdopen(dup(pidfd), "w"); - fprintf(fp, "%ld", (long)getpid()); - fclose(fp); + int nw; + char pidtxt[100]; + nw = snprintf(pidtxt, sizeof(pidtxt), "%ld", (long)getpid); + ftruncate(pidfd, 0); + write(pidfd, pidtxt, nw); } static void -setup_daemon(int daemonize, const char *dir, const char *log) +setup_daemon(int daemonize, const char *dir) { + char c; int pidfd; + pid_t pid; struct timespec ts; if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) - errx(1, "clock_gettime(CLOCK_MONOTONIC, ...) error (%s).", + btpd_err("clock_gettime(CLOCK_MONOTONIC, ...) failed (%s).\n", strerror(errno)); - if (log == NULL) - log = "log"; - if (dir == NULL) { if ((dir = find_btpd_dir()) == NULL) - errx(1, "Cannot find the btpd directory"); - else if (dir[0] != '/') - errx(1, "got non absolute path '%s' from system environment.", + btpd_err("Cannot find the btpd directory.\n"); + if (dir[0] != '/') + btpd_err("Got non absolute path '%s' from system environment.\n", dir); btpd_dir = dir; } if (mkdir(dir, 0777) == -1 && errno != EEXIST) - err(1, "Couldn't create home '%s'", dir); + btpd_err("Couldn't create home '%s' (%s).\n", dir, strerror(errno)); if (chdir(dir) != 0) - err(1, "Couldn't change working directory to '%s'", dir); + btpd_err("Couldn't change working directory to '%s' (%s).\n", dir, + strerror(errno)); if (mkdir("torrents", 0777) == -1 && errno != EEXIST) - err(1, "Couldn't create torrents subdir"); - - if ((pidfd = open("pid", O_CREAT|O_TRUNC|O_WRONLY, 0666)) == -1) - err(1, "Couldn't open 'pid'"); - - if (flock(pidfd, LOCK_NB|LOCK_EX) == -1) - errx(1, "Another instance of btpd is probably running in %s.", dir); + btpd_err("Couldn't create torrents subdir (%s).\n", strerror(errno)); if (btpd_dir == NULL) { char wd[PATH_MAX]; if (getcwd(wd, PATH_MAX) == NULL) - err(1, "couldn't get working directory"); - btpd_dir = strdup(wd); + btpd_err("Couldn't get working directory (%s).\n", + strerror(errno)); + if ((btpd_dir = strdup(wd)) == NULL) + btpd_err("Out of memory.\n"); } if (daemonize) { - if (daemon(1, 1) != 0) - err(1, "Failed to daemonize"); - freopen("/dev/null", "r", stdin); - if (freopen(log, "a", stdout) == NULL) - err(1, "Couldn't open '%s'", log); - dup2(fileno(stdout), fileno(stderr)); - setlinebuf(stdout); - setlinebuf(stderr); + if (pipe(first_btpd_comm) < 0) + btpd_err("Failed to create pipe (%s).\n", strerror(errno)); + if ((pid = fork()) < 0) + btpd_err("fork() failed (%s).\n", strerror(errno)); + if (pid != 0) { + read(first_btpd_comm[0], &c, 1); + exit(c); + } + btpd_daemon_phase--; + if (setsid() < 0) + btpd_err("setsid() failed (%s).\n", strerror(errno)); + if ((pid = fork()) < 0) + btpd_err("fork() failed (%s).\n", strerror(errno)); + if (pid != 0) + exit(0); } + if ((pidfd = open("pid", O_CREAT|O_WRONLY, 0666)) == -1) + btpd_err("Couldn't open 'pid' (%s).\n", strerror(errno)); + + if (lockf(pidfd, F_TLOCK, 0) == -1) + btpd_err("Another instance of btpd is probably running in %s.\n", dir); + writepid(pidfd); } @@ -203,10 +223,11 @@ main(int argc, char **argv) case 1: break; case 0: - errx(1, "You must specify a dotted IPv4 address.\n"); + btpd_err("You must specify a dotted IPv4 address.\n"); break; default: - err(1, "inet_ntop %s", optarg); + btpd_err("inet_ntop for '%s' failed (%s).\n", optarg, + strerror(errno)); } break; default: @@ -225,13 +246,26 @@ args_done: if (argc > 0) usage(); - setup_daemon(daemonize, dir, log); + setup_daemon(daemonize, dir); if (evloop_init() != 0) btpd_err("Failed to initialize evloop (%s).\n", strerror(errno)); btpd_init(); + if (daemonize) { + if (freopen("/dev/null", "r", stdin) == NULL) + btpd_err("freopen of stdin failed (%s).\n", strerror(errno)); + if (freopen(log == NULL ? "log" : log, "a", stderr) == NULL) + btpd_err("Couldn't open '%s' (%s).\n", log, strerror(errno)); + if (dup2(fileno(stderr), fileno(stdout)) < 0) + btpd_err("dup2 failed (%s).\n", strerror(errno)); + first_btpd_exit(0); + } + setlinebuf(stdout); + setlinebuf(stderr); + + btpd_daemon_phase = 0; evloop(); btpd_err("Exit from evloop with error (%s).\n", strerror(errno)); diff --git a/btpd/util.c b/btpd/util.c index c6b430e..02ce032 100644 --- a/btpd/util.c +++ b/btpd/util.c @@ -91,14 +91,23 @@ log_common(uint32_t type, const char *fmt, va_list ap) } } +extern int btpd_daemon_phase; +extern void first_btpd_exit(char); + void btpd_err(const char *fmt, ...) { va_list ap; va_start(ap, fmt); - log_common(BTPD_L_ERROR, fmt, ap); - va_end(ap); - exit(1); + if (btpd_daemon_phase > 0) { + vprintf(fmt, ap); + if (btpd_daemon_phase == 1) + first_btpd_exit(1); + exit(1); + } else { + log_common(BTPD_L_ERROR, fmt, ap); + abort(); + } } void