From fd2eb6980f760806ae8bb5c6962da318c6a655e8 Mon Sep 17 00:00:00 2001 From: Nick Peng Date: Fri, 1 Dec 2023 20:41:31 +0800 Subject: [PATCH] smartdns: support restart smartdns in docker. --- etc/default/smartdns | 2 +- package/optware/S50smartdns | 5 +- package/optware/smartdns-opt.conf | 5 +- src/smartdns.c | 107 +++++++++++++++++++++++++----- src/util.c | 31 +++++---- src/util.h | 2 + 6 files changed, 118 insertions(+), 34 deletions(-) diff --git a/etc/default/smartdns b/etc/default/smartdns index f7ec5258db..f44cf689c3 100644 --- a/etc/default/smartdns +++ b/etc/default/smartdns @@ -2,4 +2,4 @@ # /etc/init.d/smartdns. # Options to pass to smartdns -SMART_DNS_OPTS= +SMART_DNS_OPTS= -R diff --git a/package/optware/S50smartdns b/package/optware/S50smartdns index 58b8fdb02e..47d3bf035d 100644 --- a/package/optware/S50smartdns +++ b/package/optware/S50smartdns @@ -340,9 +340,12 @@ case "$1" in exit 1 fi + SMARTDNS_OPTION="" + [ "$SMARTDNS_CRASH_RESTART" = "1" ] && SMARTDNS_OPTION="$SMARTDNS_OPTION -R" + set_smartdns_port get_tz - $SMARTDNS_BIN -c "$SMARTDNS_CONF" -p $SMARTDNS_PID + $SMARTDNS_BIN -c "$SMARTDNS_CONF" -p $SMARTDNS_PID $SMARTDNS_OPTION if [ $? -ne 0 ]; then clear_rule exit 1 diff --git a/package/optware/smartdns-opt.conf b/package/optware/smartdns-opt.conf index fef822fcb4..9542fdfb1a 100644 --- a/package/optware/smartdns-opt.conf +++ b/package/optware/smartdns-opt.conf @@ -5,4 +5,7 @@ SMARTDNS_WORKMODE="1" # smartdns port -SMARTDNS_PORT="535" \ No newline at end of file +SMARTDNS_PORT="535" + +# restart when crash +SMARTDNS_CRASH_RESTART="1" \ No newline at end of file diff --git a/src/smartdns.c b/src/smartdns.c index 8838fe0687..d2a0fec5a0 100644 --- a/src/smartdns.c +++ b/src/smartdns.c @@ -55,6 +55,13 @@ #define SMARTDNS_PID_FILE "/run/smartdns.pid" #define SMARTDNS_LEGACY_PID_FILE "/var/run/smartdns.pid" #define TMP_BUFF_LEN_32 32 +#define SMARTDNS_CRASH_CODE 254 + +typedef enum { + SMARTDNS_RUN_MONITOR_OK = 0, + SMARTDNS_RUN_MONITOR_ERROR = 1, + SMARTDNS_RUN_MONITOR_EXIT = 2, +} smartdns_run_monitor_ret; static int verbose_screen; @@ -622,7 +629,7 @@ static void _sig_error_exit(int signo, siginfo_t *siginfo, void *ct) __DATE__, __TIME__, arch); print_stack(); sleep(1); - _exit(0); + _exit(SMARTDNS_CRASH_CODE); } static int sig_list[] = {SIGSEGV, SIGABRT, SIGBUS, SIGILL, SIGFPE}; @@ -732,14 +739,22 @@ static void _smartdns_early_log(struct tlog_loginfo *loginfo, const char *format { char log_buf[TLOG_MAX_LINE_LEN]; int sys_log_level = LOG_INFO; + int log_buf_maxlen = 0; if (loginfo->level < TLOG_WARN) { return; } - int len = vsnprintf(log_buf, sizeof(log_buf), format, ap); + log_buf_maxlen = sizeof(log_buf) - 2; + log_buf[log_buf_maxlen] = '\0'; + int len = vsnprintf(log_buf, log_buf_maxlen, format, ap); if (len <= 0) { return; + } else if (len >= log_buf_maxlen) { + log_buf[log_buf_maxlen - 2] = '.'; + log_buf[log_buf_maxlen - 3] = '.'; + log_buf[log_buf_maxlen - 4] = '.'; + len = log_buf_maxlen - 1; } if (log_buf[len - 1] != '\n') { @@ -747,6 +762,8 @@ static void _smartdns_early_log(struct tlog_loginfo *loginfo, const char *format len++; } + log_buf[len] = '\0'; + fprintf(stderr, "%s", log_buf); switch (loginfo->level) { @@ -774,45 +791,93 @@ static void _smartdns_early_log(struct tlog_loginfo *loginfo, const char *format } static int _smartdns_child_pid = 0; +static int _smartdns_child_restart = 0; -static void _smartdns_run_as_init_sig(int sig) +static void _smartdns_run_monitor_sig(int sig) { if (_smartdns_child_pid > 0) { + if (sig == SIGHUP) { + _smartdns_child_restart = 1; + kill(_smartdns_child_pid, SIGTERM); + return; + } kill(_smartdns_child_pid, SIGTERM); - waitpid(_smartdns_child_pid, NULL, 0); } + waitpid(_smartdns_child_pid, NULL, 0); _exit(0); } -static int _smartdns_run_as_init(int restart_when_crash) +static smartdns_run_monitor_ret _smartdns_run_monitor(int restart_when_crash, int is_run_as_daemon) { pid_t pid; + int status; if (restart_when_crash == 0) { - return 0; + return SMARTDNS_RUN_MONITOR_OK; + } + + if (is_run_as_daemon) { + int daemon_ret = daemon_run(); + if (daemon_ret != -2) { + if (daemon_ret == 0) { + return SMARTDNS_RUN_MONITOR_EXIT; + } + + return SMARTDNS_RUN_MONITOR_ERROR; + } } - pid = getpid(); - setpgid(pid, pid); + daemon_kickoff(0, 1); restart: pid = fork(); if (pid < 0) { fprintf(stderr, "fork failed, %s\n", strerror(errno)); - return -1; + return SMARTDNS_RUN_MONITOR_ERROR; } else if (pid == 0) { - return 0; + return SMARTDNS_RUN_MONITOR_OK; } _smartdns_child_pid = pid; - signal(SIGTERM, _smartdns_run_as_init_sig); - + signal(SIGTERM, _smartdns_run_monitor_sig); + signal(SIGHUP, _smartdns_run_monitor_sig); while (true) { - pid = waitpid(-1, NULL, 0); + pid = waitpid(-1, &status, 0); if (pid == _smartdns_child_pid) { - goto restart; + int need_restart = 0; + char signalmsg[64] = {0}; + + if (_smartdns_child_restart == 1) { + _smartdns_child_restart = 0; + goto restart; + } + + if (WEXITSTATUS(status) == SMARTDNS_CRASH_CODE) { + need_restart = 1; + } else if (WEXITSTATUS(status) == 255) { + fprintf(stderr, "run daemon failed, please check log.\n"); + } else if (WIFSIGNALED(status)) { + switch (WTERMSIG(status)) { + case SIGSEGV: + case SIGABRT: + case SIGBUS: + case SIGILL: + case SIGFPE: + snprintf(signalmsg, sizeof(signalmsg), " with signal %d", WTERMSIG(status)); + need_restart = 1; + break; + default: + break; + } + } + + if (need_restart == 1) { + printf("smartdns crashed%s, restart...\n", signalmsg); + goto restart; + } + break; } if (pid < 0) { @@ -820,7 +885,7 @@ static int _smartdns_run_as_init(int restart_when_crash) } } - return -1; + return SMARTDNS_RUN_MONITOR_ERROR; } #ifdef TEST @@ -932,7 +997,11 @@ int main(int argc, char *argv[]) } } - if (_smartdns_run_as_init(restart_when_crash) != 0) { + smartdns_run_monitor_ret init_ret = _smartdns_run_monitor(restart_when_crash, is_run_as_daemon); + if (init_ret != SMARTDNS_RUN_MONITOR_OK) { + if (init_ret == SMARTDNS_RUN_MONITOR_EXIT) { + return 0; + } return 1; } @@ -946,7 +1015,7 @@ int main(int argc, char *argv[]) goto errout; } - if (dns_no_daemon) { + if (dns_no_daemon || restart_when_crash) { is_run_as_daemon = 0; } @@ -1006,6 +1075,8 @@ int main(int argc, char *argv[]) if (ret != 0) { goto errout; } + } else if (dns_conf_log_console == 0 && verbose_screen == 0) { + daemon_close_stdfds(); } smartdns_test_notify(1); @@ -1019,5 +1090,5 @@ int main(int argc, char *argv[]) } smartdns_test_notify(2); _smartdns_exit(); - return 1; + return ret; } diff --git a/src/util.c b/src/util.c index 224991984d..526c1af3a4 100644 --- a/src/util.c +++ b/src/util.c @@ -1632,6 +1632,23 @@ void close_all_fd(int keepfd) return; } +void daemon_close_stdfds(void) +{ + int fd_null = open("/dev/null", O_RDWR); + if (fd_null < 0) { + fprintf(stderr, "open /dev/null failed, %s\n", strerror(errno)); + return; + } + + dup2(fd_null, STDIN_FILENO); + dup2(fd_null, STDOUT_FILENO); + dup2(fd_null, STDERR_FILENO); + + if (fd_null > 2) { + close(fd_null); + } +} + int daemon_kickoff(int status, int no_close) { struct daemon_msg msg; @@ -1650,19 +1667,7 @@ int daemon_kickoff(int status, int no_close) } if (no_close == 0) { - int fd_null = open("/dev/null", O_RDWR); - if (fd_null < 0) { - fprintf(stderr, "open /dev/null failed, %s\n", strerror(errno)); - return -1; - } - - dup2(fd_null, STDIN_FILENO); - dup2(fd_null, STDOUT_FILENO); - dup2(fd_null, STDERR_FILENO); - - if (fd_null > 2) { - close(fd_null); - } + daemon_close_stdfds(); } close(daemon_fd); diff --git a/src/util.h b/src/util.h index 67ee533aed..7a417de14f 100644 --- a/src/util.h +++ b/src/util.h @@ -153,6 +153,8 @@ int daemon_kickoff(int status, int no_close); int daemon_keepalive(void); +void daemon_close_stdfds(void); + int write_file(const char *filename, void *data, int data_len); int dns_packet_save(const char *dir, const char *type, const char *from, const void *packet, int packet_len);