/* ntp_config.c
 *
 * This file contains the ntpd configuration code.
 *
 * Written By: Sachin Kamboj
 *             University of Delaware
 *             Newark, DE 19711
 * Some parts borrowed from the older ntp_config.c
 * Copyright (c) 2006
 */

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#ifdef HAVE_NETINFO
# include <netinfo/ni.h>
#endif

#include "ntpd.h"
#include "ntp_io.h"
#include "ntp_unixtime.h"
#include "ntp_refclock.h"
#include "ntp_filegen.h"
#include "ntp_stdlib.h"
#include "ntpsim.h"
#include <ntp_random.h>
#include <isc/net.h>
#include <isc/result.h>

#include <stdio.h>
#include <ctype.h>
#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
#include <signal.h>
#ifndef SIGCHLD
# define SIGCHLD SIGCLD
#endif
#if !defined(VMS)
# ifdef HAVE_SYS_WAIT_H
#  include <sys/wait.h>
# endif
#endif /* VMS */

#ifdef SYS_WINNT
# include <io.h>
HANDLE ResolverThreadHandle = NULL;
#endif /* SYS_WINNT */

/*
 * [Bug 467]: Some linux headers collide with CONFIG_PHONE and CONFIG_KEYS
 * so #include these later.
 */

#include "ntp_config.h"
#include "ntp_cmdargs.h"

#include "ntp_scanner.h"
#include "ntp_parser.h"
#include "ntp_data_structures.h"

void yyerror (char *msg);

extern int priority_done;


/*
 * "logconfig" building blocks
 */
struct masks {
	const char	  *name;
	unsigned long mask;
};

static struct masks logcfg_class[] = {
	{ "clock",		NLOG_OCLOCK },
	{ "peer",		NLOG_OPEER },
	{ "sync",		NLOG_OSYNC },
	{ "sys",		NLOG_OSYS },
	{ (char *)0,	0 }
};

static struct masks logcfg_item[] = {
	{ "info",		NLOG_INFO },
	{ "allinfo",		NLOG_SYSINFO|NLOG_PEERINFO|NLOG_CLOCKINFO|NLOG_SYNCINFO },
	{ "events",		NLOG_EVENT },
	{ "allevents",		NLOG_SYSEVENT|NLOG_PEEREVENT|NLOG_CLOCKEVENT|NLOG_SYNCEVENT },
	{ "status",		NLOG_STATUS },
	{ "allstatus",		NLOG_SYSSTATUS|NLOG_PEERSTATUS|NLOG_CLOCKSTATUS|NLOG_SYNCSTATUS },
	{ "statistics",		NLOG_STATIST },
	{ "allstatistics",	NLOG_SYSSTATIST|NLOG_PEERSTATIST|NLOG_CLOCKSTATIST|NLOG_SYNCSTATIST },
	{ "allclock",		(NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OCLOCK },
	{ "allpeer",		(NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OPEER },
	{ "allsys",		(NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OSYS },
	{ "allsync",		(NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OSYNC },
	{ "all",		NLOG_SYSMASK|NLOG_PEERMASK|NLOG_CLOCKMASK|NLOG_SYNCMASK },
	{ (char *)0,	0 }
};

/* Limits */
#define MAXPHONE	10	/* maximum number of phone strings */
#define MAXPPS		20	/* maximum length of PPS device string */

/*
 * Miscellaneous macros
 */
#define STRSAME(s1, s2)	(*(s1) == *(s2) && strcmp((s1), (s2)) == 0)
#define ISEOL(c)	((c) == '#' || (c) == '\n' || (c) == '\0')
#define ISSPACE(c)	((c) == ' ' || (c) == '\t')
#define STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)

#define KEY_TYPE_MD5	4

/*
 * File descriptor used by the resolver save routines, and temporary file
 * name.
 */
int call_resolver = 1;		/* ntp-genkeys sets this to 0, for example */
#ifndef SYS_WINNT
static char res_file[20];	/* enough for /tmp/ntpXXXXXX\0 */
#define RES_TEMPFILE	"/tmp/ntpXXXXXX"
#else
static char res_file[MAX_PATH];
#endif /* SYS_WINNT */

/*
 * Definitions of things either imported from or exported to outside
 */

int curr_include_level;			/* The current include level */
struct FILE_INFO *fp[MAXINCLUDELEVEL+1];
FILE *res_fp;
struct config_tree my_config;		/* Root of the configuration tree */
short default_ai_family = AF_UNSPEC;	/* Default either IPv4 or IPv6 */
char	*sys_phone[MAXPHONE] = {NULL};	/* ACTS phone numbers */
char	*keysdir = NTP_KEYSDIR;	/* crypto keys directory */
#if defined(HAVE_SCHED_SETSCHEDULER)
int	config_priority_override = 0;
int	config_priority;
#endif

const char *config_file;
#ifdef HAVE_NETINFO
struct netinfo_config_state *config_netinfo = NULL;
int check_netinfo = 1;
#endif /* HAVE_NETINFO */
#ifdef SYS_WINNT
char *alt_config_file;
LPTSTR temp;
char config_file_storage[MAX_PATH];
char alt_config_file_storage[MAX_PATH];
#endif /* SYS_WINNT */

#ifdef HAVE_NETINFO
/*
 * NetInfo configuration state
 */
struct netinfo_config_state {
	void *domain;		/* domain with config */
	ni_id config_dir;	/* ID config dir      */
	int prop_index;		/* current property   */
	int val_index;		/* current value      */
	char **val_list;       	/* value list         */
};
#endif

struct REMOTE_CONFIG_INFO remote_config;  /* Remote configuration buffer and
                                             pointer info */
int input_from_file = 1;     /* A boolean flag, which when set, indicates that
                                the input is to be taken from the configuration
                                file, instead of the remote-configuration buffer
                             */
/* int newline_is_special = 1; */ /* A boolean flag, which when set, implies that
				     newlines are special characters that need to
				     be returned as tokens */

int old_config_style = 1;    /* A boolean flag, which when set,
                              * indicates that the old configuration
                              * format with a newline at the end of
                              * every command is being used
                              */

extern int sys_maxclock;
extern char *stats_drift_file;	/* name of the driftfile */
extern char *leapseconds_file_name; /*name of the leapseconds file */

/* FUNCTION PROTOTYPES */

static int get_flags_from_list(queue *flag_list);
static void init_auth_node(void);
static void init_syntax_tree(void);
double *create_dval(double val);
void destroy_restrict_node(struct restrict_node *my_node);
static struct sockaddr_storage *get_next_address(struct address_node *addr);

static void config_other_modes(void);
static void config_auth(void);
static void config_tos(void);
static void config_monitor(void);
static void config_access(void);
static void config_tinker(void);
static void config_system_opts(void);
static void config_logconfig(void);
static void config_phone(void);
static void config_setvar(void);
static void config_ttl(void);
static void config_trap(void);
static void config_fudge(void);
static void config_vars(void);
static int is_sane_resolved_address(struct sockaddr_storage peeraddr, int hmode);
static int get_correct_host_mode(int hmode);
static void config_peers(void);
static void config_ntpd(void);
#ifdef SIM
static void config_sim(void);
static void config_ntpdsim(void);
#endif
void getconfig(int argc,char *argv[]);
enum gnn_type {
	t_UNK,		/* Unknown */
	t_REF,		/* Refclock */
	t_MSK		/* Network Mask */
};

static unsigned long get_pfxmatch(char **s,struct masks *m);
static unsigned long get_match(char *s,struct masks *m);
static unsigned long get_logmask(char *s);
static int getnetnum(const char *num,struct sockaddr_storage *addr,int complain,enum gnn_type a_type);
static int get_multiple_netnums(const char *num, struct sockaddr_storage *addr, struct addrinfo **res, int complain, enum gnn_type a_type);
static void save_resolve(char *name,int mode,int version,int minpoll,int maxpoll,u_int flags,int ttl,keyid_t keyid,u_char *keystr);
static void abort_resolve(void);
static void do_resolve_internal(void);


/* FUNCTIONS FOR INITIALIZATION
 * ----------------------------
 */

static int
get_flags_from_list(
	queue *flag_list
	)
{
	int flags = 0;
	struct attr_val *curr_flag;
    
	while (!empty(flag_list)) {
		curr_flag = (struct attr_val *) dequeue(flag_list);
		flags |= curr_flag->value.i;
		free_node(curr_flag);
	}
	return flags;
}

static void
init_auth_node(void)
{
	my_config.auth.autokey = 0;
	my_config.auth.control_key = 0;
	my_config.auth.crypto_cmd_list = NULL;
	my_config.auth.keys = NULL;
	my_config.auth.keysdir = NULL;
	my_config.auth.requested_key = 0;
	my_config.auth.revoke = 0;
	my_config.auth.trusted_key_list = NULL;
}

static void
init_syntax_tree(void)
{
	my_config.peers = create_queue();
	my_config.orphan_cmds = create_queue();
    
	my_config.broadcastclient = 0;
	my_config.manycastserver = create_queue();
	my_config.multicastclient = create_queue();

	my_config.stats_list = create_queue();
	my_config.stats_dir = NULL;
	my_config.filegen_opts = create_queue();

	my_config.discard_opts = create_queue();
	my_config.restrict_opts = create_queue();

	my_config.enable_opts = create_queue();
	my_config.disable_opts = create_queue();
	my_config.tinker = create_queue();
	my_config.fudge = create_queue();

	my_config.logconfig = create_queue();
	my_config.phone = create_queue();
	my_config.setvar = create_queue();
	my_config.ttl = create_queue();
	my_config.trap = create_queue();
	my_config.vars = create_queue();
	my_config.sim_details = NULL;
	init_auth_node();
}

/* FUNCTIONS FOR CREATING NODES ON THE SYNTAX TREE 
 * -----------------------------------------------
 */

queue *
enqueue_in_new_queue(
	void *my_node
	)
{ 
	queue *my_queue = create_queue();

	enqueue(my_queue, my_node);
	return my_queue;
}

struct attr_val *
create_attr_dval(
	int attr,
	double value
	)
{
	struct attr_val *my_val;

	my_val = (struct attr_val *)
	    get_node(sizeof(struct attr_val));
	my_val->attr = attr;
	my_val->value.d = value;
	my_val->type = T_Double;
	return my_val;
}

struct attr_val *
create_attr_ival(
	int attr,
	int value
	)
{
	struct attr_val *my_val;

	my_val = (struct attr_val *)
	    get_node(sizeof(struct attr_val));
	my_val->attr = attr;
	my_val->value.i = value;
	my_val->type = T_Integer;
	return my_val;
}

struct attr_val *
create_attr_sval(
	int attr,
	char *s
	)
{
	struct attr_val *my_val;

	my_val = (struct attr_val *)
	    get_node(sizeof(struct attr_val));
	my_val->attr = attr;
	if (s == NULL) 
		s = "\0";	/* free() and strdup() glow on NULL */
	my_val->value.s = strdup(s);
	my_val->type = T_String;
	return my_val;
}

struct attr_val *
create_attr_pval(
	int attr,
	void *p
	)
{
	struct attr_val *my_val;

	my_val = (struct attr_val *)
	    get_node(sizeof(struct attr_val));
	my_val->attr = attr;
	my_val->value.p = p;
	my_val->type = T_Void;
	return my_val;
}

int *
create_ival(
	int val
	)
{
	int *p = (int *)get_node(sizeof(int));

	*p = val;
	return p;
}

double *
create_dval(
	double val
	)
{
	double *p = (double *) get_node(sizeof(int));

	*p = val;
	return p;
}

void **
create_pval(
	void *val
	)
{
	void **p = (void **) get_node(sizeof(void *));

	*p = val;
	return p;
}

struct address_node *
create_address_node(
	char *addr,
	int type
	)
{
	struct address_node *my_node = (struct address_node *) 
	    get_node(sizeof(struct address_node));

	my_node->address = addr;
	my_node->type = type;
	return my_node;
}

struct peer_node *
create_peer_node(
	int hmode,
	struct address_node *addr,
	queue *options
	)
{
	struct peer_node* my_node;
	int errflag = 0;

	my_node = (struct peer_node *)
	    get_node(sizeof(struct peer_node));

	/* Initialze node values to default */
	my_node->minpoll = NTP_MINDPOLL;
	my_node->maxpoll = NTP_MAXDPOLL;
	my_node->ttl = 0;
	my_node->peerversion = NTP_VERSION;
	my_node->peerkey = 0;
	my_node->peerflags = 0;

	/* Now set the node to the read values */
	my_node->host_mode = hmode;
	my_node->addr = addr;
    
	while (options && !empty(options)) {
		struct attr_val *my_val = dequeue(options);

		/* Check the kind of option being set */
		switch(my_val->attr) { 
		    case T_Minpoll:
			if (my_val->value.i < NTP_MINPOLL) {
				msyslog(LOG_INFO,
					"minpoll: provided value (%d) is below minimum (%d)",
					my_val->value.i, NTP_MINPOLL);
				my_node->minpoll = NTP_MINPOLL;
			}
			else
				my_node->minpoll = my_val->value.i;
			break;
		    case T_Maxpoll:
			if (my_val->value.i > NTP_MAXPOLL) {
				msyslog(LOG_INFO,
					"maxpoll: provided value (%d) is above maximum (%d)",
					my_val->value.i, NTP_MAXPOLL);
				my_node->maxpoll = NTP_MAXPOLL;
			}
			else
				my_node->maxpoll = my_val->value.i;
			break;
		    case T_Ttl:
			if (my_node->ttl >= MAX_TTL) {
				msyslog(LOG_ERR, "ttl: invalid argument");
				errflag = 1;
			} 
			else
				my_node->ttl = my_val->value.i;
			break;
		    case T_Mode:
			my_node->ttl = my_val->value.i;
			break;
		    case T_Key:
			my_node->peerkey = my_val->value.i;
			my_node->peerflags |=  FLAG_AUTHENABLE;
			break;
		    case T_Version:
			my_node->peerversion = my_val->value.i;
			break;
		    case T_Flag:
			my_node->peerflags |= my_val->value.i;
			break;
		}
		free_node(my_val);
	}
	if (options)
		destroy_queue(options);
    
	/* Check if errors were reported. If yes, ignore the node */
	if (errflag) {
		free_node(my_node);
		return NULL;
	}
	return my_node;
}

struct filegen_node *
create_filegen_node(
	void **name, 
	queue *options
	)
{
	struct filegen_node *my_node = (struct filegen_node *)
	    get_node(sizeof(struct filegen_node));

	my_node->name = (char *) *name;
	free_node(name);

	my_node->options = options;
	return my_node;
}


struct restrict_node *
create_restrict_node(
	struct address_node *addr,
	struct address_node *mask,
	queue *flags,
	int line_no
	)
{
	struct restrict_node *my_node = (struct restrict_node *)
	    get_node(sizeof(struct restrict_node));

	my_node->addr = addr;
	my_node->mask = mask;
	my_node->flags = flags;
	my_node->line_no = line_no;
	return my_node;
}

void
destroy_restrict_node(
	struct restrict_node *my_node
	)
{
	/* With great care, free all the memory occupied by
	 * the restrict node
	 */
	if (my_node->addr)
		free_node(my_node->addr);
	if (my_node->mask)
		free_node(my_node->mask);
	if (my_node->flags)
		destroy_queue(my_node->flags);
	free_node(my_node);
}


struct setvar_node *
create_setvar_node(
	char *var,
	char *val,
	u_short def
	)
{
	int len1 = strlen(var);
	int len2 = strlen(val);
	char *s = (char *) emalloc(len1 + len2 + 2);
	struct setvar_node *my_node;
    
	/* Copy the var = val to s */
	strcpy(s, var);
	s[len1] = '=';
	strcpy(&s[len1 + 1], val);
	s[len1+len2+1] = '\0';
    
	free(var);
	free(val);

	/* Now store the string and its length into a setvar_node */
	my_node = (struct setvar_node *)
	    get_node(sizeof(struct setvar_node));
	my_node->data = s;
	my_node->len = len1 + len2 + 2;
	my_node->def = def;
	return my_node;
}

struct addr_opts_node *
create_addr_opts_node(
	struct address_node *addr, 
	queue *options
	)
{
	struct addr_opts_node *my_node = (struct addr_opts_node *)
	    get_node(sizeof(struct addr_opts_node));

	my_node->addr = addr;
	my_node->options = options;
	return my_node;
}

script_info *
create_sim_script_info(
	double duration,
	queue *script_queue
	)
{
#ifdef SIM
	return NULL;
#else
	script_info *my_info;
	struct attr_val *my_attr_val;
	my_info = (script_info *)get_node(sizeof(script_info));
	/* XXX: check the return value... */

	/* Initialize Script Info with default values*/
	my_info->duration = duration;
	my_info->freq_offset = 0;
	my_info->wander = 0;
	my_info->jitter = 0;
	my_info->prop_delay = NET_DLY;
	my_info->proc_delay = PROC_DLY;

	/* Traverse the script_queue and fill out non-default values */
	while (!empty(script_queue)) {
		my_attr_val = (struct attr_val *) dequeue(script_queue);
        
		/* Set the desired value */
		switch(my_attr_val->attr) {
		    case T_Freq_Offset:
			my_info->freq_offset = my_attr_val->value.d;
			break;
		    case T_Wander:
			my_info->wander = my_attr_val->value.d;
			break;
		    case T_Jitter:
			my_info->jitter = my_attr_val->value.d;
			break;
		    case T_Prop_Delay:
			my_info->prop_delay = my_attr_val->value.d;
			break;
		    case T_Proc_Delay:
			my_info->proc_delay = my_attr_val->value.d;
			break;
		    default:
			yyerror("ERROR!! Invalid script info in file\n");
			break;
		}
		free_node(my_attr_val);
	}
	destroy_queue(script_queue);
	return (my_info);
#endif
}


#define ADDR_LENGTH 16 + 1

static struct sockaddr_storage *
get_next_address(
	struct address_node *addr
	)
{
	static char *addr_prefix = "192.168.0.";
	static int curr_addr_no = 1;
	char addr_string[ADDR_LENGTH];

	struct sockaddr_storage *final_addr = (struct sockaddr_storage *) 
	    malloc(sizeof(struct sockaddr_storage));
	struct addrinfo *ptr;
	int retval;
    
	if (addr->type == T_String) {
		snprintf(addr_string, ADDR_LENGTH, "%s%d", addr_prefix, curr_addr_no++);
		printf("Selecting ip address %s for hostname %s\n", addr_string, addr->address);
		retval = getaddrinfo(addr_string, "ntp", NULL, &ptr);
	}
	else {
		retval = getaddrinfo(addr->address, "ntp", NULL, &ptr);
	}
    
	if (retval == 0) {
		memcpy(final_addr, ptr->ai_addr, ptr->ai_addrlen);
		fprintf(stderr, "Successful in setting ip address of simulated server to: %s\n", stoa(final_addr));
	}
	else {
		fprintf(stderr, "ERROR!! Could not get a new address\n");
		exit(1);
	}
	freeaddrinfo(ptr);
	return final_addr;
}
    

server_info *
create_sim_server(
	struct address_node *addr,
	double server_offset,
	queue *script
	)
{
#ifdef SIM
	return NULL;
#else
	server_info *my_info;
	my_info = (server_info *) get_node(sizeof(server_info));

	my_info->server_time = server_offset;
	my_info->addr = get_next_address(addr);
	my_info->script = script;
	my_info->curr_script = dequeue(my_info->script);
	return my_info;
#endif /* SIM */
}

struct sim_node *
create_sim_node(
	queue *init_opts,
	queue *servers
	)
{
	struct sim_node *my_node = (struct sim_node *) 
	    get_node(sizeof(struct sim_node));

	my_node->init_opts = init_opts;
	my_node->servers = servers;
	return my_node;
}


struct key_tok keyword_list[] = {
	{ "automax",		T_Automax,         NO_ARG },
	{ "broadcast",		T_Broadcast,       SINGLE_ARG },
	{ "broadcastclient",	T_Broadcastclient, NO_ARG },
	{ "broadcastdelay",	T_Broadcastdelay,  NO_ARG },
	{ "calldelay",		T_Calldelay,       NO_ARG },
	{ "disable",		T_Disable,         NO_ARG },
	{ "driftfile",		T_Driftfile,       SINGLE_ARG },
	{ "enable",		T_Enable,          NO_ARG },
	{ "end",		T_End,             NO_ARG },
	{ "filegen",		T_Filegen,         NO_ARG },
	{ "fudge",		T_Fudge,           SINGLE_ARG },
	{ "includefile",	T_Includefile,     SINGLE_ARG },
	{ "leapfile",		T_Leapfile,	   SINGLE_ARG },
	{ "logconfig",		T_Logconfig,       SINGLE_ARG },
	{ "logfile",		T_Logfile,         SINGLE_ARG },
	{ "manycastclient",	T_Manycastclient,  SINGLE_ARG },
	{ "manycastserver",	T_Manycastserver,  MULTIPLE_ARG },
	{ "multicastclient",	T_Multicastclient, MULTIPLE_ARG },
	{ "peer",		T_Peer,            SINGLE_ARG },
	{ "phone",		T_Phone,           MULTIPLE_ARG },
	{ "pidfile",		T_Pidfile,         SINGLE_ARG },
	{ "pool",		T_Pool,            SINGLE_ARG },
	{ "discard",		T_Discard,         NO_ARG },
	{ "restrict",		T_Restrict,        NO_ARG },    
	{ "server",		T_Server,          SINGLE_ARG },
	{ "setvar",		T_Setvar,          NO_ARG },
	{ "statistics",		T_Statistics,      NO_ARG },
	{ "statsdir",		T_Statsdir,        SINGLE_ARG },
	{ "tick",		T_Tick,            NO_ARG },
	{ "tinker",		T_Tinker,          NO_ARG },
	{ "tos",		T_Tos,             NO_ARG },
	{ "trap",		T_Trap,            SINGLE_ARG },
	{ "default",		T_Default,         NO_ARG },

/* authentication_command */
	{ "controlkey",		T_ControlKey,      NO_ARG },
	{ "crypto",		T_Crypto,          NO_ARG },
	{ "keys",		T_Keys,            SINGLE_ARG },
	{ "keysdir",		T_Keysdir,         SINGLE_ARG },
	{ "requestkey",		T_Requestkey,      NO_ARG },
	{ "revoke",		T_Revoke,          NO_ARG },
	{ "trustedkey",		T_Trustedkey,      NO_ARG },
/* option */
	{ "autokey",		T_Autokey,         NO_ARG },
	{ "burst",	        T_Burst,           NO_ARG },
	{ "iburst",	        T_Iburst,          NO_ARG },
	{ "key",		T_Key,             NO_ARG },
	{ "maxpoll",		T_Maxpoll,         NO_ARG },
	{ "minpoll",		T_Minpoll,         NO_ARG },
	{ "mode",		T_Mode,            NO_ARG },     
	{ "noselect",		T_Noselect,        NO_ARG },
	{ "preempt",		T_Preempt,         NO_ARG },
	{ "true",	        T_True,            NO_ARG },
	{ "prefer",	        T_Prefer,          NO_ARG },
	{ "ttl",	        T_Ttl,             NO_ARG },      
	{ "version",		T_Version,         NO_ARG },
/* crypto_command */
	{ "cert",		T_Cert,            SINGLE_ARG },
	{ "gqpar",		T_Gqpar,           SINGLE_ARG },
	{ "host",		T_Host,            SINGLE_ARG },
	{ "ident",		T_Ident,           SINGLE_ARG },
	{ "iffpar",		T_Iffpar,          SINGLE_ARG },
	{ "leap",		T_Leap,            SINGLE_ARG },
	{ "mvpar",		T_Mvpar,           SINGLE_ARG },
	{ "pw",			T_Pw,              SINGLE_ARG },
	{ "randfile",		T_RandFile,        SINGLE_ARG },
	{ "sign",		T_Sign,            SINGLE_ARG },
/*** MONITORING COMMANDS ***/
/* stat */
	{ "clockstats",		T_Clockstats,      NO_ARG },
	{ "cryptostats",	T_Cryptostats,     NO_ARG },
	{ "loopstats",		T_Loopstats,       NO_ARG },
	{ "peerstats",		T_Peerstats,       NO_ARG },
	{ "rawstats",		T_Rawstats,        NO_ARG },
	{ "sysstats", 		T_Sysstats,        NO_ARG },
/* filegen_option */
	{ "disable",		T_Disable,         NO_ARG },
	{ "enable",		T_Enable,          NO_ARG },
	{ "file",		T_File,            SINGLE_ARG },
	{ "link",		T_Link,            NO_ARG },
	{ "nolink",		T_Nolink,          NO_ARG },
	{ "type",		T_Type,            NO_ARG },
/* filegen_type */
	{ "age",		T_Age,             NO_ARG },
	{ "day",		T_Day,             NO_ARG },
	{ "month",		T_Month,           NO_ARG },
	{ "none",		T_None,            NO_ARG },
	{ "pid",		T_Pid,             NO_ARG },
	{ "week",	        T_Week,            NO_ARG },
	{ "year",		T_Year,            NO_ARG },
/*** ORPHAN MODE COMMANDS ***/
/* tos_option */
	{ "minclock",		T_Minclock,        NO_ARG },
	{ "maxclock",		T_Maxclock,        NO_ARG },
	{ "minsane",		T_Minsane,         NO_ARG },
	{ "floor",		T_Floor,           NO_ARG },
	{ "ceiling",		T_Ceiling,         NO_ARG },
	{ "cohort",		T_Cohort,          NO_ARG },
	{ "mindist",		T_Mindist,         NO_ARG },
	{ "maxdist",		T_Maxdist,         NO_ARG },
	{ "maxhop",		T_Maxhop,          NO_ARG },
	{ "beacon",		T_Beacon,          NO_ARG },
	{ "orphan",		T_Orphan,          NO_ARG },
/* access_control_flag */
	{ "ignore",		T_Ignore,          NO_ARG },
	{ "limited",		T_Limited,         NO_ARG },
	{ "kod",		T_Kod,             NO_ARG },
	{ "lowpriotrap",	T_Lowpriotrap,     NO_ARG },
	{ "mask",		T_Mask,            NO_ARG },
	{ "nomodify",		T_Nomodify,        NO_ARG },
	{ "nopeer",		T_Nopeer,          NO_ARG },
	{ "noquery",		T_Noquery,         NO_ARG },
	{ "noserve",		T_Noserve,         NO_ARG },
	{ "notrap",		T_Notrap,          NO_ARG },
	{ "notrust",		T_Notrust,         NO_ARG },
	{ "ntpport",		T_Ntpport,         NO_ARG },
	{ "version",		T_Version,         NO_ARG },
/* discard_option */
	{ "average",		T_Average,         NO_ARG },
	{ "minimum",		T_Minimum,         NO_ARG },
	{ "monitor",		T_Monitor,         NO_ARG },
/* fudge_factor */
	{ "flag1",		T_Flag1,           NO_ARG },
	{ "flag2",		T_Flag2,           NO_ARG },
	{ "flag3",		T_Flag3,           NO_ARG },
	{ "flag4",		T_Flag4,           NO_ARG },
	{ "refid",		T_Refid,           SINGLE_ARG },
	{ "stratum",		T_Stratum,         NO_ARG },
	{ "time1",		T_Time1,           NO_ARG },
	{ "time2",		T_Time2,           NO_ARG },
/* system_option */
	{ "auth",		T_Auth,            NO_ARG },
	{ "bclient",		T_Bclient,         NO_ARG },
	{ "calibrate",		T_Calibrate,       NO_ARG },
	{ "kernel",		T_Kernel,          NO_ARG },
	{ "monitor",		T_Monitor,         NO_ARG },
	{ "ntp",		T_Ntp,             NO_ARG },
	{ "stats",		T_Stats,           NO_ARG },
/* tinker_option */
	{ "step",		T_Step,            NO_ARG },
	{ "panic",		T_Panic,           NO_ARG },
	{ "dispersion",		T_Dispersion,      NO_ARG },
	{ "stepout",		T_Stepout,         NO_ARG },
	{ "allan",		T_Allan,           NO_ARG },
	{ "huffpuff",		T_Huffpuff,        NO_ARG },
	{ "freq",		T_Freq,            NO_ARG },
/* miscellaneous_command */
	{ "port",		T_Port,            NO_ARG },
	{ "interface",		T_Interface,       SINGLE_ARG },
/* simulator commands */
	{ "simulate",		T_Simulate,        NO_ARG },
	{ "simulation_duration",T_Sim_Duration,	   NO_ARG },
	{ "beep_delay",     	T_Beep_Delay,      NO_ARG },
	{ "duration",       	T_Duration,        NO_ARG },
	{ "server_offset",  	T_Server_Offset,   NO_ARG },
	{ "freq_offset",	T_Freq_Offset,     NO_ARG },
	{ "wander",         	T_Wander,          NO_ARG },
	{ "jitter",         	T_Jitter,          NO_ARG },
	{ "prop_delay",     	T_Prop_Delay,      NO_ARG },
	{ "proc_delay",     	T_Proc_Delay,      NO_ARG }, 
	{ NULL, 0, 0}
};


/* FUNCTIONS FOR PERFORMING THE CONFIGURATION
 * ------------------------------------------
 */

static void
config_other_modes(void)
{

	struct sockaddr_storage addr_sock;
	struct address_node *addr_node;

	if (my_config.broadcastclient) {
		proto_config(PROTO_BROADCLIENT, my_config.broadcastclient, 0., NULL);
		my_config.broadcastclient = 0;
	}
    
	/* Configure the many-cast servers */
	if (!empty(my_config.manycastserver)) {
		while (!empty(my_config.manycastserver)) {
			addr_node = (struct address_node *)
			    dequeue(my_config.manycastserver);
            
			memset((char *)&addr_sock, 0, sizeof(addr_sock));
			addr_sock.ss_family = addr_node->type;

			if (getnetnum(addr_node->address, &addr_sock, 1, t_UNK)  == 1)
				proto_config(PROTO_MULTICAST_ADD, 0, 0., &addr_sock);
            
			free(addr_node->address);
			free_node(addr_node);
		}
		sys_manycastserver = 1;
	}
    
	/* Configure the multicast clients */
	if (!empty(my_config.multicastclient)) {
		while (!empty(my_config.multicastclient)) {
			addr_node = (struct address_node *)
			    dequeue(my_config.multicastclient);
            
			memset((char *)&addr_sock, 0, sizeof(addr_sock));
			addr_sock.ss_family = addr_node->type;

			if (getnetnum(addr_node->address, &addr_sock, 1, t_UNK)  == 1)
				proto_config(PROTO_MULTICAST_ADD, 0, 0., &addr_sock);
            
            
			free(addr_node->address);
			free_node(addr_node);
		}
		proto_config(PROTO_MULTICAST_ADD, 1, 0., NULL);
	}
}


static void
config_auth(void)
{
	struct attr_val *my_val;
	int *key_val;
    
	/* Crypto Command */
	if (my_config.auth.crypto_cmd_list) {
		while (!empty(my_config.auth.crypto_cmd_list)) {
			my_val = (struct attr_val *) 
			    dequeue(my_config.auth.crypto_cmd_list);
#ifdef OPENSSL
			crypto_config(my_val->attr, my_val->value.s);
#endif /* OPENSSL */
			free(my_val->value.s);
			free_node(my_val);
		}
		destroy_queue(my_config.auth.crypto_cmd_list);
		my_config.auth.crypto_cmd_list = NULL;
	}

	/* Keysdir Command */
	if (my_config.auth.keysdir)
		keysdir = my_config.auth.keysdir;

#ifdef OPENSSL
	crypto_setup();
#endif /* OPENSSL */
 
	/* Keys Command */
	if (my_config.auth.keys)
		getauthkeys(my_config.auth.keys);
    
	/* Control Key Command */
	if (my_config.auth.control_key != 0) 
		ctl_auth_keyid = my_config.auth.control_key;

	/* Requested Key Command */
	if (my_config.auth.requested_key) {
#ifdef DEBUG
		if (debug > 3)
			printf("set info_auth_key to %08lx\n",
			       (long unsigned int) my_config.auth.requested_key);
#endif
		info_auth_keyid = (keyid_t) my_config.auth.requested_key;
	}

	/* Trusted Key Command */
	if (my_config.auth.trusted_key_list) {
		while (!empty(my_config.auth.trusted_key_list)) {
			key_val = (int *) dequeue(my_config.auth.trusted_key_list);
			authtrust(*key_val, 1);
			free_node(key_val);
		}
		destroy_queue(my_config.auth.trusted_key_list);
		my_config.auth.trusted_key_list = NULL;
	}
    
#ifdef OPENSSL
	/* Revoke Command */
	if (my_config.auth.revoke)
		sys_revoke = my_config.auth.revoke;
#endif /* OPENSSL */

#if !defined(VMS) && !defined(SYS_VXWORKS)
	/* find a keyid */
	if (info_auth_keyid == 0)
		req_keyid = 65535;
	else
		req_keyid = info_auth_keyid;

	/* if doesn't exist, make up one at random */
	if (!authhavekey(req_keyid)) {
		char rankey[9];
		int i, j;
        
		for (i = 0; i < 8; i++)
			for (j = 1; j < 100; ++j) {
				rankey[i] = (char) (ntp_random() & 0xff);
				if (rankey[i] != 0) break;
			}
		rankey[8] = 0;

		authusekey(req_keyid, KEY_TYPE_MD5, (u_char *)rankey);
		authtrust(req_keyid, 1);
		if (!authhavekey(req_keyid)) {
			msyslog(LOG_ERR, "getconfig: Couldn't generate a valid random key!");
			/* HMS: Should this be fatal? */
		}
	}

	/* save keyid so we will accept config requests with it */
	info_auth_keyid = req_keyid;
#endif /* !defined(VMS) && !defined(SYS_VXWORKS) */

}

static void
config_tos(void)
{
	struct attr_val *tos;
    
	while (!empty(my_config.orphan_cmds)) {
		tos = (struct attr_val *) dequeue(my_config.orphan_cmds);
		proto_config(tos->attr, 0, tos->value.d, NULL);
		free_node(tos);
	}
}

static void
config_monitor(void)
{
	char **filegen_string;
	FILEGEN *filegen;
	struct filegen_node *my_node;
	struct attr_val *my_opts;

	char *filegen_file;
	int filegen_type;
	int filegen_flag;
    
	/* Set the statistics directory */
	if (my_config.stats_dir) {
		stats_config(STATS_STATSDIR,my_config.stats_dir);
		free(my_config.stats_dir);
		my_config.stats_dir = NULL;
	}
    
	/* NOTE:
	 * Calling filegen_get is brain dead. Doing a string 
	 * comparison to find the relavant filegen structure is
	 * expensive.
	 *
	 * Through the parser, we already know which filegen is
	 * being specified. Hence, we should either store a
	 * pointer to the specified structure in the syntax tree
	 * or an index into a filegen array.
	 * 
	 * Need to change the filegen code to reflect the above.
	 */

	/* Turn on the specified statistics */
	while (!empty(my_config.stats_list)) {
		filegen_string = (char **) dequeue(my_config.stats_list);
		filegen = filegen_get(*filegen_string);

#ifdef DEBUG
		if (debug > 3)
			printf("enabling filegen for %s statistics \"%s%s\"\n",
			       *filegen_string, filegen->prefix, filegen->basename);
#endif
		filegen->flag |= FGEN_FLAG_ENABLED;
		free_node(filegen_string);
	}
    
	/* Configure the statistics with the options */
	while (!empty(my_config.filegen_opts)) {
		my_node = (struct filegen_node *) dequeue(my_config.filegen_opts);
		filegen = filegen_get(my_node->name);

		/* Initilize the filegen variables to their pre-configurtion states */
		filegen_flag = filegen->flag;
		filegen_type = filegen->type;
		filegen_file = my_node->name; 

		while (!empty(my_node->options)) {
			my_opts = (struct attr_val *) dequeue(my_node->options);
			switch (my_opts->attr) {
			    case T_File:
				filegen_file = (char *) my_opts->value.p;
				break;
			    case T_Type:
				filegen_type = my_opts->value.i;
				break;
			    case T_Flag:
				switch (my_opts->value.i) {
				    case T_Link:
					filegen_flag |= FGEN_FLAG_LINK;
					break;
				    case T_Nolink:
					filegen_flag &= ~FGEN_FLAG_LINK;
					break;
				    case T_Enable:
					filegen_flag |= FGEN_FLAG_ENABLED;
					break;
				    case T_Disable:
					filegen_flag &= ~FGEN_FLAG_ENABLED;
					break;
				}
				break;
			}
			filegen_config(filegen, filegen_file, filegen_type, filegen_flag);
			free_node(my_opts);
		}
		free_node(my_node);
	}
}


static void
config_access(void) 
{
	struct attr_val *my_opt;
	struct restrict_node *my_node;
    
	struct sockaddr_storage addr_sock;
	struct sockaddr_storage addr_mask;

	int flags;
	int mflags;

	/* Configure the discard options */
	while (!empty(my_config.discard_opts)) {
		my_opt = (struct attr_val *)
		    dequeue(my_config.discard_opts);
		switch(my_opt->attr) {
		    case T_Average:
			res_avg_interval = my_opt->value.i;
			break;
		    case T_Minimum:
			res_min_interval = my_opt->value.i;
			break;
		    case T_Monitor:
			mon_age = my_opt->value.i;
			break;
		}
		free_node(my_opt);
	}

	/* Configure the restrict options */
	while (!empty(my_config.restrict_opts)) {
		my_node = (struct restrict_node *)
		    dequeue(my_config.restrict_opts);

		memset((char *)&addr_sock, 0, sizeof(addr_sock));
		/* Check if the user specified a default rule */
		if (my_node->addr) {
			/* Resolve the specified address */
			addr_sock.ss_family = my_node->addr->type;
            
			if (getnetnum(my_node->addr->address, 
				      &addr_sock, 1,t_UNK) != 1) {
                
				/* Error in resolving name!!!
				 * Free the node memory and move onto the next
				 * Restrict flag 
				 */
				msyslog(LOG_INFO,
					"restrict: error in resolving name: %s on line %d. Ignoring...",
					my_node->addr->address, my_node->line_no);
				destroy_restrict_node(my_node);
				continue;
			}
            
			SET_HOSTMASK(&addr_mask, addr_sock.ss_family);
            
			/* Resolve the mask */
			if (my_node->mask) {
				memset((char *)&addr_mask, 0, sizeof(addr_mask));
				addr_mask.ss_family = my_node->mask->type;
				if (getnetnum(my_node->mask->address, &addr_mask, 1, t_MSK) != 1) {
					/* Error in mask !!!
					 * Free the node memory and move onto the next
					 * Restrict flag 
					 */
					msyslog(LOG_INFO,
						"restrict: error in resolving mask: %s on line %d. Ignoring...",
						my_node->mask->address, my_node->line_no);
					destroy_restrict_node(my_node);
					continue;
				}
			}
		}
		else { /* The user specified a default rule */
			addr_sock.ss_family = default_ai_family;
			ANYSOCK(&addr_mask);
		}
        
		/* Parse the flags */
		flags = 0;
		mflags = 0;
        
		while (!empty(my_node->flags)) {
			int *curr_flag = (int *) dequeue(my_node->flags);
			if (*curr_flag == RESM_NTPONLY)
				mflags |= *curr_flag;
			else
				flags |= *curr_flag;
			free_node(curr_flag);
		}   

		/* Set the flags */        
		hack_restrict(RESTRICT_FLAGS, &addr_sock, &addr_mask,
			      mflags, flags);
		destroy_restrict_node(my_node);
	}
}


static void
config_tinker(void)
{
	struct attr_val *tinker;
    
	while (!empty(my_config.tinker)) {
		tinker= (struct attr_val *) dequeue(my_config.tinker);
		loop_config(tinker->attr, tinker->value.d);
		free_node(tinker);
	}
}


static void
config_system_opts(void) 
{
	int enable_flags;
	int disable_flags;

	enable_flags = get_flags_from_list(my_config.enable_opts);
	disable_flags = get_flags_from_list(my_config.disable_opts);
    
	if (enable_flags)
		proto_config(enable_flags, 1, 0., NULL);
	if (disable_flags)
		proto_config(disable_flags, 0, 0., NULL);
}

static void
config_logconfig(void)
{
	struct attr_val *my_logconfig;

	while(!empty(my_config.logconfig)) {
		my_logconfig = (struct attr_val *)
		    dequeue(my_config.logconfig);
		switch (my_logconfig->attr) {
		    case '+':
			ntp_syslogmask |= get_logmask(my_logconfig->value.s);
			break;
		    case '-':
			ntp_syslogmask &= ~get_logmask(my_logconfig->value.s);
			break;
		    case '=':
			ntp_syslogmask = get_logmask(my_logconfig->value.s);
			break;
		}
		free(my_logconfig->value.s);
		free_node(my_logconfig);
	}
}

static void
config_phone(void)
{
	int i = 0;
	char **s;
    
	while (!empty(my_config.phone)) {
		s = (char **) dequeue(my_config.phone);
		if (i < MAXPHONE)
			sys_phone[i++] = *s;
		else {
			msyslog(LOG_INFO,
				"phone: Number of phone entries exceeds %d. Ignoring phone %s...",
				MAXPHONE, *s);
			free(*s);
		}
		free_node(s);
	}
	if (i)
		sys_phone[i] = NULL;
}

static void
config_setvar(void)
{
	struct setvar_node *my_node;

	while (!empty(my_config.setvar)) {
		my_node = (struct setvar_node *) dequeue(my_config.setvar);
		set_sys_var(my_node->data, my_node->len, my_node->def);
		free_node(my_node);
	}
}

static void
config_ttl(void)
{
	int i = 0;
	int *curr_ttl;
    
	while (!empty(my_config.ttl)) {
		curr_ttl = (int *) dequeue(my_config.ttl);
		if (i < MAX_TTL)
			sys_ttl[i++] = *curr_ttl;
		else 
			msyslog(LOG_INFO,
				"ttl: Number of TTL entries exceeds %d. Ignoring TTL %d...",
				MAX_TTL, *curr_ttl);
     
		free_node(curr_ttl);
	}
	sys_ttlmax = i - 1;
}

static void
config_trap(void)
{
    
	struct addr_opts_node *curr_trap;
	struct attr_val *curr_opt;
	struct sockaddr_storage addr_sock;
	struct sockaddr_storage peeraddr;
	struct address_node *addr_node;
	struct interface *localaddr;
	int port_no;
	int err_flag;
    
	port_no = 0;
	localaddr = 0;

    
	while (!empty(my_config.trap)) {
		err_flag = 0;
		curr_trap = (struct addr_opts_node *) dequeue(my_config.trap);
        
		while (!empty(curr_trap->options)) {
			curr_opt = (struct attr_val *) dequeue(curr_trap->options);
			if (curr_opt->attr == T_Port) {
				port_no = curr_opt->value.i;
				if (port_no <= 0 || port_no > 32767) {
					msyslog(LOG_ERR, "invalid port number %d, trap ignored", port_no);
					err_flag = 1;
				}
			}
			else if (curr_opt->attr == T_Interface) {
				addr_node = (struct address_node *) curr_opt->value.p;

				/* Resolve the interface address */
				memset((char *)&addr_sock, 0, sizeof(addr_sock));
				addr_sock.ss_family = addr_node->type;
                
				if (getnetnum(addr_node->address,
					      &addr_sock, 1, t_UNK) != 1) {
					err_flag = 1;
					break;
				}
                
				localaddr = findinterface(&addr_sock);
                
				if (localaddr == NULL) {
					msyslog(LOG_ERR,
						"can't find interface with address %s",
						stoa(&addr_sock));
					err_flag = 1;
				}
                
				free(addr_node->address);
				free_node(addr_node);
			}
			free_node(curr_opt);
		}
        
		/* Now process the trap for the specified interface
		 * and port number 
		 */
		if (!err_flag) {
			memset((char *)&peeraddr, 0, sizeof(peeraddr));
			if (port_no != 0)
				((struct sockaddr_in6*)&peeraddr)->sin6_port = htons((u_short) port_no);
			else
				((struct sockaddr_in6*)&peeraddr)->sin6_port = htons(TRAPPORT);

			if (localaddr == NULL) {
				peeraddr.ss_family = default_ai_family;
				localaddr = ANY_INTERFACE_CHOOSE(&peeraddr);
			}
			else
				peeraddr.ss_family = addr_sock.ss_family;
            
			if (!ctlsettrap(&peeraddr, localaddr, 0,
					NTP_VERSION))
				msyslog(LOG_ERR,
					"can't set trap for %s, no resources",
					stoa(&peeraddr));
		}
		destroy_queue(curr_trap->options);
		free_node(curr_trap);
	}    
}

static void
config_fudge(void)
{
	struct addr_opts_node *curr_fudge;
	struct attr_val *curr_opt;
	struct sockaddr_storage addr_sock;
	struct address_node *addr_node;
	struct refclockstat clock_stat;
	int err_flag;
    
    
	while (!empty(my_config.fudge)) {
		curr_fudge = (struct addr_opts_node *) dequeue(my_config.fudge);
		err_flag = 0;
        
		/* Get the reference clock address and
		 * ensure that it is sane
		 */
		addr_node = curr_fudge->addr;
		memset((char *)&addr_sock, 0, sizeof(addr_sock));
		if (getnetnum(addr_node->address, &addr_sock, 1, t_REF) != 1)
			err_flag = 1;
        
		if (!ISREFCLOCKADR(&addr_sock)) {
			msyslog(LOG_ERR,
				"%s is inappropriate address for the fudge command, line ignored",
				stoa(&addr_sock));
			err_flag = 1;
		}

		/* Parse all the options to the fudge command */
		memset((void *)&clock_stat, 0, sizeof clock_stat);
		while (!empty(curr_fudge->options)) {
			curr_opt = (struct attr_val *) dequeue(curr_fudge->options);
            
			/* The attribute field is used to store the flag. 
			 * Set haveflags with it
			 */
			clock_stat.haveflags |= curr_opt->attr;
			switch (curr_opt->attr) {
			    case CLK_HAVETIME1:
				clock_stat.fudgetime1 = curr_opt->value.d;
				break;
			    case CLK_HAVETIME2:
				clock_stat.fudgetime2 = curr_opt->value.d;
				break;
			    case CLK_HAVEVAL1:
				clock_stat.fudgeval1 = curr_opt->value.i;
				break;
			    case CLK_HAVEVAL2:
				memcpy(&clock_stat.fudgeval2,
				       curr_opt->value.s, 
				       min(strlen(curr_opt->value.s), 4));
				free(curr_opt->value.s);
				break;
			    case CLK_HAVEFLAG1:
				if (curr_opt->value.i)
					clock_stat.flags |= CLK_FLAG1;
				else
					clock_stat.flags &= ~CLK_FLAG1;
				break;
			    case CLK_HAVEFLAG2:
				if (curr_opt->value.i)
					clock_stat.flags |= CLK_FLAG2;
				else
					clock_stat.flags &= ~CLK_FLAG2;
				break;
			    case CLK_HAVEFLAG3:
				if (curr_opt->value.i)
					clock_stat.flags |= CLK_FLAG3;
				else
					clock_stat.flags &= ~CLK_FLAG3;
				break;
			    case CLK_HAVEFLAG4:
				if (curr_opt->value.i)
					clock_stat.flags |= CLK_FLAG4;
				else
					clock_stat.flags &= ~CLK_FLAG4;
				break;
			}
            
			free_node(curr_opt);
		}

#ifdef REFCLOCK
		if (!err_flag)
			refclock_control(&addr_sock, &clock_stat,
					 (struct refclockstat *)0);
#endif

		destroy_queue(curr_fudge->options);
		free_node(curr_fudge);
	}
}

static void
config_vars(void)
{
	struct attr_val *curr_var;
	FILE *new_file;
    
	while (!empty(my_config.vars)) {
		curr_var = (struct attr_val *) dequeue(my_config.vars);
		/* Determine which variable to set and set it */
		switch (curr_var->attr) {
		    case T_Broadcastdelay:
			proto_config(PROTO_BROADDELAY, 0, curr_var->value.d, NULL);
			break;
		    case T_Calldelay:
			proto_config(PROTO_CALLDELAY, curr_var->value.i, 0, NULL);
			break;
		    case T_Tick:
			proto_config(PROTO_ADJ, 0, curr_var->value.d, NULL);
			break;
		    case T_Driftfile:
			if (!strcmp(curr_var->value.s, "\0")) { 
				stats_drift_file = 0;
				msyslog(LOG_INFO, "config: driftfile disabled\n");
			} else { 
				stats_config(STATS_FREQ_FILE, curr_var->value.s);
				free(curr_var->value.s);
			}
			break;
		    case T_WanderThreshold:
			wander_threshold = curr_var->value.d;
			break;
		    case T_Leapfile:
			stats_config(STATS_LEAP_FILE, curr_var->value.s);
			free(curr_var->value.s);
			break;
		    case T_Pidfile:
			stats_config(STATS_PID_FILE, curr_var->value.s);
			free(curr_var->value.s);
			break;
		    case T_Logfile:
			new_file = fopen(curr_var->value.s, "a");
			if (new_file != NULL) {
				NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */
				    msyslog(LOG_NOTICE, "logging to file %s", curr_var->value.s);
				if (syslog_file != NULL &&
				    fileno(syslog_file) != fileno(new_file))
					(void)fclose(syslog_file);

				syslog_file = new_file;
				syslogit = 0;
			}
			else
				msyslog(LOG_ERR,
					"Cannot open log file %s",
					curr_var->value.s);
			free(curr_var->value.s);
			break;
#ifdef OPENSSL
		    case T_Automax:
			sys_automax = curr_var->value.i;
			break;
#endif
		}
		free_node(curr_var);
	}
}

/* Define a function to check if a resolved address is sane.
 * If yes, return 1, else return 0;
 */
static int
is_sane_resolved_address(
	struct sockaddr_storage peeraddr,
	int hmode
	)
{
	if (
#ifdef REFCLOCK
		!ISREFCLOCKADR(&peeraddr) &&
#endif
		ISBADADR(&peeraddr)) {
		msyslog(LOG_ERR,
			"attempt to configure invalid address %s",
			stoa(&peeraddr));
		return 0;
	}
	/*
	 * Shouldn't be able to specify multicast
	 * address for server/peer!
	 * and unicast address for manycastclient!
	 */
	/* Check for IPv4 */
	if (peeraddr.ss_family == AF_INET) {
		if (((hmode == T_Server) || (hmode == T_Peer) || (hmode == T_Pool)) &&
#ifdef REFCLOCK
		    !ISREFCLOCKADR(&peeraddr) &&
#endif
		    IN_CLASSD(ntohl(((struct sockaddr_in*)&peeraddr)->sin_addr.s_addr))) {
			msyslog(LOG_ERR,
				"attempt to configure invalid address %s",
				stoa(&peeraddr));
			return 0;
		}
		if ((hmode == T_Manycastclient) &&
		    !IN_CLASSD(ntohl(((struct sockaddr_in*)&peeraddr)->sin_addr.s_addr))) {
			msyslog(LOG_ERR,
				"attempt to configure invalid address %s",
				stoa(&peeraddr));
			return 0;
		}
         
	}
	/* Check for IPv6 */
	else if(peeraddr.ss_family == AF_INET6) {
		if (((hmode == T_Server) || (hmode == T_Peer) || (hmode == T_Pool)) &&
#ifdef REFCLOCK
		    !ISREFCLOCKADR(&peeraddr) &&
#endif
		    IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)&peeraddr)->sin6_addr)) {
			msyslog(LOG_ERR,
				"attempt to configure in valid address %s",
				stoa(&peeraddr));
			return 0;
		}
		if ((hmode == T_Manycastclient) &&
		    !IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)&peeraddr)->sin6_addr)) {
			msyslog(LOG_ERR,
				"attempt to configure in valid address %s",
				stoa(&peeraddr));
			return 0;
		}
	}
    
	if (peeraddr.ss_family == AF_INET6 &&
	    isc_net_probeipv6() != ISC_R_SUCCESS)
		return 0;

	/* Ok, all tests succeeded, now we can return 1 */
	return 1;
}

