Commit 7ae96d88 authored by Evan Hunt's avatar Evan Hunt
Browse files

[master] add "lock-file" and fix up singleton code

4080.	[func]		Completed change #4022, adding a "lock-file" option
			to named.conf to override the default lock file,
			in addition to the "named -X <filename>" command
			line option.  Setting the lock file to "none"
			using either method disables the check completely.
			[RT #37908]
parent 603de739
4080. [func] Completed change #4022, adding a "lock-file" option
to named.conf to override the default lock file,
in addition to the "named -X <filename>" command
line option. Setting the lock file to "none"
using either method disables the check completely.
[RT #37908]
4079. [func] Preserve the case of the ownername of records to
the RRset level. [RT #37442]
......
......@@ -82,6 +82,7 @@ options {\n\
nta-recheck 300;\n\
notify-rate 20;\n\
# pid-file \"" NS_LOCALSTATEDIR "/run/named/named.pid\"; /* or /lwresd.pid */\n\
# lock-file \"" NS_LOCALSTATEDIR "/run/named/named.lock\";\n\
port 53;\n\
prefetch 2 9;\n\
recursing-file \"named.recursing\";\n\
......
......@@ -134,9 +134,10 @@ EXTERN const char * ns_g_logfile INIT(NULL);
EXTERN const char * ns_g_defaultsessionkeyfile
INIT(NS_LOCALSTATEDIR "/run/named/"
"session.key");
EXTERN const char * ns_g_singletonfile INIT(NS_LOCALSTATEDIR
EXTERN const char * ns_g_defaultlockfile INIT(NS_LOCALSTATEDIR
"/run/named/"
"named.lock");
EXTERN isc_boolean_t ns_g_forcelock INIT(ISC_FALSE);
#if NS_RUN_PID_DIR
EXTERN const char * ns_g_defaultpidfile INIT(NS_LOCALSTATEDIR
......
......@@ -117,6 +117,8 @@ struct ns_server {
isc_uint16_t session_keybits;
isc_boolean_t interface_auto;
unsigned char secret[32]; /*%< Source Identity Token */
char * lockfile;
};
#define NS_SERVER_MAGIC ISC_MAGIC('S','V','E','R')
......
......@@ -676,7 +676,11 @@ parse_command_line(int argc, char *argv[]) {
/* Obsolete. No longer in use. Ignore. */
break;
case 'X':
ns_g_singletonfile = isc_commandline_argument;
ns_g_forcelock = ISC_TRUE;
if (strcasecmp(isc_commandline_argument, "none") != 0)
ns_g_defaultlockfile = isc_commandline_argument;
else
ns_g_defaultlockfile = NULL;
break;
case 'F':
/* Reserved for FIPS mode */
......@@ -1286,11 +1290,6 @@ main(int argc, char *argv[]) {
parse_command_line(argc, argv);
if (!ns_os_issingleton(ns_g_singletonfile))
ns_main_earlyfatal("could not lock %s; "
"another named process may be running",
ns_g_singletonfile);
/*
* Warn about common configuration error.
*/
......
......@@ -400,8 +400,11 @@
<para>
Acquire a lock on the specified file at runtime; this
helps to prevent duplicate <command>named</command> instances
from running simultaneously. If not specified via this option,
the default lockfile is <filename>/var/run/named/named.lock</filename>.
from running simultaneously.
Use of this option overrides the <command>lock-file</command>
option in <filename>named.conf</filename>.
If set to <literal>none</literal>, the lock file check
is disabled.
</para>
</listitem>
</varlistentry>
......
......@@ -5368,6 +5368,85 @@ count_zones(const cfg_obj_t *conf) {
return (n);
}
static isc_result_t
check_lockfile(ns_server_t *server, const cfg_obj_t *config,
isc_boolean_t first_time)
{
isc_result_t result;
const char *filename = NULL;
const cfg_obj_t *maps[3];
const cfg_obj_t *options;
const cfg_obj_t *obj;
int i;
i = 0;
options = NULL;
result = cfg_map_get(config, "options", &options);
if (result == ISC_R_SUCCESS)
maps[i++] = options;
maps[i++] = ns_g_defaults;
maps[i] = NULL;
obj = NULL;
(void) ns_config_get(maps, "lock-file", &obj);
if (!first_time) {
if (obj != NULL && !cfg_obj_isstring(obj) &&
server->lockfile != NULL &&
strcmp(cfg_obj_asstring(obj), server->lockfile) != 0)
isc_log_write(ns_g_lctx,
NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_SERVER,
ISC_LOG_WARNING,
"changing 'lock-file' "
"has no effect until the "
"server is restarted");
return (ISC_R_SUCCESS);
}
if (obj != NULL) {
if (cfg_obj_isvoid(obj)) {
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
"skipping lock-file check ");
return (ISC_R_SUCCESS);
} else if (ns_g_forcelock) {
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
"'lock-file' has no effect "
"because the server was run with -X");
server->lockfile = isc_mem_strdup(server->mctx,
ns_g_defaultlockfile);
} else {
filename = cfg_obj_asstring(obj);
server->lockfile = isc_mem_strdup(server->mctx,
filename);
}
if (server->lockfile == NULL)
return (ISC_R_NOMEMORY);
}
if (ns_g_forcelock && ns_g_defaultlockfile != NULL) {
INSIST(server->lockfile == NULL);
server->lockfile = isc_mem_strdup(server->mctx,
ns_g_defaultlockfile);
}
if (server->lockfile == NULL)
return (ISC_R_SUCCESS);
if (ns_os_issingleton(server->lockfile))
return (ISC_R_SUCCESS);
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
"could not lock %s; another named "
"process may be running", server->lockfile);
return (ISC_R_FAILURE);
}
static isc_result_t
load_configuration(const char *filename, ns_server_t *server,
isc_boolean_t first_time)
......@@ -5516,6 +5595,11 @@ load_configuration(const char *filename, ns_server_t *server,
*/
set_limits(maps);
/*
* Check the process lockfile.
*/
CHECK(check_lockfile(server, config, first_time));
/*
* Check if max number of open sockets that the system allows is
* sufficiently large. Failing this condition is not necessarily fatal,
......@@ -6870,6 +6954,8 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
server->session_keyalg = DST_ALG_UNKNOWN;
server->session_keybits = 0;
server->lockfile = NULL;
server->magic = NS_SERVER_MAGIC;
*serverp = server;
}
......@@ -6900,6 +6986,8 @@ ns_server_destroy(ns_server_t **serverp) {
isc_mem_free(server->mctx, server->hostname);
if (server->server_id != NULL)
isc_mem_free(server->mctx, server->server_id);
if (server->lockfile != NULL)
isc_mem_free(server->mctx, server->lockfile);
if (server->zonemgr != NULL)
dns_zonemgr_detach(&server->zonemgr);
......@@ -6932,6 +7020,7 @@ fatal(const char *msg, isc_result_t result) {
isc_result_totext(result));
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
ISC_LOG_CRITICAL, "exiting (due to fatal error)");
ns_os_shutdown();
exit(1);
}
......
......@@ -15,8 +15,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: os.c,v 1.107 2011/03/02 00:02:54 marka Exp $ */
/*! \file */
#include <config.h>
......@@ -54,6 +52,7 @@
#endif
static char *pidfile = NULL;
static char *lockfile = NULL;
static int devnullfd = -1;
static int singletonfd = -1;
......@@ -675,6 +674,27 @@ cleanup_pidfile(void) {
pidfile = NULL;
}
static void
cleanup_lockfile(void) {
if (singletonfd != -1) {
close(singletonfd);
singletonfd = -1;
}
if (lockfile != NULL) {
int n = unlink(lockfile);
if (n == -1 && errno != ENOENT)
ns_main_earlywarning("unlink '%s': failed", lockfile);
free(lockfile);
lockfile = NULL;
}
}
/*
* Ensure that a directory exists.
* NOTE: This function overwrites the '/' characters in 'filename' with
* nulls. The caller should copy the filename to a fresh buffer first.
*/
static int
mkdirpath(char *filename, void (*report)(const char *, ...)) {
char *slash = strrchr(filename, '/');
......@@ -903,19 +923,42 @@ ns_os_writepidfile(const char *filename, isc_boolean_t first_time) {
isc_boolean_t
ns_os_issingleton(const char *filename) {
char strbuf[ISC_STRERRORSIZE];
struct flock lock;
if (singletonfd != -1)
return (ISC_TRUE);
if (strcasecmp(filename, "none") == 0)
return (ISC_TRUE);
/*
* Make the containing directory if it doesn't exist.
*/
lockfile = strdup(filename);
if (lockfile == NULL) {
isc__strerror(errno, strbuf, sizeof(strbuf));
ns_main_earlyfatal("couldn't allocate memory for '%s': %s",
filename, strbuf);
} else {
int ret = mkdirpath(lockfile, ns_main_earlywarning);
if (ret == -1) {
ns_main_earlywarning("couldn't create '%s'", filename);
cleanup_lockfile();
return (ISC_FALSE);
}
}
/*
* ns_os_openfile() uses safeopen() which removes any existing
* files. We can't use that here.
*/
singletonfd = open(filename, O_WRONLY | O_CREAT,
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
if (singletonfd == -1)
if (singletonfd == -1) {
cleanup_lockfile();
return (ISC_FALSE);
}
memset(&lock, 0, sizeof(lock));
lock.l_type = F_WRLCK;
......@@ -937,11 +980,7 @@ void
ns_os_shutdown(void) {
closelog();
cleanup_pidfile();
if (singletonfd != -1) {
close(singletonfd);
singletonfd = -1;
}
cleanup_lockfile();
}
isc_result_t
......
......@@ -47,6 +47,7 @@
#include <named/ntservice.h>
static char *lockfile = NULL;
static char *pidfile = NULL;
static int devnullfd = -1;
static int singletonfd = -1;
......@@ -67,6 +68,7 @@ ns_paths_init(void) {
ns_g_conffile = isc_ntpaths_get(NAMED_CONF_PATH);
ns_g_defaultpidfile = isc_ntpaths_get(NAMED_PID_PATH);
lwresd_g_defaultpidfile = isc_ntpaths_get(LWRESD_PID_PATH);
ns_g_defaultlockfile = isc_ntpaths_get(NAMED_LOCK_PATH);
ns_g_keyfile = isc_ntpaths_get(RNDC_KEY_PATH);
ns_g_defaultsessionkeyfile = isc_ntpaths_get(SESSION_KEY_PATH);
......@@ -208,6 +210,22 @@ cleanup_pidfile(void) {
pidfile = NULL;
}
static void
cleanup_lockfile(void) {
if (singletonfile != -1) {
close(singletonfd);
singletonfd = -1;
}
if (lockfile != NULL) {
int n = unlink(lockfile);
if (n == -1 && errno != ENOENT)
ns_main_earlywarning("unlink '%s': failed", lockfile);
free(lockfile);
lockfile = NULL;
}
}
FILE *
ns_os_openfile(const char *filename, int mode, isc_boolean_t switch_user) {
char strbuf[ISC_STRERRORSIZE];
......@@ -291,28 +309,40 @@ ns_os_issingleton(const char *filename) {
if (singletonfd != -1)
return (ISC_TRUE);
if (strcasecmp(filename, "none") == 0)
return (ISC_TRUE);
lockfile = strdup(filename);
if (lockfile == NULL) {
isc__strerror(errno, strbuf, sizeof(strbuf));
ns_main_earlyfatal("couldn't allocate memory for '%s': %s",
filename, strbuf);
}
/*
* ns_os_openfile() uses safeopen() which removes any existing
* files. We can't use that here.
*/
singletonfd = open(filename, O_WRONLY | O_CREAT,
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
if (singletonfd == -1)
if (singletonfd == -1) {
cleanup_lockfile();
return (ISC_FALSE);
}
memset(&o, 0, sizeof(o));
/* Expect ERROR_LOCK_VIOLATION if already locked */
if (!LockFileEx((HANDLE) _get_osfhandle(singletonfd),
LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY,
0, 0, 1, &o)) {
close(singletonfd);
singletonfd = -1;
cleanup_lockfile();
return (ISC_FALSE);
}
return (ISC_TRUE);
}
void
ns_os_shutdown(void) {
closelog();
......
......@@ -16,4 +16,4 @@
rm -f */named.memstats
rm -f */named*.run
rm -f ns*/named.lock ns*/.nolock
rm -f ns*/named.lock ns*/named*.pid ns*/other.lock
/*
* Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
// NS2
controls { /* empty */ };
options {
query-source address 10.53.0.2;
port 5300;
pid-file "named4.pid";
lock-file none;
listen-on { 10.53.0.2; 10.53.0.3; };
listen-on-v6 { fd92:7065:b8e:ffff::2; };
recursion no;
notify yes;
dnssec-enable no;
dnssec-validation no;
};
#!/bin/sh -e
#
# Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
SYSTEMTESTTOP=..
. $SYSTEMTESTTOP/conf.sh
$SHELL clean.sh
......@@ -30,7 +30,7 @@ status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:verifying that named checks for conflicting listeners ($n)"
ret=0
(cd ns2; $NAMED -c named-alt1.conf -D ns2-extra-1 -X .nolock -m record,size,mctx -d 99 -g -U 4 >> named2.run 2>&1 & )
(cd ns2; $NAMED -c named-alt1.conf -D ns2-extra-1 -X other.lock -m record,size,mctx -d 99 -g -U 4 >> named2.run 2>&1 & )
sleep 2
grep "unable to listen on any configured interface" ns2/named2.run > /dev/null || ret=1
[ -s ns2/named2.pid ] && kill -15 `cat ns2/named2.pid`
......@@ -43,8 +43,19 @@ ret=0
(cd ns2; $NAMED -c named-alt2.conf -D ns2-extra-2 -X named.lock -m record,size,mctx -d 99 -g -U 4 >> named3.run 2>&1 & )
sleep 2
grep "another named process" ns2/named3.run > /dev/null || ret=1
[ -s ns2/named3.pid ] && kill -15 `cat ns3/named2.pid`
[ -s ns2/named3.pid ] && kill -15 `cat ns2/named3.pid`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:verifying that 'lock-file none' disables process check ($n)"
ret=0
(cd ns2; $NAMED -c named-alt3.conf -D ns2-extra-3 -m record,size,mctx -d 99 -g -U 4 >> named4.run 2>&1 & )
sleep 2
grep "another named process" ns2/named4.run > /dev/null && ret=1
[ -s ns2/named4.pid ] && kill -15 `cat ns2/named4.pid`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
exit $status
......@@ -4779,6 +4779,7 @@ badresp:1,adberr:0,findfail:0,valfail:0]
<optional> cache-file <replaceable>path_name</replaceable>; </optional>
<optional> dump-file <replaceable>path_name</replaceable>; </optional>
<optional> bindkeys-file <replaceable>path_name</replaceable>; </optional>
<optional> lock-file <replaceable>path_name</replaceable>; </optional>
<optional> secroots-file <replaceable>path_name</replaceable>; </optional>
<optional> session-keyfile <replaceable>path_name</replaceable>; </optional>
<optional> session-keyname <replaceable>key_name</replaceable>; </optional>
......@@ -5333,6 +5334,30 @@ badresp:1,adberr:0,findfail:0,valfail:0]
</listitem>
</varlistentry>
 
<varlistentry>
<term><command>lock-file</command></term>
<listitem>
<para>
The pathname of a file on which <command>named</command> will
attempt to acquire a file lock when starting up for
the first time; if unsuccessful, the server will
will terminate, under the assumption that another
server is already running. If not specified, the default is
<filename>/var/run/named/named.lock</filename>.
</para>
<para>
Specifying <command>lock-file none</command> disables the
use of a lock file. <command>lock-file</command> is
ignored if named was run using the <option>-X</option>
option, which overrides it. Changes to
<command>lock-file</command> are ignored if
<command>named</command> is being reloaded or
reconfigured; it is only effective when the server is
first started up.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>pid-file</command></term>
<listitem>
......
......@@ -266,10 +266,13 @@
other name server processes are running before starting up.
This is implemented in two ways: 1) by refusing to start
if the configured network interfaces all return "address
in use", and 2) by acquiring a file lock on
<filename>/var/run/named/named.lock</filename>, or on a different
file specified via the <command>named -X</command> command
line option.
in use", and 2) by attempting to acquire a lock on a file
specified by the <command>lock-file</option> option or
the <command>-X</command> command line option. The
default lock file is
<filename>/var/run/named/named.lock</filename>.
Specifying <literal>none</literal> will disable the lock
file check.
</para>
</listitem>
<listitem>
......
......@@ -38,6 +38,7 @@ enum NtPaths {
RNDC_CONF_PATH,
NAMED_PID_PATH,
LWRESD_PID_PATH,
NAMED_LOCK_PATH,
LOCAL_STATE_DIR,
SYS_CONF_DIR,
RNDC_KEY_PATH,
......
......@@ -41,6 +41,7 @@ static char lwresd_resolvconfFile[MAX_PATH];
static char rndc_confFile[MAX_PATH];
static char ns_defaultpidfile[MAX_PATH];
static char lwresd_defaultpidfile[MAX_PATH];
static char ns_lockfile[MAX_PATH];
static char local_state_dir[MAX_PATH];
static char sys_conf_dir[MAX_PATH];
static char rndc_keyFile[MAX_PATH];
......@@ -96,6 +97,9 @@ isc_ntpaths_init(void) {
strcpy(lwresd_defaultpidfile, namedBase);
strcat(lwresd_defaultpidfile, "\\etc\\lwresd.pid");
strcpy(ns_lockfile, namedBase);
strcat(ns_lockfile, "\\etc\\named.lock");
strcpy(local_state_dir, namedBase);
strcat(local_state_dir, "\\bin");
......@@ -129,6 +133,9 @@ isc_ntpaths_get(int ind) {
case LWRESD_PID_PATH:
return (lwresd_defaultpidfile);
break;
case NAMED_LOCK_PATH:
return (ns_lockfile);
break;
case LOCAL_STATE_DIR:
return (local_state_dir);
break;
......
......@@ -964,6 +964,7 @@ options_clauses[] = {
{ "keep-response-order", &cfg_type_bracketed_aml, 0 },
{ "listen-on", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI },
{ "listen-on-v6", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI },
{ "lock-file", &cfg_type_qstringornone, 0 },
#ifdef ISC_PLATFORM_USESIT
{ "sit-secret", &cfg_type_sstring, 0 },
#else
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment