Implement deamon-ising (`-f' to run in foreground).
log to syslog if deamon. implement `-t' option and chroot
This commit is contained in:
@@ -69,6 +69,11 @@ EXTERN const char * ns_g_conffile INIT("/etc/named.conf");
|
||||
* Misc.
|
||||
*/
|
||||
EXTERN isc_boolean_t ns_g_coreok INIT(ISC_TRUE);
|
||||
EXTERN const char * ns_g_chrootdir INIT(NULL);
|
||||
EXTERN isc_boolean_t ns_g_foreground INIT(ISC_FALSE);
|
||||
|
||||
EXTERN const char * ns_g_defaultpidfile INIT("/var/run/named.pid");
|
||||
EXTERN char * ns_g_pidfile INIT(NULL);
|
||||
|
||||
/*
|
||||
* XXX Temporary.
|
||||
|
||||
@@ -87,4 +87,10 @@ ns_server_reloadwanted(ns_server_t *server);
|
||||
* is ignored.
|
||||
*/
|
||||
|
||||
void
|
||||
ns_update_pidfile(const char *filename);
|
||||
/*
|
||||
* Save the pid to the given file
|
||||
*/
|
||||
|
||||
#endif /* NS_SERVER_H */
|
||||
|
||||
@@ -89,15 +89,25 @@ ns_log_init(void) {
|
||||
/*
|
||||
* Create and install the default channel.
|
||||
*/
|
||||
destination.file.stream = stderr;
|
||||
destination.file.name = NULL;
|
||||
destination.file.versions = ISC_LOG_ROLLNEVER;
|
||||
destination.file.maximum_size = 0;
|
||||
flags = ISC_LOG_PRINTTIME;
|
||||
result = isc_log_createchannel(ns_g_lctx, "_default",
|
||||
ISC_LOG_TOFILEDESC,
|
||||
ISC_LOG_DYNAMIC,
|
||||
&destination, flags);
|
||||
if (ns_g_foreground) {
|
||||
destination.file.stream = stderr;
|
||||
destination.file.name = NULL;
|
||||
destination.file.versions = ISC_LOG_ROLLNEVER;
|
||||
destination.file.maximum_size = 0;
|
||||
flags = ISC_LOG_PRINTTIME;
|
||||
result = isc_log_createchannel(ns_g_lctx, "_default",
|
||||
ISC_LOG_TOFILEDESC,
|
||||
ISC_LOG_DYNAMIC,
|
||||
&destination, flags);
|
||||
} else {
|
||||
destination.facility = LOG_DAEMON;
|
||||
flags = ISC_LOG_PRINTTIME;
|
||||
result = isc_log_createchannel(ns_g_lctx, "_default",
|
||||
ISC_LOG_TOSYSLOG,
|
||||
ISC_LOG_DYNAMIC,
|
||||
&destination, flags);
|
||||
}
|
||||
|
||||
if (result != ISC_R_SUCCESS)
|
||||
goto cleanup;
|
||||
result = isc_log_usechannel(ns_g_lctx, "_default", NULL, NULL);
|
||||
|
||||
@@ -19,11 +19,16 @@
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* XXX this include will need to go. It's here for _SC_OPEN_MAX */
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#include <isc/app.h>
|
||||
#include <isc/assertions.h>
|
||||
#include <isc/error.h>
|
||||
@@ -140,7 +145,7 @@ parse_command_line(int argc, char *argv[]) {
|
||||
int ch;
|
||||
|
||||
isc_commandline_errprint = ISC_FALSE;
|
||||
while ((ch = isc_commandline_parse(argc, argv, "b:c:d:N:p:sx:")) !=
|
||||
while ((ch = isc_commandline_parse(argc, argv, "b:c:d:fN:p:st:x:")) !=
|
||||
-1) {
|
||||
switch (ch) {
|
||||
case 'b':
|
||||
@@ -150,6 +155,9 @@ parse_command_line(int argc, char *argv[]) {
|
||||
case 'd':
|
||||
ns_g_debuglevel = atoi(isc_commandline_argument);
|
||||
break;
|
||||
case 'f':
|
||||
ns_g_foreground = ISC_TRUE;
|
||||
break;
|
||||
case 'N':
|
||||
ns_g_cpus = atoi(isc_commandline_argument);
|
||||
if (ns_g_cpus == 0)
|
||||
@@ -162,6 +170,10 @@ parse_command_line(int argc, char *argv[]) {
|
||||
/* XXXRTH temporary syntax */
|
||||
want_stats = ISC_TRUE;
|
||||
break;
|
||||
case 't':
|
||||
/* XXXJAB should be make a copy? */
|
||||
ns_g_chrootdir = isc_commandline_argument;
|
||||
break;
|
||||
case 'x':
|
||||
/* XXXRTH temporary syntax */
|
||||
ns_g_cachefile = isc_commandline_argument;
|
||||
@@ -251,16 +263,29 @@ cleanup() {
|
||||
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
|
||||
ISC_LOG_NOTICE, "exiting");
|
||||
ns_log_shutdown();
|
||||
|
||||
if (ns_g_pidfile != NULL) {
|
||||
(void)unlink(ns_g_pidfile);
|
||||
isc_mem_free(ns_g_mctx, ns_g_pidfile);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[]) {
|
||||
isc_result_t result;
|
||||
int n;
|
||||
|
||||
program_name = argv[0];
|
||||
isc_assertion_setcallback(assertion_failed);
|
||||
isc_error_setfatal(library_fatal_error);
|
||||
|
||||
for (n = sysconf(_SC_OPEN_MAX) - 1; n >= 0; n--)
|
||||
if (n != STDIN_FILENO &&
|
||||
n != STDOUT_FILENO &&
|
||||
n != STDERR_FILENO)
|
||||
(void) close(n);
|
||||
|
||||
|
||||
result = ns_os_init();
|
||||
if (result != ISC_R_SUCCESS)
|
||||
ns_main_earlyfatal("ns_os_init() failed: %s",
|
||||
@@ -281,6 +306,33 @@ main(int argc, char *argv[]) {
|
||||
|
||||
parse_command_line(argc, argv);
|
||||
|
||||
if (ns_g_chrootdir != NULL) {
|
||||
#ifdef HAVE_CHROOT
|
||||
if (chroot(ns_g_chrootdir) < 0) {
|
||||
ns_main_earlyfatal("chroot %s failed: %s\n",
|
||||
ns_g_chrootdir, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if (chdir("/") < 0) {
|
||||
ns_main_earlyfatal("chdir(\"/\") failed: %s\n",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
#else
|
||||
fprintf(stderr, "warning: chroot() not available\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* deamon() must be called before any threads are created
|
||||
* (fork() is deadly to threads). Threads get created in setup().
|
||||
*/
|
||||
if (ns_g_foreground == ISC_FALSE) {
|
||||
if (daemon(1, 0) != 0) {
|
||||
ns_main_earlyfatal("daemon(): %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
setup();
|
||||
|
||||
/*
|
||||
@@ -315,3 +367,5 @@ main(int argc, char *argv[]) {
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
@@ -101,6 +104,8 @@ typedef struct {
|
||||
|
||||
static void fatal(char *msg, isc_result_t result);
|
||||
static void ns_server_reload(isc_task_t *task, isc_event_t *event);
|
||||
static FILE *write_open(char *filename);
|
||||
|
||||
static isc_result_t
|
||||
ns_listenelt_fromconfig(dns_c_lstnon_t *celt, dns_c_ctx_t *cctx,
|
||||
dns_aclconfctx_t *actx,
|
||||
@@ -440,6 +445,7 @@ load_configuration(const char *filename, ns_server_t *server) {
|
||||
dns_view_t *view, *view_next;
|
||||
dns_viewlist_t tmpviewlist;
|
||||
dns_aclconfctx_t aclconfctx;
|
||||
char *pidfile;
|
||||
|
||||
dns_aclconfctx_init(&aclconfctx);
|
||||
|
||||
@@ -563,6 +569,15 @@ load_configuration(const char *filename, ns_server_t *server) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (dns_c_ctx_getpidfilename(configctx, &pidfile) == ISC_R_SUCCESS) {
|
||||
ns_update_pidfile(pidfile);
|
||||
} else {
|
||||
ns_update_pidfile(ns_g_defaultpidfile);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Swap our new view list with the production one.
|
||||
*/
|
||||
@@ -905,3 +920,83 @@ ns_listenelt_fromconfig(dns_c_lstnon_t *celt, dns_c_ctx_t *cctx,
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
void
|
||||
ns_update_pidfile(const char *pidfile)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
INSIST(pidfile != NULL);
|
||||
INSIST(strlen(pidfile) > 0);
|
||||
|
||||
if (ns_g_pidfile != NULL) {
|
||||
(void)unlink(ns_g_pidfile);
|
||||
isc_mem_free(ns_g_mctx, ns_g_pidfile);
|
||||
}
|
||||
|
||||
ns_g_pidfile = isc_mem_strdup(ns_g_mctx, (char *) pidfile);
|
||||
if (ns_g_pidfile == NULL) {
|
||||
fatal("failed to isc_mem_strdup() the pidfile",
|
||||
ISC_R_NOMEMORY);
|
||||
}
|
||||
|
||||
/* Not sure why I'm doing it this way, but bind8 did */
|
||||
fp = write_open(ns_g_pidfile);
|
||||
if (fp != NULL) {
|
||||
fprintf(fp, "%ld\n", (long)getpid());
|
||||
(void)fclose(fp);
|
||||
} else {
|
||||
isc_log_write(ns_g_lctx,
|
||||
NS_LOGCATEGORY_GENERAL,
|
||||
NS_LOGMODULE_SERVER,
|
||||
ISC_LOG_ERROR,
|
||||
"couldn't create pid file '%s'",
|
||||
ns_g_pidfile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static FILE *
|
||||
write_open(char *filename)
|
||||
{
|
||||
FILE *stream;
|
||||
int fd;
|
||||
struct stat sb;
|
||||
int regular;
|
||||
|
||||
if (stat(filename, &sb) < 0) {
|
||||
if (errno != ENOENT) {
|
||||
isc_log_write(ns_g_lctx,
|
||||
NS_LOGCATEGORY_GENERAL,
|
||||
NS_LOGMODULE_SERVER,
|
||||
ISC_LOG_ERROR,
|
||||
"write_open: stat of %s failed: %s",
|
||||
filename, strerror(errno));
|
||||
return (NULL);
|
||||
}
|
||||
regular = 1;
|
||||
} else
|
||||
regular = (sb.st_mode & S_IFREG);
|
||||
|
||||
if (!regular) {
|
||||
isc_log_write(ns_g_lctx,
|
||||
NS_LOGCATEGORY_GENERAL,
|
||||
NS_LOGMODULE_SERVER,
|
||||
ISC_LOG_ERROR,
|
||||
"write_open: %s isn't a regular file",
|
||||
filename);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
(void)unlink(filename);
|
||||
fd = open(filename, O_WRONLY|O_CREAT|O_EXCL,
|
||||
S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
|
||||
if (fd < 0)
|
||||
return (NULL);
|
||||
stream = fdopen(fd, "w");
|
||||
if (stream == NULL)
|
||||
(void)close(fd);
|
||||
return (stream);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user