static int
get_correct_host_mode(
	int hmode
	)
{ 
	switch (hmode) {
	    case T_Server:
	    case T_Pool:
	    case T_Manycastclient:
		return MODE_CLIENT;
		break;
	    case T_Peer:
		return MODE_ACTIVE;
		break;
	    case T_Broadcast:
		return MODE_BROADCAST;
		break;
	    default:
		fprintf(stderr, "Fatal error in client_type in ntp_config.y");
		exit(1);
		break;
	}
}

static void
config_peers(void)
{
	struct addrinfo *res, *res_bak;
	struct sockaddr_storage peeraddr;
	struct peer_node *curr_peer;
	int hmode;
	int status;
	int no_needed;
	int i;
    
	while (!empty(my_config.peers)) {
		curr_peer = (struct peer_node *) dequeue(my_config.peers);
        
		/* Find the number of associations needed.
		 * If a pool coomand is specified, then sys_maxclock needed
		 * else, only one is needed
		 */
		no_needed = (curr_peer->host_mode == T_Pool) ? sys_maxclock : 1;

		/* Find the correct host-mode */
		hmode = get_correct_host_mode(curr_peer->host_mode);
        
		/* Attempt to resolve the address */
		memset((char *)&peeraddr, 0, sizeof(peeraddr));
		peeraddr.ss_family = curr_peer->addr->type;
        
		status = get_multiple_netnums(curr_peer->addr->address, &peeraddr, &res, 0, t_UNK);
        
		/* I don't know why getnetnum would return -1.
		 * The old code had this test, so I guess it must be
		 * useful 
		 */
		if (status == -1) {
			/* Do nothing, apparantly we found an IPv6
			 * address and can't do anything about it */
		}
		/* Check if name resolution failed. If yes, store the
		 * peer information in a file for asynchronous 
		 * resolution later
		 */
		else if (status != 1) {
			save_resolve(curr_peer->addr->address,
				     hmode,
				     curr_peer->peerversion,
				     curr_peer->minpoll,
				     curr_peer->maxpoll, 
				     curr_peer->peerflags, 
				     curr_peer->ttl,
				     curr_peer->peerkey,
				     (u_char *)"*");
		}
		/* Yippie!! Name resolution has succeeded!!!
		 * Now we can proceed to some more sanity checks on
		 * the resolved address before we start to configure
		 * the peer
		 */
		else {
			res_bak = res;
			/* Loop to configure the desired number of associations 
			 */
			for (i = 0; (i < no_needed) && res; res = res->ai_next) {
				++i;
				memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
#ifdef DEBUG
				if (debug > 1)
					printf("configuring host %s with address %s\n",
					       curr_peer->addr->address, stoa(&peeraddr));
#endif
				if (is_sane_resolved_address(peeraddr, curr_peer->host_mode)) {
					if (peer_config(&peeraddr,
							ANY_INTERFACE_CHOOSE(&peeraddr), 
							hmode,
							curr_peer->peerversion, 
							curr_peer->minpoll, 
							curr_peer->maxpoll, 
							curr_peer->peerflags,
							curr_peer->ttl, 
							curr_peer->peerkey, 
							(u_char *)"*") == 0) {
						msyslog(LOG_ERR,
							"configuration of %s failed",
							stoa(&peeraddr));
					}
				}
			}
			freeaddrinfo(res_bak);
		}

		/* Ok, everything done. Free up peer node memory */
		free(curr_peer->addr->address);
		free_node(curr_peer->addr);
		free_node(curr_peer);
	}
}

#ifdef SIM
static void
config_sim(void)
{
	int i;
	server_info *serv_info;
	struct attr_val *init_stmt;
    
	/* Check if a simulate block was found in the configuration code.
	 * If not, return an error and exit
	 */
	if (my_config.sim_details == NULL) {
		fprintf(stderr, "ERROR!! I couldn't find a \"simulate\" block for configuring the simulator.\n");
		fprintf(stderr, "\tCheck your configuration file.\n");
		exit(1);
	}

	/* Process the initialization statements 
	 * -------------------------------------
	 */
	while(!empty(my_config.sim_details->init_opts)) {
		init_stmt = (struct attr_val *) 
		    dequeue(my_config.sim_details->init_opts);
		switch(init_stmt->attr) {
		    case T_Beep_Delay:
			simulation.beep_delay = init_stmt->value.d;
			break;
		    case T_Sim_Duration:
			simulation.end_time = init_stmt->value.d;
			break;
		    default:
			yyerror("Internal Error in parser...\n"
				"Invalid init statement in simulator block");
			break;
		}
		free_node(init_stmt);
	}
	destroy_queue(my_config.sim_details->init_opts);


	/* Process the server list 
	 * -----------------------
	 */
	simulation.num_of_servers = get_no_of_elements(my_config.sim_details->servers);
	simulation.servers = (server_info *) malloc(simulation.num_of_servers *
						    sizeof(server_info));

	for (i = 0;i < simulation.num_of_servers;++i) {
		serv_info = (server_info *) 
		    dequeue(my_config.sim_details->servers);
		if (!serv_info) 
			yyerror("Internal Error in parser...\n"
				"Tried to initialize server list but no server returned\n");
		memcpy(&simulation.servers[i], serv_info, sizeof(server_info));
		free_node(serv_info);
	}
	destroy_queue(my_config.sim_details->servers);
    
	/* Free the sim_node memory and set the sim_details as NULL */
	free_node(my_config.sim_details);
	my_config.sim_details = NULL;
    
	/* Create server associations */
	printf("Creating server associations\n");
	create_server_associations();
	fprintf(stderr,"\tServer associations successfully created!!\n");
}
#endif /* SIM */

/* Define two different config functions. One for the daemon and the other for
 * the simulator. The simulator ignores a lot of the standard ntpd configuration
 * options 
 */

static void
config_ntpd(void)
{
	config_auth();
	config_tos();
	config_monitor();
	config_access();
	config_tinker();
	config_system_opts();
	config_logconfig();
	config_phone();
	config_setvar();
	config_ttl();
	config_trap();
	config_vars();
	config_other_modes();
	config_peers();
	config_fudge();
}

#ifdef SIM
static void
config_ntpdsim(void)
{
	printf("Configuring Simulator...\n");
	printf("Some ntpd-specific commands in the configuration file will be ignored.\n");

	config_tos();
	config_monitor();
	config_tinker();
	config_system_opts();
	config_logconfig();
	config_vars();
	config_sim();
}
#endif /* SIM */

void
config_remotely(void)
{
	input_from_file = 0;
#if 0
	init_syntax_tree();
#endif
	yyparse();
#ifdef DEBUG
	if (debug > 1) 
		printf("Finished Parsing!!\n");
#endif

	config_ntpd();
    
	input_from_file = 1;
}
    

/* ACTUAL getconfig code */

void
getconfig(
	int argc,
	char *argv[]
	)
{
	char line[MAXLINE];

#ifndef SYS_WINNT
	config_file = CONFIG_FILE;
#else
	temp = CONFIG_FILE;
	if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)config_file_storage, (DWORD)sizeof(config_file_storage))) {
		msyslog(LOG_ERR, "ExpandEnvironmentStrings CONFIG_FILE failed: %m\n");
		exit(1);
	}
	config_file = config_file_storage;
    
	temp = ALT_CONFIG_FILE;
	if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)alt_config_file_storage, (DWORD)sizeof(alt_config_file_storage))) {
		msyslog(LOG_ERR, "ExpandEnvironmentStrings ALT_CONFIG_FILE failed: %m\n");
		exit(1);
	}
	alt_config_file = alt_config_file_storage;

#endif /* SYS_WINNT */
	res_fp = NULL;
	ntp_syslogmask = NLOG_SYNCMASK; /* set more via logconfig */

	/*
	 * install a non default variable with this daemon version
	 */
	(void) sprintf(line, "daemon_version=\"%s\"", Version);
	set_sys_var(line, strlen(line)+1, RO);
    
	/*
	 * Say how we're setting the time of day
	 */
	(void) sprintf(line, "settimeofday=\"%s\"", set_tod_using);
	set_sys_var(line, strlen(line)+1, RO);

	/*
	 * Initialize the loop.
	 */
	loop_config(LOOP_DRIFTINIT, 0.);
    
	getCmdOpts(argc, argv);

	curr_include_level = 0;
	if (
		(fp[curr_include_level] = F_OPEN(FindConfig(config_file), "r")) == NULL
#ifdef HAVE_NETINFO
		/* If there is no config_file, try NetInfo. */
		&& check_netinfo && !(config_netinfo = get_netinfo_config())
#endif /* HAVE_NETINFO */
		) {
		fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(config_file));
		msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(config_file));
#ifdef SYS_WINNT
		/* Under WinNT try alternate_config_file name, first NTP.CONF, then NTP.INI */
        
		if ((fp[curr_include_level] = F_OPEN(FindConfig(alt_config_file), "r")) == NULL) {

			/*
			 * Broadcast clients can sometimes run without
			 * a configuration file.
			 */
            
			fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(alt_config_file));
			msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(alt_config_file));
			return;
		}
