mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-01-18 12:42:54 -05:00
config file: directory, logfile, pidfile. And they work too.
and log_warn. git-svn-id: file:///svn/unbound/trunk@139 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
c4d87f4f5d
commit
7e4700ec5f
15 changed files with 231 additions and 31 deletions
|
|
@ -62,10 +62,9 @@ daemon_init()
|
|||
}
|
||||
|
||||
int
|
||||
daemon_open_shared_ports(struct daemon* daemon, struct config_file* cfg)
|
||||
daemon_open_shared_ports(struct daemon* daemon)
|
||||
{
|
||||
log_assert(daemon);
|
||||
daemon->cfg = cfg;
|
||||
if(daemon->cfg->port == daemon->listening_port)
|
||||
return 1;
|
||||
listening_ports_free(daemon->ports);
|
||||
|
|
@ -116,5 +115,7 @@ daemon_delete(struct daemon* daemon)
|
|||
return;
|
||||
listening_ports_free(daemon->ports);
|
||||
lock_basic_destroy(&daemon->lock);
|
||||
free(daemon->cwd);
|
||||
free(daemon->pidfile);
|
||||
free(daemon);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,6 +56,10 @@ struct daemon {
|
|||
lock_basic_t lock;
|
||||
/** The config settings */
|
||||
struct config_file* cfg;
|
||||
/** current working directory */
|
||||
char* cwd;
|
||||
/** pidfile that is used */
|
||||
char* pidfile;
|
||||
/** port number that has ports opened. */
|
||||
int listening_port;
|
||||
/** listening ports, opened, to be shared by threads */
|
||||
|
|
@ -76,11 +80,11 @@ struct daemon* daemon_init();
|
|||
|
||||
/**
|
||||
* Open shared listening ports (if needed).
|
||||
* The cfg member pointer must have been set for the daemon.
|
||||
* @param daemon: the daemon.
|
||||
* @param cfg: the cfg settings. Applied to daemon.
|
||||
* @return: false on error.
|
||||
*/
|
||||
int daemon_open_shared_ports(struct daemon* daemon, struct config_file* cfg);
|
||||
int daemon_open_shared_ports(struct daemon* daemon);
|
||||
|
||||
/**
|
||||
* Fork workers and start service.
|
||||
|
|
|
|||
116
daemon/unbound.c
116
daemon/unbound.c
|
|
@ -44,6 +44,7 @@
|
|||
#include "util/log.h"
|
||||
#include "daemon/daemon.h"
|
||||
#include "util/config_file.h"
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <pwd.h>
|
||||
|
||||
|
|
@ -60,9 +61,100 @@ static void usage()
|
|||
printf("Report bugs to %s\n", PACKAGE_BUGREPORT);
|
||||
}
|
||||
|
||||
/** to changedir, logfile */
|
||||
static void
|
||||
apply_dir(struct daemon* daemon, struct config_file* cfg, int cmdline_verbose)
|
||||
{
|
||||
/* apply changes if they have changed */
|
||||
daemon->cfg = cfg;
|
||||
verbosity = cmdline_verbose + cfg->verbosity;
|
||||
if(cfg->directory && cfg->directory[0]) {
|
||||
if(!daemon->cwd || strcmp(daemon->cwd, cfg->directory) != 0) {
|
||||
if(chdir(cfg->directory)) {
|
||||
log_err("Could not chdir to %s: %s",
|
||||
cfg->directory, strerror(errno));
|
||||
}
|
||||
free(daemon->cwd);
|
||||
if(!(daemon->cwd = strdup(cfg->directory)))
|
||||
fatal_exit("malloc failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Read existing pid from pidfile. */
|
||||
static pid_t
|
||||
readpid (const char* file)
|
||||
{
|
||||
int fd;
|
||||
pid_t pid;
|
||||
char pidbuf[32];
|
||||
char* t;
|
||||
int l;
|
||||
|
||||
if ((fd = open(file, O_RDONLY)) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (((l = read(fd, pidbuf, sizeof(pidbuf)))) == -1) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
/* Empty pidfile means no pidfile... */
|
||||
if (l == 0) {
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
pid = strtol(pidbuf, &t, 10);
|
||||
|
||||
if (*t && *t != '\n') {
|
||||
return -1;
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
|
||||
/** write pid to file. */
|
||||
static void
|
||||
writepid (const char* pidfile, pid_t pid)
|
||||
{
|
||||
FILE* f;
|
||||
|
||||
if ((f = fopen(pidfile, "w")) == NULL ) {
|
||||
log_err("cannot open pidfile %s: %s",
|
||||
pidfile, strerror(errno));
|
||||
return;
|
||||
}
|
||||
if(fprintf(f, "%lu\n", (unsigned long)pid) < 0) {
|
||||
log_err("cannot write to pidfile %s: %s",
|
||||
pidfile, strerror(errno));
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
/** check old pid file */
|
||||
static void
|
||||
checkoldpid(struct config_file* cfg)
|
||||
{
|
||||
pid_t old;
|
||||
if((old = readpid(cfg->pidfile)) == -1) {
|
||||
if(errno != ENOENT) {
|
||||
log_err("Could not read pidfile %s: %s",
|
||||
cfg->pidfile, strerror(errno));
|
||||
}
|
||||
} else {
|
||||
/** see if it is still alive */
|
||||
if(kill(old, 0) == 0 || errno == EPERM)
|
||||
log_warn("unbound is already running as pid %u.", old);
|
||||
else log_warn("did not exit gracefully last time (%u)", old);
|
||||
}
|
||||
}
|
||||
|
||||
/** daemonize, drop user priviliges and chroot if needed */
|
||||
static void
|
||||
do_chroot(struct config_file* cfg)
|
||||
do_chroot(struct daemon* daemon, struct config_file* cfg)
|
||||
{
|
||||
log_assert(cfg);
|
||||
|
||||
|
|
@ -80,6 +172,13 @@ do_chroot(struct config_file* cfg)
|
|||
fatal_exit("unable to set user id: %s", strerror(errno));
|
||||
endpwent();
|
||||
}
|
||||
/* check old pid file before forking */
|
||||
if(cfg->pidfile && cfg->pidfile[0]) {
|
||||
checkoldpid(cfg);
|
||||
}
|
||||
|
||||
/* init logfile just before fork */
|
||||
log_init(cfg->logfile);
|
||||
if(cfg->do_daemonize) {
|
||||
int fd;
|
||||
/* Take off... */
|
||||
|
|
@ -87,6 +186,7 @@ do_chroot(struct config_file* cfg)
|
|||
case 0:
|
||||
break;
|
||||
case -1:
|
||||
unlink(cfg->pidfile);
|
||||
fatal_exit("fork failed: %s", strerror(errno));
|
||||
default:
|
||||
/* exit interactive session */
|
||||
|
|
@ -103,6 +203,10 @@ do_chroot(struct config_file* cfg)
|
|||
(void)close(fd);
|
||||
}
|
||||
}
|
||||
if(cfg->pidfile && cfg->pidfile[0]) {
|
||||
writepid(cfg->pidfile, getpid());
|
||||
daemon->pidfile = strdup(cfg->pidfile);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -129,13 +233,13 @@ static void run_daemon(const char* cfgfile, int cmdline_verbose)
|
|||
fatal_exit("Could not alloc config defaults");
|
||||
if(!config_read(cfg, cfgfile))
|
||||
fatal_exit("Could not read config file: %s", cfgfile);
|
||||
verbosity = cmdline_verbose + cfg->verbosity;
|
||||
apply_dir(daemon, cfg, cmdline_verbose);
|
||||
|
||||
/* prepare */
|
||||
if(!daemon_open_shared_ports(daemon, cfg))
|
||||
if(!daemon_open_shared_ports(daemon))
|
||||
fatal_exit("could not open ports");
|
||||
if(!done_chroot) {
|
||||
do_chroot(cfg);
|
||||
do_chroot(daemon, cfg);
|
||||
done_chroot = 1;
|
||||
}
|
||||
/* work */
|
||||
|
|
@ -147,6 +251,8 @@ static void run_daemon(const char* cfgfile, int cmdline_verbose)
|
|||
config_delete(cfg);
|
||||
}
|
||||
verbose(VERB_ALGO, "Exit cleanup.");
|
||||
if(daemon->pidfile)
|
||||
unlink(daemon->pidfile);
|
||||
daemon_delete(daemon);
|
||||
}
|
||||
|
||||
|
|
@ -168,7 +274,7 @@ main(int argc, char* argv[])
|
|||
const char* cfgfile = NULL;
|
||||
int cmdline_verbose = 0;
|
||||
|
||||
log_init();
|
||||
log_init(NULL);
|
||||
/* parse the options */
|
||||
while( (c=getopt(argc, argv, "c:hv")) != -1) {
|
||||
switch(c) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
And everything is started again (and listening ports if needed).
|
||||
- Ports for queries are shared.
|
||||
- config file added interface:, chroot: and username:.
|
||||
- config file: directory, logfile, pidfile. And they work too.
|
||||
|
||||
22 February 2007: Wouter
|
||||
- Have a config file. Removed commandline options, moved to config.
|
||||
|
|
|
|||
|
|
@ -57,8 +57,19 @@ server:
|
|||
# forward-to-port: 53
|
||||
|
||||
# if given, a chroot(2) is done to the given directory.
|
||||
# i.e. you can chroot to the working directory, for example,
|
||||
# for extra security, but make sure all files are in that directory.
|
||||
# chroot: "/some/directory"
|
||||
|
||||
# if given, user privileges are dropped (after binding port),
|
||||
# and the given username is assumed. Default is nothing "".
|
||||
# username: "unbound"
|
||||
|
||||
# the working directory.
|
||||
# directory: "/etc/unbound"
|
||||
|
||||
# the log file, "" means log to stderr.
|
||||
# logfile: ""
|
||||
|
||||
# the pid file.
|
||||
# pidfile: "unbound.pid"
|
||||
|
|
|
|||
|
|
@ -66,7 +66,6 @@ This is in addition to the verbosity (if any) from the config file.
|
|||
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr resolv.conf 5 ,
|
||||
.Xr unbound.conf 5 .
|
||||
|
||||
.Sh AUTHORS
|
||||
|
|
|
|||
|
|
@ -79,9 +79,19 @@ If given a chroot is done to the given directory. The default is none ("").
|
|||
.It \fBusername:\fR <name>
|
||||
If given, after binding the port the user privileges are dropped. Default is
|
||||
not to change user, username: "". If this user is not capable of binding the
|
||||
port, reloads (by signal HUP) will work, however, if you change the port
|
||||
number in the config file, and that port number requires privileges, then
|
||||
a reload will fail to bind to the new port number; a restart is needed.
|
||||
port, reloads (by signal HUP) will still retain the opened ports.
|
||||
If you change the port number in the config file, and that new port number
|
||||
requires privileges, then a restart is needed.
|
||||
.It \fBdirectory:\fR <directory>
|
||||
Sets the working directory for the program.
|
||||
.It \fBlogfile:\fR <filename>
|
||||
If "" is given, logging goes to stderr, or nowhere once daemonized.
|
||||
The logfile is appended to, in the following format:
|
||||
[seconds since 1970] unbound[pid]: type: message.
|
||||
.It \fBpidfile:\fR <filename>
|
||||
The process id is written to the file. Default is "unbound.pid". So,
|
||||
kill -HUP `cat /etc/unbound/unbound.pid` will trigger a reload,
|
||||
kill -QUIT `cat /etc/unbound/unbound.pid` will gracefully terminate.
|
||||
|
||||
.Sh FILES
|
||||
.Bl -tag -width indent
|
||||
|
|
|
|||
|
|
@ -151,6 +151,7 @@ main(int argc, char* argv[])
|
|||
char* init_optarg = optarg;
|
||||
struct replay_scenario* scen = NULL;
|
||||
|
||||
log_init(NULL);
|
||||
log_info("Start of %s testbound program.", PACKAGE_STRING);
|
||||
/* determine commandline options for the daemon */
|
||||
pass_argc = 1;
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ net_test()
|
|||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
log_init(NULL);
|
||||
if(argc != 1) {
|
||||
printf("usage: %s\n", argv[0]);
|
||||
printf("\tperforms unit tests.\n");
|
||||
|
|
|
|||
|
|
@ -77,18 +77,12 @@ config_create()
|
|||
cfg->do_tcp = 1;
|
||||
cfg->outgoing_base_port = cfg->port + 1000;
|
||||
cfg->outgoing_num_ports = 16;
|
||||
if(!(cfg->fwd_address = strdup(""))) {
|
||||
config_delete(cfg);
|
||||
return NULL;
|
||||
}
|
||||
if(!(cfg->username = strdup(""))) {
|
||||
config_delete(cfg);
|
||||
return NULL;
|
||||
}
|
||||
if(!(cfg->chrootdir = strdup(""))) {
|
||||
config_delete(cfg);
|
||||
return NULL;
|
||||
}
|
||||
if(!(cfg->fwd_address = strdup(""))) {config_delete(cfg); return NULL;}
|
||||
if(!(cfg->username = strdup(""))) {config_delete(cfg); return NULL;}
|
||||
if(!(cfg->chrootdir = strdup(""))) {config_delete(cfg); return NULL;}
|
||||
if(!(cfg->directory = strdup("/etc/unbound"))) {config_delete(cfg); return NULL;}
|
||||
if(!(cfg->logfile = strdup(""))) {config_delete(cfg); return NULL;}
|
||||
if(!(cfg->pidfile = strdup("unbound.pid"))) {config_delete(cfg); return NULL;}
|
||||
cfg->fwd_port = UNBOUND_DNS_PORT;
|
||||
cfg->do_daemonize = 0;
|
||||
cfg->num_ifs = 0;
|
||||
|
|
@ -140,6 +134,9 @@ config_delete(struct config_file* cfg)
|
|||
free(cfg->fwd_address);
|
||||
free(cfg->username);
|
||||
free(cfg->chrootdir);
|
||||
free(cfg->directory);
|
||||
free(cfg->logfile);
|
||||
free(cfg->pidfile);
|
||||
if(cfg->ifs) {
|
||||
int i;
|
||||
for(i=0; i<cfg->num_ifs; i++)
|
||||
|
|
|
|||
|
|
@ -83,6 +83,12 @@ struct config_file {
|
|||
char* chrootdir;
|
||||
/** username to change to, if not "". */
|
||||
char* username;
|
||||
/** working directory */
|
||||
char* directory;
|
||||
/** filename to log to. */
|
||||
char* logfile;
|
||||
/** pidfile to write pid to. */
|
||||
char* pidfile;
|
||||
|
||||
/** daemonize, i.e. fork into the background. */
|
||||
int do_daemonize;
|
||||
|
|
|
|||
|
|
@ -111,6 +111,9 @@ forward-to-port{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_FORWARD_TO_PORT;
|
|||
interface{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_INTERFACE;}
|
||||
chroot{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_CHROOT;}
|
||||
username{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_USERNAME;}
|
||||
directory{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DIRECTORY;}
|
||||
logfile{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_LOGFILE;}
|
||||
pidfile{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_PIDFILE;}
|
||||
{NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++;}
|
||||
|
||||
/* Quoted strings. Strip leading and ending quotes */
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ extern struct config_parser_state* cfg_parser;
|
|||
%token VAR_OUTGOING_PORT VAR_OUTGOING_RANGE VAR_INTERFACE
|
||||
%token VAR_DO_IP4 VAR_DO_IP6 VAR_DO_UDP VAR_DO_TCP
|
||||
%token VAR_FORWARD_TO VAR_FORWARD_TO_PORT VAR_CHROOT
|
||||
%token VAR_USERNAME
|
||||
%token VAR_USERNAME VAR_DIRECTORY VAR_LOGFILE VAR_PIDFILE
|
||||
|
||||
%%
|
||||
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
|
||||
|
|
@ -90,7 +90,7 @@ content_server: server_num_threads | server_verbosity | server_port |
|
|||
server_outgoing_port | server_outgoing_range | server_do_ip4 |
|
||||
server_do_ip6 | server_do_udp | server_do_tcp | server_forward_to |
|
||||
server_forward_to_port | server_interface | server_chroot |
|
||||
server_username;
|
||||
server_username | server_directory | server_logfile | server_pidfile;
|
||||
server_num_threads: VAR_NUM_THREADS STRING
|
||||
{
|
||||
OUTYY(("P(server_num_threads:%s)\n", $2));
|
||||
|
|
@ -215,6 +215,27 @@ server_username: VAR_USERNAME STRING
|
|||
cfg_parser->cfg->username = $2;
|
||||
}
|
||||
;
|
||||
server_directory: VAR_DIRECTORY STRING
|
||||
{
|
||||
OUTYY(("P(server_directory:%s)\n", $2));
|
||||
free(cfg_parser->cfg->directory);
|
||||
cfg_parser->cfg->directory = $2;
|
||||
}
|
||||
;
|
||||
server_logfile: VAR_LOGFILE STRING
|
||||
{
|
||||
OUTYY(("P(server_logfile:%s)\n", $2));
|
||||
free(cfg_parser->cfg->logfile);
|
||||
cfg_parser->cfg->logfile = $2;
|
||||
}
|
||||
;
|
||||
server_pidfile: VAR_PIDFILE STRING
|
||||
{
|
||||
OUTYY(("P(server_pidfile:%s)\n", $2));
|
||||
free(cfg_parser->cfg->pidfile);
|
||||
cfg_parser->cfg->pidfile = $2;
|
||||
}
|
||||
;
|
||||
%%
|
||||
|
||||
/* parse helper routines could be here */
|
||||
|
|
|
|||
37
util/log.c
37
util/log.c
|
|
@ -44,10 +44,28 @@
|
|||
#endif
|
||||
|
||||
enum verbosity_value verbosity = 0;
|
||||
static FILE* logfile = 0;
|
||||
|
||||
void
|
||||
log_init()
|
||||
log_init(const char* filename)
|
||||
{
|
||||
FILE *f;
|
||||
if(!filename || !filename[0]) {
|
||||
if(logfile && logfile != stderr)
|
||||
fclose(logfile);
|
||||
logfile = stderr;
|
||||
return;
|
||||
}
|
||||
/* open the file for logging */
|
||||
f = fopen(filename, "a");
|
||||
if(!f) {
|
||||
log_err("Could not open logfile %s: %s", filename,
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
if(logfile && logfile != stderr)
|
||||
fclose(logfile);
|
||||
logfile = f;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -56,9 +74,9 @@ log_vmsg(const char* type, const char *format, va_list args)
|
|||
char message[MAXSYSLOGMSGLEN];
|
||||
const char* ident="unbound";
|
||||
vsnprintf(message, sizeof(message), format, args);
|
||||
fprintf(stderr, "[%d] %s[%d] %s: %s\n",
|
||||
fprintf(logfile, "[%d] %s[%d] %s: %s\n",
|
||||
(int)time(NULL), ident, (int)getpid(), type, message);
|
||||
fflush(stderr);
|
||||
fflush(logfile);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -87,6 +105,19 @@ log_err(const char *format, ...)
|
|||
va_end(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* implementation of log_warn
|
||||
* @param format: format string printf-style.
|
||||
*/
|
||||
void
|
||||
log_warn(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
log_vmsg("warning", format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* implementation of fatal_exit
|
||||
* @param format: format string printf-style.
|
||||
|
|
|
|||
10
util/log.h
10
util/log.h
|
|
@ -76,8 +76,9 @@ void verbose(enum verbosity_value level,
|
|||
|
||||
/**
|
||||
* call this to initialize logging services.
|
||||
* @param filename: if NULL stderr is used.
|
||||
*/
|
||||
void log_init();
|
||||
void log_init(const char* filename);
|
||||
|
||||
/**
|
||||
* Log informational message.
|
||||
|
|
@ -93,6 +94,13 @@ void log_info(const char* format, ...) ATTR_FORMAT(printf, 1, 2);
|
|||
*/
|
||||
void log_err(const char* format, ...) ATTR_FORMAT(printf, 1, 2);
|
||||
|
||||
/**
|
||||
* Log warning message.
|
||||
* Pass printf formatted arguments. No trailing newline is needed.
|
||||
* @param format: printf-style format string. Arguments follow.
|
||||
*/
|
||||
void log_warn(const char* format, ...) ATTR_FORMAT(printf, 1, 2);
|
||||
|
||||
/**
|
||||
* Log fatal error message, and exit the current process.
|
||||
* Pass printf formatted arguments. No trailing newline is needed.
|
||||
|
|
|
|||
Loading…
Reference in a new issue