ntp_parser.y   [plain text]


/* ntp_parser.y
 *
 * The parser for the NTP configuration file.
 *
 * Written By:	Sachin Kamboj
 *		University of Delaware
 *		Newark, DE 19711
 * Copyright (c) 2006
 */

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

  #include "ntpd.h"
  #include "ntp_machine.h"
  #include "ntp.h"
  #include "ntp_stdlib.h"
  #include "ntp_filegen.h"
  #include "ntp_data_structures.h"
  #include "ntp_scanner.h"
  #include "ntp_config.h"
  #include "ntp_crypto.h"

  #include "ntpsim.h"		/* HMS: Do we really want this all the time? */
				/* SK: It might be a good idea to always
				   include the simulator code. That way
				   someone can use the same configuration file
				   for both the simulator and the daemon
				*/


  struct FILE_INFO *ip_file;   /* Pointer to the configuration file stream */

  #define YYMALLOC	emalloc
  #define YYFREE	free
  #define YYERROR_VERBOSE
  #define YYMAXDEPTH	1000   /* stop the madness sooner */
  void yyerror (char *msg);
  extern int input_from_file;  /* 0=input from ntpq :config */
%}

/* 
 * Enable generation of token names array even without YYDEBUG.
 * We access via token_name() defined below.
 */
%token-table

%union {
    char   *String;
    double  Double;
    int     Integer;
    void   *VoidPtr;
    queue  *Queue;
    struct attr_val *Attr_val;
    struct address_node *Address_node;
    struct setvar_node *Set_var;

    /* Simulation types */
    server_info *Sim_server;
    script_info *Sim_script;
}

/* TERMINALS (do not appear left of colon) */
%token	<Integer>	T_Age
%token	<Integer>	T_All
%token	<Integer>	T_Allan
%token	<Integer>	T_Auth
%token	<Integer>	T_Autokey
%token	<Integer>	T_Automax
%token	<Integer>	T_Average
%token	<Integer>	T_Bclient
%token	<Integer>	T_Beacon
%token	<Integer>	T_Bias
%token	<Integer>	T_Broadcast
%token	<Integer>	T_Broadcastclient
%token	<Integer>	T_Broadcastdelay
%token	<Integer>	T_Burst
%token	<Integer>	T_Calibrate
%token	<Integer>	T_Calldelay
%token	<Integer>	T_Ceiling
%token	<Integer>	T_Clockstats
%token	<Integer>	T_Cohort
%token	<Integer>	T_ControlKey
%token	<Integer>	T_Crypto
%token	<Integer>	T_Cryptostats
%token	<Integer>	T_Day
%token	<Integer>	T_Default
%token	<Integer>	T_Digest
%token	<Integer>	T_Disable
%token	<Integer>	T_Discard
%token	<Integer>	T_Dispersion
%token	<Double>	T_Double
%token	<Integer>	T_Driftfile
%token	<Integer>	T_Drop
%token	<Integer>	T_Enable
%token	<Integer>	T_End
%token	<Integer>	T_False
%token	<Integer>	T_File
%token	<Integer>	T_Filegen
%token	<Integer>	T_Flag1
%token	<Integer>	T_Flag2
%token	<Integer>	T_Flag3
%token	<Integer>	T_Flag4
%token	<Integer>	T_Flake
%token	<Integer>	T_Floor
%token	<Integer>	T_Freq
%token	<Integer>	T_Fudge
%token	<Integer>	T_Host
%token	<Integer>	T_Huffpuff
%token	<Integer>	T_Iburst
%token	<Integer>	T_Ident
%token	<Integer>	T_Ignore
%token	<Integer>	T_Includefile
%token	<Integer>	T_Integer
%token	<Integer>	T_Interface
%token	<Integer>	T_Ipv4
%token	<Integer>	T_Ipv4_flag
%token	<Integer>	T_Ipv6
%token	<Integer>	T_Ipv6_flag
%token	<Integer>	T_Kernel
%token	<Integer>	T_Key
%token	<Integer>	T_Keys
%token	<Integer>	T_Keysdir
%token	<Integer>	T_Kod
%token	<Integer>	T_Mssntp
%token	<Integer>	T_Leapfile
%token	<Integer>	T_Limited
%token	<Integer>	T_Link
%token	<Integer>	T_Listen
%token	<Integer>	T_Logconfig
%token	<Integer>	T_Logfile
%token	<Integer>	T_Loopstats
%token	<Integer>	T_Lowpriotrap
%token	<Integer>	T_Manycastclient
%token	<Integer>	T_Manycastserver
%token	<Integer>	T_Mask
%token	<Integer>	T_Maxclock
%token	<Integer>	T_Maxdist
%token	<Integer>	T_Maxpoll
%token	<Integer>	T_Minclock
%token	<Integer>	T_Mindist
%token	<Integer>	T_Minimum
%token	<Integer>	T_Minpoll
%token	<Integer>	T_Minsane
%token	<Integer>	T_Mode
%token	<Integer>	T_Monitor
%token	<Integer>	T_Month
%token	<Integer>	T_Multicastclient
%token	<Integer>	T_Nic
%token	<Integer>	T_Nolink
%token	<Integer>	T_Nomodify
%token	<Integer>	T_None
%token	<Integer>	T_Nopeer
%token	<Integer>	T_Noquery
%token	<Integer>	T_Noselect
%token	<Integer>	T_Noserve
%token	<Integer>	T_Notrap
%token	<Integer>	T_Notrust
%token	<Integer>	T_Ntp
%token	<Integer>	T_Ntpport
%token	<Integer>	T_NtpSignDsocket
%token	<Integer>	T_Orphan
%token	<Integer>	T_Panic
%token	<Integer>	T_Peer
%token	<Integer>	T_Peerstats
%token	<Integer>	T_Phone
%token	<Integer>	T_Pid
%token	<Integer>	T_Pidfile
%token	<Integer>	T_Pool
%token	<Integer>	T_Port
%token	<Integer>	T_Preempt
%token	<Integer>	T_Prefer
%token	<Integer>	T_Protostats
%token	<Integer>	T_Pw
%token	<Integer>	T_Qos
%token	<Integer>	T_Randfile
%token	<Integer>	T_Rawstats
%token	<Integer>	T_Refid
%token	<Integer>	T_Requestkey
%token	<Integer>	T_Restrict
%token	<Integer>	T_Revoke
%token	<Integer>	T_Saveconfigdir
%token	<Integer>	T_Server
%token	<Integer>	T_Setvar
%token	<Integer>	T_Sign
%token	<Integer>	T_Statistics
%token	<Integer>	T_Stats
%token	<Integer>	T_Statsdir
%token	<Integer>	T_Step
%token	<Integer>	T_Stepout
%token	<Integer>	T_Stratum
%token	<String>	T_String
%token	<Integer>	T_Sysstats
%token	<Integer>	T_Tick
%token	<Integer>	T_Time1
%token	<Integer>	T_Time2
%token	<Integer>	T_Timingstats
%token	<Integer>	T_Tinker
%token	<Integer>	T_Tos
%token	<Integer>	T_Trap
%token	<Integer>	T_True
%token	<Integer>	T_Trustedkey
%token	<Integer>	T_Ttl
%token	<Integer>	T_Type
%token	<Integer>	T_Unconfig
%token	<Integer>	T_Unpeer
%token	<Integer>	T_Version
%token	<Integer>	T_WanderThreshold	/* Not a token */
%token	<Integer>	T_Week
%token	<Integer>	T_Wildcard
%token	<Integer>	T_Xleave
%token	<Integer>	T_Year
%token	<Integer>	T_Flag		/* Not an actual token */
%token	<Integer>	T_Void		/* Not an actual token */
%token	<Integer>	T_EOC


/* NTP Simulator Tokens */
%token	<Integer>	T_Simulate
%token	<Integer>	T_Beep_Delay
%token	<Integer>	T_Sim_Duration
%token	<Integer>	T_Server_Offset
%token	<Integer>	T_Duration
%token	<Integer>	T_Freq_Offset
%token	<Integer>	T_Wander
%token	<Integer>	T_Jitter
%token	<Integer>	T_Prop_Delay
%token	<Integer>	T_Proc_Delay



/*** NON-TERMINALS ***/
%type	<Integer>	access_control_flag
%type	<Queue>		ac_flag_list
%type	<Address_node>	address
%type	<Queue>		address_list
%type	<Integer>	boolean
%type	<Integer>	client_type
%type	<Attr_val>	crypto_command
%type	<Queue>		crypto_command_line
%type	<Queue>		crypto_command_list
%type	<Attr_val>	discard_option
%type	<Queue>		discard_option_list
%type	<Attr_val>	filegen_option
%type	<Queue>		filegen_option_list
%type	<Integer>	filegen_type
%type	<Attr_val>	fudge_factor
%type	<Queue>		fudge_factor_list
%type	<Queue>		integer_list
%type	<Integer>	nic_rule_action
%type	<Queue>		interface_command
%type	<Integer>	interface_nic
%type	<Address_node>	ip_address
%type	<Attr_val>	log_config_command
%type	<Queue>		log_config_list
%type	<Integer>	nic_rule_class
%type	<Double>	number
%type	<Attr_val>	option
%type	<Queue>		option_list
%type	<Integer>	stat
%type	<Queue>		stats_list
%type	<Queue>		string_list
%type	<Attr_val>	system_option
%type	<Queue>		system_option_list
%type	<Attr_val>	tinker_option
%type	<Queue>		tinker_option_list
%type	<Attr_val>	tos_option
%type	<Queue>		tos_option_list
%type	<Attr_val>	trap_option
%type	<Queue>		trap_option_list
%type	<Integer>	unpeer_keyword
%type	<Set_var>	variable_assign