#else  /* not SYS_WINNT */
		return;
#endif /* not SYS_WINNT */
	}

	/*** BULK OF THE PARSER ***/
	ip_file = fp[curr_include_level];
	key_scanner = create_keyword_scanner(keyword_list);
	init_syntax_tree();
	yyparse();
#ifdef DEBUG
	if (debug > 1) 
		printf("Finished Parsing!!\n");
#endif

	/* The actual configuration done depends on whether we are configuring the
	 * simulator or the daemon. Perform a check and call the appropriate 
	 * function as needed.
	 */

#ifndef SIM
	config_ntpd();
#else
	config_ntpdsim();
#endif

	while (curr_include_level != -1) {
		FCLOSE(fp[curr_include_level--]);
	}
    
    
#ifdef HAVE_NETINFO
	if (config_netinfo)
		free_netinfo_config(config_netinfo);
#endif /* HAVE_NETINFO */
        
	if (res_fp != NULL) {
		if (call_resolver) {
			/*
			 * Need name resolution
			 */
			do_resolve_internal();
		}
	}
}



/* FUNCTIONS COPIED FROM THE OLDER ntp_config.c
 * --------------------------------------------
 */


/*
 * get_pfxmatch - find value for prefixmatch
 * and update char * accordingly
 */
static unsigned long
get_pfxmatch(
	char ** s,
	struct masks *m
	)
{
	while (m->name) {
		if (strncmp(*s, m->name, strlen(m->name)) == 0) {
			*s += strlen(m->name);
			return m->mask;
		} else {
			m++;
		}
	}
	return 0;
}

/*
 * get_match - find logmask value
 */
static unsigned long
get_match(
	char *s,
	struct masks *m
	)
{
	while (m->name) {
		if (strcmp(s, m->name) == 0) {
			return m->mask;
		} else {
			m++;
		}
	}
	return 0;
}

/*
 * get_logmask - build bitmask for ntp_syslogmask
 */
static unsigned long
get_logmask(
	char *s
	)
{
	char *t;
	unsigned long offset;
	unsigned long mask;

	t = s;
	offset = get_pfxmatch(&t, logcfg_class);
	mask   = get_match(t, logcfg_item);

	if (mask)
		return mask << offset;
	else
		msyslog(LOG_ERR, "logconfig: illegal argument %s - ignored", s);

	return 0;
}


#ifdef HAVE_NETINFO

/* 
 * get_netinfo_config - find the nearest NetInfo domain with an ntp
 * configuration and initialize the configuration state.
 */
static struct netinfo_config_state *
get_netinfo_config(void)
{
	ni_status status;
	void *domain;
	ni_id config_dir;
       	struct netinfo_config_state *config;

	if (ni_open(NULL, ".", &domain) != NI_OK) return NULL;

	while ((status = ni_pathsearch(domain, &config_dir, NETINFO_CONFIG_DIR)) == NI_NODIR) {
		void *next_domain;
		if (ni_open(domain, "..", &next_domain) != NI_OK) {
			ni_free(next_domain);
			break;
		}
		ni_free(domain);
		domain = next_domain;
	}
	if (status != NI_OK) {
		ni_free(domain);
		return NULL;
	}

       	config = (struct netinfo_config_state *)malloc(sizeof(struct netinfo_config_state));
       	config->domain = domain;
       	config->config_dir = config_dir;
       	config->prop_index = 0;
       	config->val_index = 0;
       	config->val_list = NULL;

	return config;
}



/*
 * free_netinfo_config - release NetInfo configuration state
 */
static void
free_netinfo_config(
	struct netinfo_config_state *config
	)
{
	ni_free(config->domain);
	free(config);
}



/*
 * gettokens_netinfo - return tokens from NetInfo
 */
static int
gettokens_netinfo (
	struct netinfo_config_state *config,
	char **tokenlist,
	int *ntokens
	)
{
	int prop_index = config->prop_index;
	int val_index = config->val_index;
	char **val_list = config->val_list;

	/*
	 * Iterate through each keyword and look for a property that matches it.
	 */
  again:
	if (!val_list) {
	       	for (; prop_index < (sizeof(keywords)/sizeof(keywords[0])); prop_index++)
	       	{
		       	ni_namelist namelist;
			struct keyword current_prop = keywords[prop_index];

			/*
			 * For each value associated in the property, we're going to return
			 * a separate line. We squirrel away the values in the config state
			 * so the next time through, we don't need to do this lookup.
			 */
		       	NI_INIT(&namelist);
	       		if (ni_lookupprop(config->domain, &config->config_dir, current_prop.text, &namelist) == NI_OK) {
				ni_index index;

				/* Found the property, but it has no values */
				if (namelist.ni_namelist_len == 0) continue;

				if (! (val_list = config->val_list = (char**)malloc(sizeof(char*) * (namelist.ni_namelist_len + 1))))
				{ msyslog(LOG_ERR, "out of memory while configuring"); break; }

				for (index = 0; index < namelist.ni_namelist_len; index++) {
					char *value = namelist.ni_namelist_val[index];

					if (! (val_list[index] = (char*)malloc(strlen(value)+1)))
					{ msyslog(LOG_ERR, "out of memory while configuring"); break; }

					strcpy(val_list[index], value);
				}
				val_list[index] = NULL;

				break;
			}
			ni_namelist_free(&namelist);
		}
		config->prop_index = prop_index;
	}

	/* No list; we're done here. */
       	if (!val_list) return CONFIG_UNKNOWN;

	/*
	 * We have a list of values for the current property.
	 * Iterate through them and return each in order.
	 */
	if (val_list[val_index])
	{
		int ntok = 1;
		int quoted = 0;
		char *tokens = val_list[val_index];

		msyslog(LOG_INFO, "%s %s", keywords[prop_index].text, val_list[val_index]);

		(const char*)tokenlist[0] = keywords[prop_index].text;
		for (ntok = 1; ntok < MAXTOKENS; ntok++) {
			tokenlist[ntok] = tokens;
			while (!ISEOL(*tokens) && (!ISSPACE(*tokens) || quoted))
				quoted ^= (*tokens++ == '"');

			if (ISEOL(*tokens)) {
				*tokens = '\0';
				break;
			} else {		/* must be space */
				*tokens++ = '\0';
				while (ISSPACE(*tokens)) tokens++;
				if (ISEOL(*tokens)) break;
			}
		}

		if (ntok == MAXTOKENS) {
			/* HMS: chomp it to lose the EOL? */
			msyslog(LOG_ERR,
				"gettokens_netinfo: too many tokens.  Ignoring: %s",
				tokens);
		} else {
			*ntokens = ntok + 1;
		}

		config->val_index++;	/* HMS: Should this be in the 'else'? */

		return keywords[prop_index].keytype;
	}

	/* We're done with the current property. */
	prop_index = ++config->prop_index;

	/* Free val_list and reset counters. */
	for (val_index = 0; val_list[val_index]; val_index++)
		free(val_list[val_index]);
       	free(val_list);	val_list = config->val_list = NULL; val_index = config->val_index = 0;

	goto again;
}

#endif /* HAVE_NETINFO */

/*
 * getnetnum - return a net number (this is crude, but careful)
 */

