| 601 | } |
| 602 | |
| 603 | void Daemon::daemonize(const std::string& pid_file) |
| 604 | { |
| 605 | USBGUARD_LOG(Trace) << "Starting daemonization"; |
| 606 | pid_t pid = 0; |
| 607 | pid_t original_pid = getpid(); |
| 608 | sigset_t mask; |
| 609 | sigemptyset(&mask); |
| 610 | sigaddset(&mask, SIGUSR1); |
| 611 | sigprocmask(SIG_BLOCK, &mask, nullptr); |
| 612 | USBGUARD_SYSCALL_THROW("Daemonize", (pid = fork()) < 0); |
| 613 | |
| 614 | if (pid > 0) { |
| 615 | constexpr int timeout_val = 5; |
| 616 | struct timespec timeout { |
| 617 | timeout_val, 0 |
| 618 | }; |
| 619 | const time_t start = time(nullptr); |
| 620 | siginfo_t info; |
| 621 | |
| 622 | do { |
| 623 | const int signum = sigtimedwait(&mask, &info, &timeout); |
| 624 | |
| 625 | if (signum == SIGUSR1 && info.si_signo == SIGUSR1 && info.si_pid == pid) { |
| 626 | waitpid(pid, nullptr, 0); |
| 627 | USBGUARD_LOG(Trace) << "Finished daemonization"; |
| 628 | exit(EXIT_SUCCESS); |
| 629 | } |
| 630 | |
| 631 | if (signum == -1 && errno == EAGAIN) { |
| 632 | break; /* timed out */ |
| 633 | } |
| 634 | |
| 635 | timeout.tv_sec = timeout_val - difftime(time(nullptr), start); /* avoid potentially endless loop */ |
| 636 | } |
| 637 | while (true); |
| 638 | |
| 639 | throw Exception("Daemonize", "signal", "Waiting on pid file write timeout!"); |
| 640 | } |
| 641 | |
| 642 | /* Now we are forked */ |
| 643 | USBGUARD_SYSCALL_THROW("Daemonize", setsid() < 0); |
| 644 | signal(SIGCHLD, SIG_IGN); |
| 645 | USBGUARD_SYSCALL_THROW("Daemonize", (pid_fd = open(pid_file.c_str(), O_RDWR|O_CREAT, 0640)) < 0); |
| 646 | USBGUARD_SYSCALL_THROW("Daemonize", (lockf(pid_fd, F_TLOCK, 0)) < 0); |
| 647 | USBGUARD_SYSCALL_THROW("Daemonize", (pid = fork()) < 0); |
| 648 | |
| 649 | if (pid > 0) { |
| 650 | try { |
| 651 | std::string pid_str = std::to_string(pid); |
| 652 | USBGUARD_SYSCALL_THROW("Daemonize", write(pid_fd, pid_str.c_str(), pid_str.size()) != static_cast<ssize_t>(pid_str.size())); |
| 653 | kill(original_pid, SIGUSR1); |
| 654 | exit(EXIT_SUCCESS); |
| 655 | } |
| 656 | catch (...) { |
| 657 | kill(pid, SIGKILL); |
| 658 | throw; |
| 659 | } |
| 660 | } |