/* NTP Simulator non-terminals */
%type	<Queue>		sim_init_statement_list
%type	<Attr_val>	sim_init_statement
%type	<Queue>		sim_server_list
%type	<Sim_server>	sim_server
%type	<Double>	sim_server_offset
%type	<Address_node>	sim_server_name
%type	<Queue>		sim_act_list
%type	<Sim_script>	sim_act
%type	<Queue>		sim_act_stmt_list
%type	<Attr_val>	sim_act_stmt

%%

/* ntp.conf
 * Configuration File Grammar
 * --------------------------
 */

configuration
	:	command_list
	;

command_list
	:	command_list command T_EOC
	|	command T_EOC
	|	error T_EOC
		{
			/* I will need to incorporate much more fine grained
			 * error messages. The following should suffice for
			 * the time being.
			 */
			msyslog(LOG_ERR, 
				"syntax error in %s line %d, column %d",
				ip_file->fname,
				ip_file->err_line_no,
				ip_file->err_col_no);
		}
	;

command :	/* NULL STATEMENT */
	|	server_command
	|	unpeer_command
	|	other_mode_command
	|	authentication_command
	|	monitoring_command
	|	access_control_command
	|	orphan_mode_command
	|	fudge_command
	|	system_option_command
	|	tinker_command
	|	miscellaneous_command
	|	simulate_command
	;

/* Server Commands
 * ---------------
 */

server_command
	:	client_type address option_list
		{
			struct peer_node *my_node =  create_peer_node($1, $2, $3);
			if (my_node)
				enqueue(cfgt.peers, my_node);
		}
	|	client_type address
		{
			struct peer_node *my_node = create_peer_node($1, $2, NULL);
			if (my_node)
				enqueue(cfgt.peers, my_node);
		}
	;

client_type
	:	T_Server
	|	T_Pool
	|	T_Peer
	|	T_Broadcast
	|	T_Manycastclient
	;

address
	:	ip_address
	|	T_Ipv4_flag T_String	{ $$ = create_address_node($2, AF_INET); }
	|	T_Ipv6_flag T_String	{ $$ = create_address_node($2, AF_INET6); }
	;

ip_address
	:	T_String { $$ = create_address_node($1, 0); }
	;

option_list
	:	option_list option { $$ = enqueue($1, $2); }
	|	option { $$ = enqueue_in_new_queue($1); }
	;

option
	:	T_Autokey		{ $$ = create_attr_ival(T_Flag, $1); }
	|	T_Bias number		{ $$ = create_attr_dval($1, $2); }
	|	T_Burst			{ $$ = create_attr_ival(T_Flag, $1); }
	|	T_Iburst		{ $$ = create_attr_ival(T_Flag, $1); }
	|	T_Key T_Integer		{ $$ = create_attr_ival($1, $2); }
	|	T_Minpoll T_Integer	{ $$ = create_attr_ival($1, $2); }
	|	T_Maxpoll T_Integer	{ $$ = create_attr_ival($1, $2); }
	|	T_Noselect		{ $$ = create_attr_ival(T_Flag, $1); }
	|	T_Preempt		{ $$ = create_attr_ival(T_Flag, $1); }
	|	T_Prefer		{ $$ = create_attr_ival(T_Flag, $1); }
	|	T_True			{ $$ = create_attr_ival(T_Flag, $1); }
	|	T_Xleave		{ $$ = create_attr_ival(T_Flag, $1); }
	|	T_Ttl T_Integer		{ $$ = create_attr_ival($1, $2); }
	|	T_Mode T_Integer	{ $$ = create_attr_ival($1, $2); }
	|	T_Version T_Integer	{ $$ = create_attr_ival($1, $2); }
	;


/* unpeer commands
 * ---------------
 */

