Skip to content

Commit a70b748

Browse files
authored
Merge pull request #2419 from pi-hole/tweak/prevent_restart_during_gravity_run
Do not restart FTL while `pihole -g` is still ongoing
2 parents c7f925e + c8b5401 commit a70b748

6 files changed

Lines changed: 73 additions & 2 deletions

File tree

src/api/action.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
// flush_network_table()
2323
#include "database/network-table.h"
2424
#include "config/config.h"
25+
// gravity_running
26+
#include "daemon.h"
2527

2628
static int run_and_stream_command(struct ftl_conn *api, const char *path, const char *const args[], const char *extra_env)
2729
{
@@ -57,6 +59,18 @@ static int run_and_stream_command(struct ftl_conn *api, const char *path, const
5759
if(extra_env != NULL)
5860
setenv(extra_env, "1", 1);
5961

62+
// Detach child into its own session/process group so signals
63+
// sent to the parent's process group (like SIGTERM) do not
64+
// propagate to this child.
65+
(void)setsid();
66+
67+
// Ignore SIGTERM so systemd's cgroup-level kill (the
68+
// default KillMode=control-group sends SIGTERM to ALL
69+
// processes in the cgroup) doesn't terminate gravity
70+
// mid-run. SIG_IGN is preserved across execv(), unlike
71+
// custom handlers which are reset to SIG_DFL.
72+
signal(SIGTERM, SIG_IGN);
73+
6074
// Run pihole -g
6175
execv(path, (char *const *)args);
6276

@@ -129,7 +143,16 @@ int api_action_gravity(struct ftl_conn *api)
129143
get_bool_var(query, "color", &color);
130144

131145
const char *extra_env = color ? "FORCE_COLOR" : NULL;
132-
return run_and_stream_command(api, "/usr/local/bin/pihole", (const char *const []){ "pihole", "-g", NULL }, extra_env);
146+
147+
gravity_running = 1;
148+
const int ret = run_and_stream_command(api, "/usr/local/bin/pihole", (const char *const []){ "pihole", "-g", NULL }, extra_env);
149+
gravity_running = 0;
150+
151+
// If a termination/restart was requested while gravity was running,
152+
// act on it now rather than waiting up to ~1s for the GC thread to pick it up
153+
check_if_want_terminate();
154+
155+
return ret;
133156
}
134157

135158
int api_action_restartDNS(struct ftl_conn *api)

src/daemon.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
pthread_t threads[THREADS_MAX] = { 0 };
4848
bool resolver_ready = false;
4949
bool dnsmasq_failed = false;
50+
volatile sig_atomic_t gravity_running = 0;
51+
volatile sig_atomic_t want_terminate = 0;
5052

5153
void go_daemon(void)
5254
{

src/daemon.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,7 @@ ssize_t getrandom_fallback(void *buf, size_t buflen, unsigned int flags);
5656

5757
extern bool resolver_ready;
5858
extern bool dnsmasq_failed;
59+
extern volatile sig_atomic_t gravity_running;
60+
extern volatile sig_atomic_t want_terminate;
5961

6062
#endif //DAEMON_H

src/gc.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,14 @@ void *GC_thread(void *val)
721721
set_dnsmasq_debug(is_debugged, dpid);
722722
}
723723

724+
// Intermediate cancellation-point
725+
if(killed)
726+
break;
727+
728+
// Check if we need to terminate/restart FTL but this has been
729+
// postponed because of an ongoing gravity run
730+
check_if_want_terminate();
731+
724732
// Sleep for the remaining time of the interval (if any)
725733
const double time_end = double_time();
726734
const double time_diff = time_end - time_start;

src/signals.c

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,10 @@ const char * const thread_names[THREADS_MAX] = {
234234
"ntp-server4",
235235
"ntp-server6",
236236
"webserver",
237-
};
237+
};
238+
239+
// Private prototypes
240+
static void terminate(void);
238241

239242
// Return the (null-terminated) name of the calling thread
240243
// The name is stored in the buffer as well as returned for convenience
@@ -577,6 +580,38 @@ static void SIGTERM_handler(int signum, siginfo_t *si, void *context)
577580
log_info("Asked to terminate by \"%s\" (PID %ld, user %s UID %ld)",
578581
kill_name, (long int)kill_pid, kill_user, (long int)kill_uid);
579582

583+
// Check if we can terminate
584+
want_terminate = true;
585+
check_if_want_terminate();
586+
}
587+
588+
// Checks if the program should terminate or not
589+
static time_t last_term_warning = 0;
590+
void check_if_want_terminate(void)
591+
{
592+
if(!want_terminate)
593+
// We are not asked to terminate
594+
return;
595+
596+
// Return early if we are not allowed to terminate
597+
if(gravity_running)
598+
{
599+
// Only log once every 30 seconds or if any debugging is enabled
600+
if(time(NULL) - last_term_warning > 30 || debug_flags[DEBUG_ANY])
601+
{
602+
log_info("Not terminating as gravity is still running...");
603+
last_term_warning = time(NULL);
604+
}
605+
return;
606+
}
607+
608+
// Terminate if gravity is not running
609+
terminate();
610+
}
611+
612+
// Terminates the DNS service by signaling or marking it as failed
613+
static void terminate(void)
614+
{
580615
// Terminate dnsmasq to stop DNS service
581616
if(!dnsmasq_failed)
582617
{

src/signals.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
void handle_signals(void);
2222
void handle_realtime_signals(void);
2323
pid_t main_pid(void);
24+
void check_if_want_terminate(void);
2425
void thread_sleepms(const enum thread_types thread, const int milliseconds);
2526
void init_backtrace(const char *argv0);
2627
void generate_backtrace(void);

0 commit comments

Comments
 (0)