2
0
Эх сурвалжийг харах

smartdns: support restart smartdns in docker.

Nick Peng 1 жил өмнө
parent
commit
fd2eb6980f

+ 1 - 1
etc/default/smartdns

@@ -2,4 +2,4 @@
 # /etc/init.d/smartdns.
 
 # Options to pass to smartdns
-SMART_DNS_OPTS=
+SMART_DNS_OPTS= -R

+ 4 - 1
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

+ 4 - 1
package/optware/smartdns-opt.conf

@@ -5,4 +5,7 @@
 SMARTDNS_WORKMODE="1"
 
 # smartdns port
-SMARTDNS_PORT="535"
+SMARTDNS_PORT="535"
+
+# restart when crash
+SMARTDNS_CRASH_RESTART="1"

+ 89 - 18
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 @@ restart:
 		}
 	}
 
-	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 @@ errout:
 	}
 	smartdns_test_notify(2);
 	_smartdns_exit();
-	return 1;
+	return ret;
 }

+ 18 - 13
src/util.c

@@ -1632,6 +1632,23 @@ errout:
 	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);

+ 2 - 0
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);