unpeer_command
	:	unpeer_keyword address
		{
			struct unpeer_node *my_node = create_unpeer_node($2);
			if (my_node)
				enqueue(cfgt.unpeers, my_node);
		}
	;	
unpeer_keyword	
	:	T_Unconfig
	|	T_Unpeer
	;
	
	
/* Other Modes
 * (broadcastclient manycastserver multicastclient)
 * ------------------------------------------------
 */

other_mode_command
	:	T_Broadcastclient
			{ cfgt.broadcastclient = 1; }
	|	T_Manycastserver address_list
			{ append_queue(cfgt.manycastserver, $2); }
	|	T_Multicastclient address_list
			{ append_queue(cfgt.multicastclient, $2); }
	;



/* Authentication Commands
 * -----------------------
 */

authentication_command
	:	T_Automax T_Integer
			{ enqueue(cfgt.vars, create_attr_ival($1, $2)); }
	|	T_ControlKey T_Integer
			{ cfgt.auth.control_key = $2; }
	|	T_Crypto crypto_command_line
		{ 
			cfgt.auth.cryptosw++;
			append_queue(cfgt.auth.crypto_cmd_list, $2);
		}
	|	T_Keys T_String
			{ cfgt.auth.keys = $2; }
	|	T_Keysdir T_String
			{ cfgt.auth.keysdir = $2; }
	|	T_Requestkey T_Integer
			{ cfgt.auth.request_key = $2; }
	|	T_Revoke T_Integer
			{ cfgt.auth.revoke = $2; }
	|	T_Trustedkey integer_list
			{ cfgt.auth.trusted_key_list = $2; }
	|	T_NtpSignDsocket T_String
			{ cfgt.auth.ntp_signd_socket = $2; }
	;

crypto_command_line
	:	crypto_command_list
	|	/* Null list */
			{ $$ = create_queue(); }
	;

crypto_command_list
	:	crypto_command_list crypto_command
		{ 
			if ($2 != NULL)
				$$ = enqueue($1, $2);
			else
				$$ = $1;
		}
	|	crypto_command
		{
			if ($1 != NULL)
				$$ = enqueue_in_new_queue($1);
			else
				$$ = create_queue();
		}
	;

crypto_command
	:	T_Host	T_String
			{ $$ = create_attr_sval($1, $2); }
	|	T_Ident	T_String
			{ $$ = create_attr_sval($1, $2); }
	|	T_Pw T_String
			{ $$ = create_attr_sval($1, $2); }
	|	T_Randfile T_String
			{ $$ = create_attr_sval($1, $2); }
	|	T_Sign	T_String
			{ $$ = create_attr_sval($1, $2); }
	|	T_Digest T_String
			{ $$ = create_attr_sval($1, $2); }
	|	T_Revoke T_Integer
		{
			$$ = NULL;
			cfgt.auth.revoke = $2;
			msyslog(LOG_WARNING,
				"'crypto revoke %d' is deprecated, "
				"please use 'revoke %d' instead.",
				cfgt.auth.revoke, cfgt.auth.revoke);
		}
	;


/* Orphan Mode Commands
 * --------------------
 */

orphan_mode_command
	:	T_Tos tos_option_list
			{ append_queue(cfgt.orphan_cmds,$2); }
	;

tos_option_list
	:	tos_option_list tos_option { $$ = enqueue($1, $2); }
	|	tos_option { $$ = enqueue_in_new_queue($1); }
	;

tos_option
	:	T_Ceiling T_Integer
			{ $$ = create_attr_dval($1, (double)$2); }
	|	T_Floor T_Integer
			{ $$ = create_attr_dval($1, (double)$2); }
	|	T_Cohort boolean
			{ $$ = create_attr_dval($1, (double)$2); }
	|	T_Orphan T_Integer
			{ $$ = create_attr_dval($1, (double)$2); }
	|	T_Mindist number
			{ $$ = create_attr_dval($1, $2); }
	|	T_Maxdist number
			{ $$ = create_attr_dval($1, $2); }
	|	T_Minclock number
			{ $$ = create_attr_dval($1, $2); }
	|	T_Maxclock number
			{ $$ = create_attr_dval($1, $2); }
	|	T_Minsane T_Integer
			{ $$ = create_attr_dval($1, (double)$2); }
	|	T_Beacon T_Integer
			{ $$ = create_attr_dval($1, (double)$2); }
	;


/* Monitoring Commands
 * -------------------
 */