static int
getnetnum(
	const char *num,
	struct sockaddr_storage *addr,
	int complain,
	enum gnn_type a_type
	)
{
	int retval;
	struct addrinfo *res;

	/* Get all the addresses that resolve to this name */
	retval = get_multiple_netnums(num, addr, &res, complain, a_type);

	if (retval != 1) {
		/* Name resolution failed */
		return retval;
	}

	memcpy(addr, res->ai_addr, res->ai_addrlen);
#ifdef DEBUG
	if (debug > 1)
		printf("getnetnum given %s, got %s \n",
		       num, stoa(addr));
#endif
	freeaddrinfo(res);
	return 1;
}

static int
get_multiple_netnums(
	const char *num,
	struct sockaddr_storage *addr,
	struct addrinfo **res,
	int complain,
	enum gnn_type a_type
	)
{
	struct addrinfo hints;
	struct addrinfo *ptr;

	int retval;

	/* Get host address. Looking for UDP datagram connection */
	memset(&hints, 0, sizeof (hints));
	if (addr->ss_family == AF_INET || addr->ss_family == AF_INET6)
		hints.ai_family = addr->ss_family;
	else
		hints.ai_family = AF_UNSPEC;
	/*
	 * If we don't have an IPv6 stack, just look up IPv4 addresses
	 */
	if (isc_net_probeipv6() != ISC_R_SUCCESS)
		hints.ai_family = AF_INET;

	hints.ai_socktype = SOCK_DGRAM;
#ifdef DEBUG
	if (debug > 3)
		printf("getaddrinfo %s\n", num);
#endif
	retval = getaddrinfo(num, "ntp", &hints, &ptr);
	if (retval != 0 ||
	    (ptr->ai_family == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS)) {
		if (complain)
			msyslog(LOG_ERR,
				"getaddrinfo: \"%s\" invalid host address, ignored",
				num);
#ifdef DEBUG
		if (debug > 0)
			printf(
				"getaddrinfo: \"%s\" invalid host address%s.\n",
				num, (complain)
				? ", ignored"
				: "");
#endif
		if (retval == 0 && 
		    ptr->ai_family == AF_INET6 && 
		    isc_net_probeipv6() != ISC_R_SUCCESS) 
		{
			return -1;
		}
		else {
			return 0;
		}
	}
	*res = ptr;

	return 1;
}



#if !defined(VMS) && !defined(SYS_WINNT)
/*
 * catchchild - receive the resolver's exit status
 */
static RETSIGTYPE
catchchild(
	int sig
	)
{
	/*
	 * We only start up one child, and if we're here
	 * it should have already exited.  Hence the following
	 * shouldn't hang.  If it does, please tell me.
	 */
#if !defined (SYS_WINNT) && !defined(SYS_VXWORKS)
	(void) wait(0);
#endif /* SYS_WINNT  && VXWORKS*/
}
#endif /* VMS */


/*
 * save_resolve - save configuration info into a file for later name resolution
 */
static void
save_resolve(
	char *name,
	int mode,
	int version,
	int minpoll,
	int maxpoll,
	u_int flags,
	int ttl,
	keyid_t keyid,
	u_char *keystr
	)
{
#ifndef SYS_VXWORKS
	if (res_fp == NULL) {
#ifndef SYS_WINNT
		(void) strcpy(res_file, RES_TEMPFILE);
#else
		/* no /tmp directory under NT */
		{
			if(!(GetTempPath((DWORD)MAX_PATH, (LPTSTR)res_file))) {
				msyslog(LOG_ERR, "cannot get pathname for temporary directory: %m");
				return;
			}
			(void) strcat(res_file, "ntpdXXXXXX");
		}
#endif /* SYS_WINNT */
#ifdef HAVE_MKSTEMP
		{
			int fd;

			res_fp = NULL;
			if ((fd = mkstemp(res_file)) != -1)
				res_fp = fdopen(fd, "r+");
		}
#else
		(void) mktemp(res_file);
		res_fp = fopen(res_file, "w");
#endif
		if (res_fp == NULL) {
			msyslog(LOG_ERR, "open failed for %s: %m", res_file);
			return;
		}
	}
#ifdef DEBUG
	if (debug) {
		printf("resolving %s\n", name);
	}
#endif

	(void)fprintf(res_fp, "%s %d %d %d %d %d %d %u %s\n", name,
		      mode, version, minpoll, maxpoll, flags, ttl, keyid, keystr);
#ifdef DEBUG
	if (debug > 1)
		printf("config: %s %d %d %d %d %x %d %u %s\n", name, mode,
		       version, minpoll, maxpoll, flags, ttl, keyid, keystr);
#endif

#else  /* SYS_VXWORKS */
	/* save resolve info to a struct */
#endif /* SYS_VXWORKS */
}


/*
 * abort_resolve - terminate the resolver stuff and delete the file
 */
static void
abort_resolve(void)
{
	/*
	 * In an ideal world we would might reread the file and
	 * log the hosts which aren't getting configured.  Since
	 * this is too much work, however, just close and delete
	 * the temp file.
	 */
	if (res_fp != NULL)
		(void) fclose(res_fp);
	res_fp = NULL;

#ifndef SYS_VXWORKS		/* we don't open the file to begin with */
#if !defined(VMS)
	(void) unlink(res_file);
#else
	(void) delete(res_file);
#endif /* VMS */
#endif /* SYS_VXWORKS */
}


/*
 * do_resolve_internal - start up the resolver function (not program)
 */
/*
 * On VMS, this routine will simply refuse to resolve anything.
 *
 * Possible implementation: keep `res_file' in memory, do async
 * name resolution via QIO, update from within completion AST.
 * I'm unlikely to find the time for doing this, though. -wjm
 */
static void
do_resolve_internal(void)
{
	int i;

	if (res_fp == NULL) {
		/* belch */
		msyslog(LOG_ERR,
			"do_resolve_internal: Fatal: res_fp == NULL");
		exit(1);
	}

	/* we are done with this now */
	(void) fclose(res_fp);
	res_fp = NULL;

#if !defined(VMS) && !defined (SYS_VXWORKS)
	req_file = res_file;	/* set up pointer to res file */
#ifndef SYS_WINNT
	(void) signal_no_reset(SIGCHLD, catchchild);

#ifndef SYS_VXWORKS
	i = fork();
	if (i == 0) {
		/*
		 * this used to close everything
		 * I don't think this is necessary
		 */
		/*
		 * To the unknown commenter above:
		 * Well, I think it's better to clean up
		 * after oneself. I have had problems with
		 * refclock-io when intres was running - things
		 * where fine again when ntpintres was gone.
		 * So some systems react erratic at least.
		 *
		 *			Frank Kardel
		 *
		 * 94-11-16:
		 * Further debugging has proven that the above is
		 * absolutely harmful. The internal resolver
		 * is still in the SIGIO process group and the lingering
		 * async io information causes it to process requests from
		 * all file decriptor causing a race between the NTP daemon
		 * and the resolver. which then eats data when it wins 8-(.
		 * It is absolutly necessary to kill any IO associations
		 * shared with the NTP daemon.
		 *
		 * We also block SIGIO (currently no ports means to
		 * disable the signal handle for IO).
		 *
		 * Thanks to wgstuken@informatik.uni-erlangen.de to notice
		 * that it is the ntp-resolver child running into trouble.
		 *
		 * THUS:
		 */

		closelog();
		kill_asyncio(0);

		(void) signal_no_reset(SIGCHLD, SIG_DFL);

#ifdef DEBUG
		if (0)
			debug = 2;
#endif

# ifndef LOG_DAEMON
		openlog("ntpd_initres", LOG_PID);
# else /* LOG_DAEMON */

#  ifndef LOG_NTP
#   define	LOG_NTP LOG_DAEMON
#  endif
		openlog("ntpd_initres", LOG_PID | LOG_NDELAY, LOG_NTP);
#ifndef SYS_CYGWIN32
#  ifdef DEBUG
		if (debug)
			setlogmask(LOG_UPTO(LOG_DEBUG));
		else
#  endif /* DEBUG */
			setlogmask(LOG_UPTO(LOG_DEBUG)); /* @@@ was INFO */
# endif /* LOG_DAEMON */
#endif

		ntp_intres();

		/*
		 * If we got here, the intres code screwed up.
		 * Print something so we don't die without complaint
		 */
		msyslog(LOG_ERR, "call to ntp_intres lost");
		abort_resolve();
		exit(1);
	}
#else
	/* vxWorks spawns a thread... -casey */
	i = sp (ntp_intres);
	/*i = taskSpawn("ntp_intres",100,VX_FP_TASK,20000,ntp_intres);*/
#endif
	if (i == -1) {
		msyslog(LOG_ERR, "fork() failed, can't start ntp_intres: %m");
		(void) signal_no_reset(SIGCHLD, SIG_DFL);
		abort_resolve();
	}
#else /* SYS_WINNT */
	{
		/* NT's equivalent of fork() is _spawn(), but the start point
		 * of the new process is an executable filename rather than
		 * a function name as desired here.
		 */
		DWORD dwThreadId;
		fflush(stdout);
		ResolverThreadHandle = CreateThread(
			NULL,				 /* no security attributes	*/
			0,				 /* use default stack size	*/
			(LPTHREAD_START_ROUTINE) ntp_intres, /* thread function		*/
			NULL,				 /* argument to thread function   */
			0,				 /* use default creation flags	  */
			&dwThreadId);			 /* returns the thread identifier */
		if (ResolverThreadHandle == NULL) {
			msyslog(LOG_ERR, "CreateThread() failed, can't start ntp_intres");
			abort_resolve();
		}
	}
#endif /* SYS_WINNT */
#else /* VMS  VX_WORKS */
	msyslog(LOG_ERR,
		"Name resolution not implemented for VMS - use numeric addresses");
	abort_resolve();
#endif /* VMS VX_WORKS */
}


syntax highlighted by Code2HTML, v. 0.9.1