monitoring_command
	:	T_Statistics stats_list
			{ append_queue(cfgt.stats_list, $2); }
	|	T_Statsdir T_String
		{
			if (input_from_file)
				cfgt.stats_dir = $2;
			else {
				free($2);
				yyerror("statsdir remote configuration ignored");
			}
		}
	|	T_Filegen stat filegen_option_list
		{
			enqueue(cfgt.filegen_opts,
				create_filegen_node($2, $3));
		}
	;

stats_list
	:	stats_list stat { $$ = enqueue($1, create_ival($2)); }
	|	stat { $$ = enqueue_in_new_queue(create_ival($1)); }
	;

stat
	:	T_Clockstats
	|	T_Cryptostats
	|	T_Loopstats
	|	T_Peerstats
	|	T_Rawstats
	|	T_Sysstats
	|	T_Timingstats
	|	T_Protostats
	;

filegen_option_list
	:	filegen_option_list filegen_option
		{
			if ($2 != NULL)
				$$ = enqueue($1, $2);
			else
				$$ = $1;
		}
	|	filegen_option
		{
			if ($1 != NULL)
				$$ = enqueue_in_new_queue($1);
			else
				$$ = create_queue();
		}
	;

filegen_option
	:	T_File T_String
		{
			if (input_from_file)
				$$ = create_attr_sval($1, $2);
			else {
				$$ = NULL;
				free($2);
				yyerror("filegen file remote configuration ignored");
			}
		}
	|	T_Type filegen_type
		{
			if (input_from_file)
				$$ = create_attr_ival($1, $2);
			else {
				$$ = NULL;
				yyerror("filegen type remote configuration ignored");
			}
		}
	|	T_Link
		{
			if (input_from_file)
				$$ = create_attr_ival(T_Flag, $1);
			else {
				$$ = NULL;
				yyerror("filegen link remote configuration ignored");
			}
		}
	|	T_Nolink
		{
			if (input_from_file)
				$$ = create_attr_ival(T_Flag, $1);
			else {
				$$ = NULL;
				yyerror("filegen nolink remote configuration ignored");
			}
		}
	|	T_Enable	{ $$ = create_attr_ival(T_Flag, $1); }
	|	T_Disable	{ $$ = create_attr_ival(T_Flag, $1); }
	;

filegen_type
	:	T_None
	|	T_Pid
	|	T_Day
	|	T_Week
	|	T_Month
	|	T_Year
	|	T_Age
	;


/* Access Control Commands
 * -----------------------
 */

access_control_command
	:	T_Discard discard_option_list
		{
			append_queue(cfgt.discard_opts, $2);
		}
	|	T_Restrict address ac_flag_list
		{
			enqueue(cfgt.restrict_opts,
				create_restrict_node($2, NULL, $3, ip_file->line_no));
		}
	|	T_Restrict T_Default ac_flag_list
		{
			enqueue(cfgt.restrict_opts,
				create_restrict_node(NULL, NULL, $3, ip_file->line_no));
		}
	|	T_Restrict T_Ipv4_flag T_Default ac_flag_list
		{
			enqueue(cfgt.restrict_opts,
				create_restrict_node(
					create_address_node(
						estrdup("0.0.0.0"), 
						AF_INET),
					create_address_node(
						estrdup("255.255.255.255"), 
						AF_INET),
					$4, 
					ip_file->line_no));
		}
	|	T_Restrict T_Ipv6_flag T_Default ac_flag_list
		{
			enqueue(cfgt.restrict_opts,
				create_restrict_node(
					create_address_node(
						estrdup("::"), 
						AF_INET6),
					create_address_node(
						estrdup("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"),
						AF_INET6),
					$4, 
					ip_file->line_no));
		}
	|	T_Restrict ip_address T_Mask ip_address ac_flag_list
		{
			enqueue(cfgt.restrict_opts,
				create_restrict_node($2, $4, $5, ip_file->line_no));
		}
	;

ac_flag_list
	:	/* Null statement */
			{ $$ = create_queue(); }
	|	ac_flag_list access_control_flag
			{ $$ = enqueue($1, create_ival($2)); }
	;

access_control_flag
	:	T_Flake
	|	T_Ignore
	|	T_Kod
	|	T_Mssntp
	|	T_Limited
	|	T_Lowpriotrap
	|	T_Nomodify
	|	T_Nopeer
	|	T_Noquery
	|	T_Noserve
	|	T_Notrap
	|	T_Notrust
	|	T_Ntpport
	|	T_Version
	;

discard_option_list
	:	discard_option_list discard_option
			{ $$ = enqueue($1, $2); }
	|	discard_option 
			{ $$ = enqueue_in_new_queue($1); }
	;

discard_option
	:	T_Average T_Integer { $$ = create_attr_ival($1, $2); }
	|	T_Minimum T_Integer { $$ = create_attr_ival($1, $2); }
	|	T_Monitor T_Integer { $$ = create_attr_ival($1, $2); }
	;

/* Fudge Commands
 * --------------
 */

fudge_command
	:	T_Fudge address fudge_factor_list
			{ enqueue(cfgt.fudge, create_addr_opts_node($2, $3)); }
	;

fudge_factor_list
	:	fudge_factor_list fudge_factor
			{ enqueue($1, $2); }
	|	fudge_factor
			{ $$ = enqueue_in_new_queue($1); }
	;
	
fudge_factor
	:	T_Time1 number		{ $$ = create_attr_dval($1, $2); }
	|	T_Time2 number		{ $$ = create_attr_dval($1, $2); }
	|	T_Stratum T_Integer	{ $$ = create_attr_ival($1, $2); }
	|	T_Refid T_String	{ $$ = create_attr_sval($1, $2); }
	|	T_Flag1 boolean		{ $$ = create_attr_ival($1, $2); }
	|	T_Flag2	boolean		{ $$ = create_attr_ival($1, $2); }
	|	T_Flag3	boolean		{ $$ = create_attr_ival($1, $2); }
	|	T_Flag4 boolean		{ $$ = create_attr_ival($1, $2); }
	;

/* Command for System Options
 * --------------------------
 */

system_option_command
	:	T_Enable system_option_list
			{ append_queue(cfgt.enable_opts, $2);  }
	|	T_Disable system_option_list
			{ append_queue(cfgt.disable_opts, $2);  }
	;

system_option_list
	:	system_option_list system_option
		{
			if ($2 != NULL)
				$$ = enqueue($1, $2);
			else
				$$ = $1;
		}
	|	system_option
		{
			if ($1 != NULL)
				$$ = enqueue_in_new_queue($1);
			else
				$$ = create_queue();
		}
	;

system_option
	:	T_Auth      { $$ = create_attr_ival(T_Flag, $1); }
	|	T_Bclient   { $$ = create_attr_ival(T_Flag, $1); }
	|	T_Calibrate { $$ = create_attr_ival(T_Flag, $1); }
	|	T_Kernel    { $$ = create_attr_ival(T_Flag, $1); }
	|	T_Monitor   { $$ = create_attr_ival(T_Flag, $1); }
	|	T_Ntp       { $$ = create_attr_ival(T_Flag, $1); }
	|	T_Stats     
		{ 
			if (input_from_file)
				$$ = create_attr_ival(T_Flag, $1);
			else {
				$$ = NULL;
				yyerror("enable/disable stats remote configuration ignored");
			}
		}
	;

/* Tinker Commands
 * ---------------
 */

tinker_command
	:	T_Tinker tinker_option_list  { append_queue(cfgt.tinker, $2); }
	;

tinker_option_list
	:	tinker_option_list tinker_option  { $$ = enqueue($1, $2); }
	|	tinker_option { $$ = enqueue_in_new_queue($1); }
	;

tinker_option
	:	T_Allan number	    { $$ = create_attr_dval($1, $2); }
	|	T_Dispersion number { $$ = create_attr_dval($1, $2); }
	|	T_Freq number	    { $$ = create_attr_dval($1, $2); }
	|	T_Huffpuff number   { $$ = create_attr_dval($1, $2); }
	|	T_Panic number	    { $$ = create_attr_dval($1, $2); }
	|	T_Step number	    { $$ = create_attr_dval($1, $2); }
	|	T_Stepout number    { $$ = create_attr_dval($1, $2); }
	;


/* Miscellaneous Commands
 * ----------------------
 */

miscellaneous_command
	:	interface_command
	|	T_Includefile T_String command
		{
			if (curr_include_level >= MAXINCLUDELEVEL) {
				fprintf(stderr, "getconfig: Maximum include file level exceeded.\n");
				msyslog(LOG_ERR, "getconfig: Maximum include file level exceeded.");
			}
			else {
				fp[curr_include_level + 1] = F_OPEN(FindConfig($2), "r");
				if (fp[curr_include_level + 1] == NULL) {
					fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig($2));
					msyslog(LOG_ERR, "getconfig: Couldn't open <%s>", FindConfig($2));
				}
				else
					ip_file = fp[++curr_include_level];
			}
		}
	|	T_End
		{
			while (curr_include_level != -1)
				FCLOSE(fp[curr_include_level--]);
		}

	|	T_Broadcastdelay number
			{ enqueue(cfgt.vars, create_attr_dval($1, $2)); }
	|	T_Calldelay T_Integer
			{ enqueue(cfgt.vars, create_attr_ival($1, $2)); }
	|	T_Tick number
			{ enqueue(cfgt.vars, create_attr_dval($1, $2)); }
	|	T_Driftfile drift_parm
			{ /* Null action, possibly all null parms */ }
	|	T_Leapfile T_String
			{ enqueue(cfgt.vars, create_attr_sval($1, $2)); }

	|	T_Pidfile T_String
			{ enqueue(cfgt.vars, create_attr_sval($1, $2)); }
	|	T_Logfile T_String
		{
			if (input_from_file)
				enqueue(cfgt.vars,
					create_attr_sval($1, $2));
			else {
				free($2);
				yyerror("logfile remote configuration ignored");
			}
		}

	|	T_Logconfig log_config_list
			{ append_queue(cfgt.logconfig, $2); }
	|	T_Phone string_list
			{ append_queue(cfgt.phone, $2); }
	|	T_Saveconfigdir	T_String
		{
			if (input_from_file)
				enqueue(cfgt.vars,
					create_attr_sval($1, $2));
			else {
				free($2);
				yyerror("saveconfigdir remote configuration ignored");
			}
		}
	|	T_Setvar variable_assign
			{ enqueue(cfgt.setvar, $2); }
	|	T_Trap ip_address
			{ enqueue(cfgt.trap, create_addr_opts_node($2, NULL)); }
	|	T_Trap ip_address trap_option_list
			{ enqueue(cfgt.trap, create_addr_opts_node($2, $3)); }
	|	T_Ttl integer_list
			{ append_queue(cfgt.ttl, $2); }
	|	T_Qos T_String
			{ enqueue(cfgt.qos, create_attr_sval($1, $2)); }
	;
	
drift_parm
	:	T_String
			{ enqueue(cfgt.vars, create_attr_sval(T_Driftfile, $1)); }
	|	T_String T_Double
			{ enqueue(cfgt.vars, create_attr_dval(T_WanderThreshold, $2));
			  enqueue(cfgt.vars, create_attr_sval(T_Driftfile, $1)); }
	|	/* Null driftfile,  indicated by null string "\0" */
			{ enqueue(cfgt.vars, create_attr_sval(T_Driftfile, "\0")); }
	;

variable_assign
	:	T_String '=' T_String T_Default
			{ $$ = create_setvar_node($1, $3, $4); }
	|	T_String '=' T_String
			{ $$ = create_setvar_node($1, $3, 0); }
	;

trap_option_list
	:	trap_option_list trap_option
				{ $$ = enqueue($1, $2); }
	|	trap_option	{ $$ = enqueue_in_new_queue($1); }
	;

trap_option
	:	T_Port T_Integer	{ $$ = create_attr_ival($1, $2); }
	|	T_Interface ip_address	{ $$ = create_attr_pval($1, $2); }
	;

log_config_list
	:	log_config_list log_config_command { $$ = enqueue($1, $2); }
	|	log_config_command  { $$ = enqueue_in_new_queue($1); }
	;

log_config_command
	:	T_String
		{
			char prefix = $1[0];
			char *type = $1 + 1;
			
			if (prefix != '+' && prefix != '-' && prefix != '=') {
				yyerror("Logconfig prefix is not '+', '-' or '='\n");
			}
			else
				$$ = create_attr_sval(prefix, estrdup(type));
			YYFREE($1);
		}
	;

interface_command
	:	interface_nic nic_rule_action nic_rule_class
		{
			enqueue(cfgt.nic_rules,
				create_nic_rule_node($3, NULL, $2));
		}
	|	interface_nic nic_rule_action T_String
		{
			enqueue(cfgt.nic_rules,
				create_nic_rule_node(0, $3, $2));
		}
	;

interface_nic
	:	T_Interface
	|	T_Nic
	;

nic_rule_class
	:	T_All
	|	T_Ipv4
	|	T_Ipv6
	|	T_Wildcard
	;

nic_rule_action
	:	T_Listen
	|	T_Ignore
	|	T_Drop
	;



/* Miscellaneous Rules
 * -------------------
 */

integer_list
	:	integer_list T_Integer { $$ = enqueue($1, create_ival($2)); }
	|	T_Integer { $$ = enqueue_in_new_queue(create_ival($1)); }
	;

string_list
	:	string_list T_String { $$ = enqueue($1, create_pval($2)); }
	|	T_String { $$ = enqueue_in_new_queue(create_pval($1)); }
	;

address_list
	:	address_list address { $$ = enqueue($1, $2); }
	|	address { $$ = enqueue_in_new_queue($1); }
	;

boolean
	:	T_Integer
		{
			if ($1 != 0 && $1 != 1) {
				yyerror("Integer value is not boolean (0 or 1). Assuming 1");
				$$ = 1;
			}
			else
				$$ = $1;
		}
	|	T_True    { $$ = 1; }
	|	T_False   { $$ = 0; }
	;

number
	:	T_Integer { $$ = (double)$1; }
	|	T_Double
	;


/* Simulator Configuration Commands
 * --------------------------------
 */

simulate_command
	:	sim_conf_start '{' sim_init_statement_list sim_server_list '}'
		{
			cfgt.sim_details = create_sim_node($3, $4);

			/* Reset the old_config_style variable */
			old_config_style = 1;
		}
	;

/* The following is a terrible hack to get the configuration file to
 * treat newlines as whitespace characters within the simulation.
 * This is needed because newlines are significant in the rest of the
 * configuration file.
 */
sim_conf_start
	:	T_Simulate { old_config_style = 0; }
	;

sim_init_statement_list
	:	sim_init_statement_list sim_init_statement T_EOC { $$ = enqueue($1, $2); }
	|	sim_init_statement T_EOC			 { $$ = enqueue_in_new_queue($1); }
	;

sim_init_statement
	:	T_Beep_Delay '=' number   { $$ = create_attr_dval($1, $3); }
	|	T_Sim_Duration '=' number { $$ = create_attr_dval($1, $3); }
	;

sim_server_list
	:	sim_server_list sim_server { $$ = enqueue($1, $2); }
	|	sim_server		   { $$ = enqueue_in_new_queue($1); }
	;

sim_server
	:	sim_server_name '{' sim_server_offset sim_act_list '}'
		{ $$ = create_sim_server($1, $3, $4); }
	;

sim_server_offset
	:	T_Server_Offset '=' number T_EOC { $$ = $3; }
	;

sim_server_name
	:	T_Server '=' address { $$ = $3; }
	;

sim_act_list
	:	sim_act_list sim_act { $$ = enqueue($1, $2); }
	|	sim_act		     { $$ = enqueue_in_new_queue($1); }
	;

sim_act
	:	T_Duration '=' number '{' sim_act_stmt_list '}'
			{ $$ = create_sim_script_info($3, $5); }
	;

sim_act_stmt_list
	:	sim_act_stmt_list sim_act_stmt T_EOC { $$ = enqueue($1, $2); }
	|	sim_act_stmt T_EOC		     { $$ = enqueue_in_new_queue($1); }
	;

sim_act_stmt
	:	T_Freq_Offset '=' number
			{ $$ = create_attr_dval($1, $3); }
	|	T_Wander '=' number
			{ $$ = create_attr_dval($1, $3); }
	|	T_Jitter '=' number
			{ $$ = create_attr_dval($1, $3); }
	|	T_Prop_Delay '=' number
			{ $$ = create_attr_dval($1, $3); }
	|	T_Proc_Delay '=' number
			{ $$ = create_attr_dval($1, $3); }
	;


%%

void yyerror (char *msg)
{
	int retval;

	ip_file->err_line_no = ip_file->prev_token_line_no;
	ip_file->err_col_no = ip_file->prev_token_col_no;
	
	msyslog(LOG_ERR, 
		"line %d column %d %s", 
		ip_file->err_line_no,
		ip_file->err_col_no,
		msg);
	if (!input_from_file) {
		/* Save the error message in the correct buffer */
		retval = snprintf(remote_config.err_msg + remote_config.err_pos,
				  MAXLINE - remote_config.err_pos,
				  "column %d %s",
				  ip_file->err_col_no, msg);

		/* Increment the value of err_pos */
		if (retval > 0)
			remote_config.err_pos += retval;

		/* Increment the number of errors */
		++remote_config.no_errors;
	}
}


/*
 * token_name - convert T_ token integers to text
 *		example: token_name(T_Server) returns "T_Server"
 */
const char *
token_name(
	int token
	)
{
	return yytname[YYTRANSLATE(token)];
}


/* Initial Testing function -- ignore
int main(int argc, char *argv[])
{
	ip_file = FOPEN(argv[1], "r");
	if (!ip_file) {
		fprintf(stderr, "ERROR!! Could not open file: %s\n", argv[1]);
	}
	key_scanner = create_keyword_scanner(keyword_list);
	print_keyword_scanner(key_scanner, 0);
	yyparse();
	return 0;
}
*/