1204076Spjd%{
2204076Spjd/*-
3204076Spjd * Copyright (c) 2009-2010 The FreeBSD Foundation
4219351Spjd * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>
5204076Spjd * All rights reserved.
6204076Spjd *
7204076Spjd * This software was developed by Pawel Jakub Dawidek under sponsorship from
8204076Spjd * the FreeBSD Foundation.
9204076Spjd *
10204076Spjd * Redistribution and use in source and binary forms, with or without
11204076Spjd * modification, are permitted provided that the following conditions
12204076Spjd * are met:
13204076Spjd * 1. Redistributions of source code must retain the above copyright
14204076Spjd *    notice, this list of conditions and the following disclaimer.
15204076Spjd * 2. Redistributions in binary form must reproduce the above copyright
16204076Spjd *    notice, this list of conditions and the following disclaimer in the
17204076Spjd *    documentation and/or other materials provided with the distribution.
18204076Spjd *
19204076Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
20204076Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21204076Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22204076Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
23204076Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24204076Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25204076Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26204076Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27204076Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28204076Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29204076Spjd * SUCH DAMAGE.
30204076Spjd *
31204076Spjd * $FreeBSD$
32204076Spjd */
33204076Spjd
34204076Spjd#include <sys/param.h>	/* MAXHOSTNAMELEN */
35204076Spjd#include <sys/queue.h>
36222108Spjd#include <sys/socket.h>
37204076Spjd#include <sys/sysctl.h>
38204076Spjd
39204076Spjd#include <arpa/inet.h>
40204076Spjd
41204076Spjd#include <err.h>
42222108Spjd#include <errno.h>
43204076Spjd#include <stdio.h>
44204076Spjd#include <string.h>
45204076Spjd#include <sysexits.h>
46204076Spjd#include <unistd.h>
47204076Spjd
48210883Spjd#include <pjdlog.h>
49210883Spjd
50204076Spjd#include "hast.h"
51204076Spjd
52204076Spjdextern int depth;
53204076Spjdextern int lineno;
54204076Spjd
55204076Spjdextern FILE *yyin;
56204076Spjdextern char *yytext;
57204076Spjd
58210883Spjdstatic struct hastd_config *lconfig;
59204076Spjdstatic struct hast_resource *curres;
60216721Spjdstatic bool mynode, hadmynode;
61204076Spjd
62204076Spjdstatic char depth0_control[HAST_ADDRSIZE];
63229509Strocinystatic char depth0_pidfile[PATH_MAX];
64222119Spjdstatic char depth0_listen_tcp4[HAST_ADDRSIZE];
65222119Spjdstatic char depth0_listen_tcp6[HAST_ADDRSIZE];
66222108Spjdstatic TAILQ_HEAD(, hastd_listen) depth0_listen;
67204076Spjdstatic int depth0_replication;
68219351Spjdstatic int depth0_checksum;
69219354Spjdstatic int depth0_compression;
70207371Spjdstatic int depth0_timeout;
71211886Spjdstatic char depth0_exec[PATH_MAX];
72229509Strocinystatic int depth0_metaflush;
73204076Spjd
74204076Spjdstatic char depth1_provname[PATH_MAX];
75204076Spjdstatic char depth1_localpath[PATH_MAX];
76229509Strocinystatic int depth1_metaflush;
77204076Spjd
78252181Smariusextern void yyerror(const char *);
79252181Smariusextern int yylex(void);
80210883Spjdextern void yyrestart(FILE *);
81210883Spjd
82210883Spjdstatic int
83204076Spjdisitme(const char *name)
84204076Spjd{
85204076Spjd	char buf[MAXHOSTNAMELEN];
86249236Strociny	unsigned long hostid;
87204076Spjd	char *pos;
88204076Spjd	size_t bufsize;
89204076Spjd
90204076Spjd	/*
91231017Strociny	 * First check if the given name matches our full hostname.
92204076Spjd	 */
93210883Spjd	if (gethostname(buf, sizeof(buf)) < 0) {
94210883Spjd		pjdlog_errno(LOG_ERR, "gethostname() failed");
95210883Spjd		return (-1);
96210883Spjd	}
97204076Spjd	if (strcmp(buf, name) == 0)
98210883Spjd		return (1);
99204076Spjd
100204076Spjd	/*
101249236Strociny	 * Check if it matches first part of the host name.
102204076Spjd	 */
103204076Spjd	pos = strchr(buf, '.');
104221632Strociny	if (pos != NULL && (size_t)(pos - buf) == strlen(name) &&
105221632Strociny	    strncmp(buf, name, pos - buf) == 0) {
106210883Spjd		return (1);
107221632Strociny	}
108204076Spjd
109204076Spjd	/*
110249236Strociny	 * Check if it matches host UUID.
111204076Spjd	 */
112204076Spjd	bufsize = sizeof(buf);
113210883Spjd	if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) {
114210883Spjd		pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed");
115210883Spjd		return (-1);
116210883Spjd	}
117204076Spjd	if (strcasecmp(buf, name) == 0)
118210883Spjd		return (1);
119204076Spjd
120249236Strociny 	/*
121249236Strociny	 * Check if it matches hostid.
122249236Strociny	 */
123249236Strociny	bufsize = sizeof(hostid);
124249236Strociny	if (sysctlbyname("kern.hostid", &hostid, &bufsize, NULL, 0) < 0) {
125249236Strociny		pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostid) failed");
126249236Strociny		return (-1);
127249236Strociny	}
128249236Strociny	(void)snprintf(buf, sizeof(buf), "hostid%lu", hostid);
129249236Strociny	if (strcmp(buf, name) == 0)
130249236Strociny		return (1);
131249236Strociny
132204076Spjd	/*
133204076Spjd	 * Looks like this isn't about us.
134204076Spjd	 */
135210883Spjd	return (0);
136204076Spjd}
137204076Spjd
138222108Spjdstatic bool
139222108Spjdfamily_supported(int family)
140222108Spjd{
141222108Spjd	int sock;
142222108Spjd
143222108Spjd	sock = socket(family, SOCK_STREAM, 0);
144222108Spjd	if (sock == -1 && errno == EPROTONOSUPPORT)
145222108Spjd		return (false);
146222108Spjd	if (sock >= 0)
147222108Spjd		(void)close(sock);
148222108Spjd	return (true);
149222108Spjd}
150222108Spjd
151216721Spjdstatic int
152216721Spjdnode_names(char **namesp)
153216721Spjd{
154216721Spjd	static char names[MAXHOSTNAMELEN * 3];
155216721Spjd	char buf[MAXHOSTNAMELEN];
156249236Strociny	unsigned long hostid;
157216721Spjd	char *pos;
158216721Spjd	size_t bufsize;
159216721Spjd
160216721Spjd	if (gethostname(buf, sizeof(buf)) < 0) {
161216721Spjd		pjdlog_errno(LOG_ERR, "gethostname() failed");
162216721Spjd		return (-1);
163216721Spjd	}
164216721Spjd
165216721Spjd	/* First component of the host name. */
166216721Spjd	pos = strchr(buf, '.');
167216721Spjd	if (pos != NULL && pos != buf) {
168216721Spjd		(void)strlcpy(names, buf, MIN((size_t)(pos - buf + 1),
169216721Spjd		    sizeof(names)));
170216721Spjd		(void)strlcat(names, ", ", sizeof(names));
171216721Spjd	}
172216721Spjd
173216721Spjd	/* Full host name. */
174216721Spjd	(void)strlcat(names, buf, sizeof(names));
175216721Spjd	(void)strlcat(names, ", ", sizeof(names));
176216721Spjd
177216721Spjd	/* Host UUID. */
178216721Spjd	bufsize = sizeof(buf);
179216721Spjd	if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) {
180216721Spjd		pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed");
181216721Spjd		return (-1);
182216721Spjd	}
183216721Spjd	(void)strlcat(names, buf, sizeof(names));
184249236Strociny	(void)strlcat(names, ", ", sizeof(names));
185216721Spjd
186249236Strociny	/* Host ID. */
187249236Strociny	bufsize = sizeof(hostid);
188249236Strociny	if (sysctlbyname("kern.hostid", &hostid, &bufsize, NULL, 0) < 0) {
189249236Strociny		pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostid) failed");
190249236Strociny		return (-1);
191249236Strociny	}
192249236Strociny	(void)snprintf(buf, sizeof(buf), "hostid%lu", hostid);
193249236Strociny	(void)strlcat(names, buf, sizeof(names));
194249236Strociny
195216721Spjd	*namesp = names;
196216721Spjd
197216721Spjd	return (0);
198216721Spjd}
199216721Spjd
200204076Spjdvoid
201204076Spjdyyerror(const char *str)
202204076Spjd{
203204076Spjd
204210883Spjd	pjdlog_error("Unable to parse configuration file at line %d near '%s': %s",
205204076Spjd	    lineno, yytext, str);
206204076Spjd}
207204076Spjd
208204076Spjdstruct hastd_config *
209210883Spjdyy_config_parse(const char *config, bool exitonerror)
210204076Spjd{
211204076Spjd	int ret;
212204076Spjd
213204076Spjd	curres = NULL;
214204076Spjd	mynode = false;
215210883Spjd	depth = 0;
216210883Spjd	lineno = 0;
217204076Spjd
218207371Spjd	depth0_timeout = HAST_TIMEOUT;
219249236Strociny	depth0_replication = HAST_REPLICATION_MEMSYNC;
220219351Spjd	depth0_checksum = HAST_CHECKSUM_NONE;
221219354Spjd	depth0_compression = HAST_COMPRESSION_HOLE;
222204076Spjd	strlcpy(depth0_control, HAST_CONTROL, sizeof(depth0_control));
223229509Strociny	strlcpy(depth0_pidfile, HASTD_PIDFILE, sizeof(depth0_pidfile));
224222108Spjd	TAILQ_INIT(&depth0_listen);
225222119Spjd	strlcpy(depth0_listen_tcp4, HASTD_LISTEN_TCP4,
226222119Spjd	    sizeof(depth0_listen_tcp4));
227222119Spjd	strlcpy(depth0_listen_tcp6, HASTD_LISTEN_TCP6,
228222119Spjd	    sizeof(depth0_listen_tcp6));
229211886Spjd	depth0_exec[0] = '\0';
230229509Strociny	depth0_metaflush = 1;
231204076Spjd
232210883Spjd	lconfig = calloc(1, sizeof(*lconfig));
233210883Spjd	if (lconfig == NULL) {
234210883Spjd		pjdlog_error("Unable to allocate memory for configuration.");
235210883Spjd		if (exitonerror)
236210883Spjd			exit(EX_TEMPFAIL);
237210883Spjd		return (NULL);
238210883Spjd	}
239204076Spjd
240222108Spjd	TAILQ_INIT(&lconfig->hc_listen);
241210883Spjd	TAILQ_INIT(&lconfig->hc_resources);
242210883Spjd
243204076Spjd	yyin = fopen(config, "r");
244210883Spjd	if (yyin == NULL) {
245210883Spjd		pjdlog_errno(LOG_ERR, "Unable to open configuration file %s",
246210883Spjd		    config);
247210883Spjd		yy_config_free(lconfig);
248210883Spjd		if (exitonerror)
249210883Spjd			exit(EX_OSFILE);
250210883Spjd		return (NULL);
251210883Spjd	}
252210883Spjd	yyrestart(yyin);
253204076Spjd	ret = yyparse();
254204076Spjd	fclose(yyin);
255204076Spjd	if (ret != 0) {
256210883Spjd		yy_config_free(lconfig);
257210883Spjd		if (exitonerror)
258210883Spjd			exit(EX_CONFIG);
259210883Spjd		return (NULL);
260204076Spjd	}
261204076Spjd
262204076Spjd	/*
263204076Spjd	 * Let's see if everything is set up.
264204076Spjd	 */
265210883Spjd	if (lconfig->hc_controladdr[0] == '\0') {
266210883Spjd		strlcpy(lconfig->hc_controladdr, depth0_control,
267210883Spjd		    sizeof(lconfig->hc_controladdr));
268204076Spjd	}
269229509Strociny	if (lconfig->hc_pidfile[0] == '\0') {
270229509Strociny		strlcpy(lconfig->hc_pidfile, depth0_pidfile,
271229509Strociny		    sizeof(lconfig->hc_pidfile));
272229509Strociny	}
273222108Spjd	if (!TAILQ_EMPTY(&depth0_listen))
274222108Spjd		TAILQ_CONCAT(&lconfig->hc_listen, &depth0_listen, hl_next);
275222108Spjd	if (TAILQ_EMPTY(&lconfig->hc_listen)) {
276222108Spjd		struct hastd_listen *lst;
277222108Spjd
278222108Spjd		if (family_supported(AF_INET)) {
279222108Spjd			lst = calloc(1, sizeof(*lst));
280222108Spjd			if (lst == NULL) {
281222108Spjd				pjdlog_error("Unable to allocate memory for listen address.");
282222108Spjd				yy_config_free(lconfig);
283222108Spjd				if (exitonerror)
284222108Spjd					exit(EX_TEMPFAIL);
285222108Spjd				return (NULL);
286222108Spjd			}
287222119Spjd			(void)strlcpy(lst->hl_addr, depth0_listen_tcp4,
288222108Spjd			    sizeof(lst->hl_addr));
289222108Spjd			TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next);
290222108Spjd		} else {
291222108Spjd			pjdlog_debug(1,
292222108Spjd			    "No IPv4 support in the kernel, not listening on IPv4 address.");
293222108Spjd		}
294222108Spjd		if (family_supported(AF_INET6)) {
295222108Spjd			lst = calloc(1, sizeof(*lst));
296222108Spjd			if (lst == NULL) {
297222108Spjd				pjdlog_error("Unable to allocate memory for listen address.");
298222108Spjd				yy_config_free(lconfig);
299222108Spjd				if (exitonerror)
300222108Spjd					exit(EX_TEMPFAIL);
301222108Spjd				return (NULL);
302222108Spjd			}
303222119Spjd			(void)strlcpy(lst->hl_addr, depth0_listen_tcp6,
304222108Spjd			    sizeof(lst->hl_addr));
305222108Spjd			TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next);
306222108Spjd		} else {
307222108Spjd			pjdlog_debug(1,
308222108Spjd			    "No IPv6 support in the kernel, not listening on IPv6 address.");
309222108Spjd		}
310222108Spjd		if (TAILQ_EMPTY(&lconfig->hc_listen)) {
311222108Spjd			pjdlog_error("No address to listen on.");
312222108Spjd			yy_config_free(lconfig);
313222108Spjd			if (exitonerror)
314222108Spjd				exit(EX_TEMPFAIL);
315222108Spjd			return (NULL);
316222108Spjd		}
317204076Spjd	}
318210883Spjd	TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) {
319229509Strociny		PJDLOG_ASSERT(curres->hr_provname[0] != '\0');
320229509Strociny		PJDLOG_ASSERT(curres->hr_localpath[0] != '\0');
321229509Strociny		PJDLOG_ASSERT(curres->hr_remoteaddr[0] != '\0');
322204076Spjd
323204076Spjd		if (curres->hr_replication == -1) {
324204076Spjd			/*
325204076Spjd			 * Replication is not set at resource-level.
326204076Spjd			 * Use global or default setting.
327204076Spjd			 */
328204076Spjd			curres->hr_replication = depth0_replication;
329249236Strociny			curres->hr_original_replication = depth0_replication;
330204076Spjd		}
331219351Spjd		if (curres->hr_checksum == -1) {
332219351Spjd			/*
333219351Spjd			 * Checksum is not set at resource-level.
334219351Spjd			 * Use global or default setting.
335219351Spjd			 */
336219351Spjd			curres->hr_checksum = depth0_checksum;
337219351Spjd		}
338219354Spjd		if (curres->hr_compression == -1) {
339219354Spjd			/*
340219354Spjd			 * Compression is not set at resource-level.
341219354Spjd			 * Use global or default setting.
342219354Spjd			 */
343219354Spjd			curres->hr_compression = depth0_compression;
344219354Spjd		}
345207371Spjd		if (curres->hr_timeout == -1) {
346207371Spjd			/*
347207371Spjd			 * Timeout is not set at resource-level.
348207371Spjd			 * Use global or default setting.
349207371Spjd			 */
350207371Spjd			curres->hr_timeout = depth0_timeout;
351207371Spjd		}
352211886Spjd		if (curres->hr_exec[0] == '\0') {
353211886Spjd			/*
354211886Spjd			 * Exec is not set at resource-level.
355211886Spjd			 * Use global or default setting.
356211886Spjd			 */
357211886Spjd			strlcpy(curres->hr_exec, depth0_exec,
358211886Spjd			    sizeof(curres->hr_exec));
359211886Spjd		}
360229509Strociny		if (curres->hr_metaflush == -1) {
361229509Strociny			/*
362229509Strociny			 * Metaflush is not set at resource-level.
363229509Strociny			 * Use global or default setting.
364229509Strociny			 */
365229509Strociny			curres->hr_metaflush = depth0_metaflush;
366229509Strociny		}
367204076Spjd	}
368204076Spjd
369210883Spjd	return (lconfig);
370204076Spjd}
371204076Spjd
372204076Spjdvoid
373204076Spjdyy_config_free(struct hastd_config *config)
374204076Spjd{
375222108Spjd	struct hastd_listen *lst;
376204076Spjd	struct hast_resource *res;
377204076Spjd
378222108Spjd	while ((lst = TAILQ_FIRST(&depth0_listen)) != NULL) {
379222108Spjd		TAILQ_REMOVE(&depth0_listen, lst, hl_next);
380222108Spjd		free(lst);
381222108Spjd	}
382222108Spjd	while ((lst = TAILQ_FIRST(&config->hc_listen)) != NULL) {
383222108Spjd		TAILQ_REMOVE(&config->hc_listen, lst, hl_next);
384222108Spjd		free(lst);
385222108Spjd	}
386204076Spjd	while ((res = TAILQ_FIRST(&config->hc_resources)) != NULL) {
387204076Spjd		TAILQ_REMOVE(&config->hc_resources, res, hr_next);
388204076Spjd		free(res);
389204076Spjd	}
390210883Spjd	free(config);
391204076Spjd}
392204076Spjd%}
393204076Spjd
394231017Strociny%token CONTROL PIDFILE LISTEN REPLICATION CHECKSUM COMPRESSION METAFLUSH
395231017Strociny%token TIMEOUT EXEC RESOURCE NAME LOCAL REMOTE SOURCE ON OFF
396219354Spjd%token FULLSYNC MEMSYNC ASYNC NONE CRC32 SHA256 HOLE LZF
397204076Spjd%token NUM STR OB CB
398204076Spjd
399221643Spjd%type <str> remote_str
400204076Spjd%type <num> replication_type
401219351Spjd%type <num> checksum_type
402219354Spjd%type <num> compression_type
403229509Strociny%type <num> boolean
404204076Spjd
405204076Spjd%union
406204076Spjd{
407204076Spjd	int num;
408204076Spjd	char *str;
409204076Spjd}
410204076Spjd
411204076Spjd%token <num> NUM
412204076Spjd%token <str> STR
413204076Spjd
414204076Spjd%%
415204076Spjd
416204076Spjdstatements:
417204076Spjd	|
418204076Spjd	statements statement
419204076Spjd	;
420204076Spjd
421204076Spjdstatement:
422204076Spjd	control_statement
423204076Spjd	|
424229509Strociny	pidfile_statement
425229509Strociny	|
426204076Spjd	listen_statement
427204076Spjd	|
428204076Spjd	replication_statement
429204076Spjd	|
430219351Spjd	checksum_statement
431219351Spjd	|
432219354Spjd	compression_statement
433219354Spjd	|
434207371Spjd	timeout_statement
435207371Spjd	|
436211886Spjd	exec_statement
437211886Spjd	|
438229509Strociny	metaflush_statement
439229509Strociny	|
440204076Spjd	node_statement
441204076Spjd	|
442204076Spjd	resource_statement
443204076Spjd	;
444204076Spjd
445204076Spjdcontrol_statement:	CONTROL STR
446204076Spjd	{
447204076Spjd		switch (depth) {
448204076Spjd		case 0:
449204076Spjd			if (strlcpy(depth0_control, $2,
450204076Spjd			    sizeof(depth0_control)) >=
451204076Spjd			    sizeof(depth0_control)) {
452210883Spjd				pjdlog_error("control argument is too long.");
453214274Spjd				free($2);
454210883Spjd				return (1);
455204076Spjd			}
456204076Spjd			break;
457204076Spjd		case 1:
458211883Spjd			if (!mynode)
459211883Spjd				break;
460211883Spjd			if (strlcpy(lconfig->hc_controladdr, $2,
461211883Spjd			    sizeof(lconfig->hc_controladdr)) >=
462211883Spjd			    sizeof(lconfig->hc_controladdr)) {
463211883Spjd				pjdlog_error("control argument is too long.");
464214274Spjd				free($2);
465211883Spjd				return (1);
466204076Spjd			}
467204076Spjd			break;
468204076Spjd		default:
469229509Strociny			PJDLOG_ABORT("control at wrong depth level");
470204076Spjd		}
471214274Spjd		free($2);
472204076Spjd	}
473204076Spjd	;
474204076Spjd
475229509Strocinypidfile_statement:	PIDFILE STR
476229509Strociny	{
477229509Strociny		switch (depth) {
478229509Strociny		case 0:
479229509Strociny			if (strlcpy(depth0_pidfile, $2,
480229509Strociny			    sizeof(depth0_pidfile)) >=
481229509Strociny			    sizeof(depth0_pidfile)) {
482229509Strociny				pjdlog_error("pidfile argument is too long.");
483229509Strociny				free($2);
484229509Strociny				return (1);
485229509Strociny			}
486229509Strociny			break;
487229509Strociny		case 1:
488229509Strociny			if (!mynode)
489229509Strociny				break;
490229509Strociny			if (strlcpy(lconfig->hc_pidfile, $2,
491229509Strociny			    sizeof(lconfig->hc_pidfile)) >=
492229509Strociny			    sizeof(lconfig->hc_pidfile)) {
493229509Strociny				pjdlog_error("pidfile argument is too long.");
494229509Strociny				free($2);
495229509Strociny				return (1);
496229509Strociny			}
497229509Strociny			break;
498229509Strociny		default:
499229509Strociny			PJDLOG_ABORT("pidfile at wrong depth level");
500229509Strociny		}
501229509Strociny		free($2);
502229509Strociny	}
503229509Strociny	;
504229509Strociny
505204076Spjdlisten_statement:	LISTEN STR
506204076Spjd	{
507222108Spjd		struct hastd_listen *lst;
508222108Spjd
509222108Spjd		lst = calloc(1, sizeof(*lst));
510222108Spjd		if (lst == NULL) {
511222108Spjd			pjdlog_error("Unable to allocate memory for listen address.");
512222108Spjd			free($2);
513222108Spjd			return (1);
514222108Spjd		}
515222108Spjd		if (strlcpy(lst->hl_addr, $2, sizeof(lst->hl_addr)) >=
516222108Spjd		    sizeof(lst->hl_addr)) {
517222108Spjd			pjdlog_error("listen argument is too long.");
518222108Spjd			free($2);
519222108Spjd			free(lst);
520222108Spjd			return (1);
521222108Spjd		}
522204076Spjd		switch (depth) {
523204076Spjd		case 0:
524222108Spjd			TAILQ_INSERT_TAIL(&depth0_listen, lst, hl_next);
525204076Spjd			break;
526204076Spjd		case 1:
527222108Spjd			if (mynode)
528222108Spjd				TAILQ_INSERT_TAIL(&depth0_listen, lst, hl_next);
529222108Spjd			else
530222108Spjd				free(lst);
531204076Spjd			break;
532204076Spjd		default:
533229509Strociny			PJDLOG_ABORT("listen at wrong depth level");
534204076Spjd		}
535214274Spjd		free($2);
536204076Spjd	}
537204076Spjd	;
538204076Spjd
539204076Spjdreplication_statement:	REPLICATION replication_type
540204076Spjd	{
541204076Spjd		switch (depth) {
542204076Spjd		case 0:
543204076Spjd			depth0_replication = $2;
544204076Spjd			break;
545204076Spjd		case 1:
546229509Strociny			PJDLOG_ASSERT(curres != NULL);
547229509Strociny			curres->hr_replication = $2;
548249236Strociny			curres->hr_original_replication = $2;
549204076Spjd			break;
550204076Spjd		default:
551229509Strociny			PJDLOG_ABORT("replication at wrong depth level");
552204076Spjd		}
553204076Spjd	}
554204076Spjd	;
555204076Spjd
556204076Spjdreplication_type:
557204076Spjd	FULLSYNC	{ $$ = HAST_REPLICATION_FULLSYNC; }
558204076Spjd	|
559204076Spjd	MEMSYNC		{ $$ = HAST_REPLICATION_MEMSYNC; }
560204076Spjd	|
561204076Spjd	ASYNC		{ $$ = HAST_REPLICATION_ASYNC; }
562204076Spjd	;
563204076Spjd
564219351Spjdchecksum_statement:	CHECKSUM checksum_type
565219351Spjd	{
566219351Spjd		switch (depth) {
567219351Spjd		case 0:
568219351Spjd			depth0_checksum = $2;
569219351Spjd			break;
570219351Spjd		case 1:
571229509Strociny			PJDLOG_ASSERT(curres != NULL);
572229509Strociny			curres->hr_checksum = $2;
573219351Spjd			break;
574219351Spjd		default:
575229509Strociny			PJDLOG_ABORT("checksum at wrong depth level");
576219351Spjd		}
577219351Spjd	}
578219351Spjd	;
579219351Spjd
580219351Spjdchecksum_type:
581219351Spjd	NONE		{ $$ = HAST_CHECKSUM_NONE; }
582219351Spjd	|
583219351Spjd	CRC32		{ $$ = HAST_CHECKSUM_CRC32; }
584219351Spjd	|
585219351Spjd	SHA256		{ $$ = HAST_CHECKSUM_SHA256; }
586219351Spjd	;
587219351Spjd
588219354Spjdcompression_statement:	COMPRESSION compression_type
589219354Spjd	{
590219354Spjd		switch (depth) {
591219354Spjd		case 0:
592219354Spjd			depth0_compression = $2;
593219354Spjd			break;
594219354Spjd		case 1:
595229509Strociny			PJDLOG_ASSERT(curres != NULL);
596229509Strociny			curres->hr_compression = $2;
597219354Spjd			break;
598219354Spjd		default:
599229509Strociny			PJDLOG_ABORT("compression at wrong depth level");
600219354Spjd		}
601219354Spjd	}
602219354Spjd	;
603219354Spjd
604219354Spjdcompression_type:
605219354Spjd	NONE		{ $$ = HAST_COMPRESSION_NONE; }
606219354Spjd	|
607219354Spjd	HOLE		{ $$ = HAST_COMPRESSION_HOLE; }
608219354Spjd	|
609219354Spjd	LZF		{ $$ = HAST_COMPRESSION_LZF; }
610219354Spjd	;
611219354Spjd
612207371Spjdtimeout_statement:	TIMEOUT NUM
613207371Spjd	{
614220889Spjd		if ($2 <= 0) {
615220889Spjd			pjdlog_error("Negative or zero timeout.");
616220889Spjd			return (1);
617220889Spjd		}
618207371Spjd		switch (depth) {
619207371Spjd		case 0:
620207371Spjd			depth0_timeout = $2;
621207371Spjd			break;
622207371Spjd		case 1:
623229509Strociny			PJDLOG_ASSERT(curres != NULL);
624229509Strociny			curres->hr_timeout = $2;
625207371Spjd			break;
626207371Spjd		default:
627229509Strociny			PJDLOG_ABORT("timeout at wrong depth level");
628207371Spjd		}
629207371Spjd	}
630207371Spjd	;
631207371Spjd
632211886Spjdexec_statement:		EXEC STR
633211886Spjd	{
634211886Spjd		switch (depth) {
635211886Spjd		case 0:
636211886Spjd			if (strlcpy(depth0_exec, $2, sizeof(depth0_exec)) >=
637211886Spjd			    sizeof(depth0_exec)) {
638211886Spjd				pjdlog_error("Exec path is too long.");
639214274Spjd				free($2);
640211886Spjd				return (1);
641211886Spjd			}
642211886Spjd			break;
643211886Spjd		case 1:
644229509Strociny			PJDLOG_ASSERT(curres != NULL);
645211886Spjd			if (strlcpy(curres->hr_exec, $2,
646211886Spjd			    sizeof(curres->hr_exec)) >=
647211886Spjd			    sizeof(curres->hr_exec)) {
648211886Spjd				pjdlog_error("Exec path is too long.");
649214274Spjd				free($2);
650211886Spjd				return (1);
651211886Spjd			}
652211886Spjd			break;
653211886Spjd		default:
654229509Strociny			PJDLOG_ABORT("exec at wrong depth level");
655211886Spjd		}
656214274Spjd		free($2);
657211886Spjd	}
658211886Spjd	;
659211886Spjd
660229509Strocinymetaflush_statement:	METAFLUSH boolean
661229509Strociny	{
662229509Strociny		switch (depth) {
663229509Strociny		case 0:
664229509Strociny			depth0_metaflush = $2;
665229509Strociny			break;
666229509Strociny		case 1:
667229509Strociny			PJDLOG_ASSERT(curres != NULL);
668229509Strociny			depth1_metaflush = $2;
669229509Strociny			break;
670229509Strociny		case 2:
671229509Strociny			if (!mynode)
672229509Strociny				break;
673229509Strociny			PJDLOG_ASSERT(curres != NULL);
674229509Strociny			curres->hr_metaflush = $2;
675229509Strociny			break;
676229509Strociny		default:
677229509Strociny			PJDLOG_ABORT("metaflush at wrong depth level");
678229509Strociny		}
679229509Strociny	}
680229509Strociny	;
681229509Strociny
682229509Strocinyboolean:
683229509Strociny	ON		{ $$ = 1; }
684229509Strociny	|
685229509Strociny	OFF		{ $$ = 0; }
686229509Strociny	;
687229509Strociny
688204076Spjdnode_statement:		ON node_start OB node_entries CB
689204076Spjd	{
690204076Spjd		mynode = false;
691204076Spjd	}
692204076Spjd	;
693204076Spjd
694204076Spjdnode_start:	STR
695204076Spjd	{
696210883Spjd		switch (isitme($1)) {
697210883Spjd		case -1:
698214274Spjd			free($1);
699210883Spjd			return (1);
700210883Spjd		case 0:
701210883Spjd			break;
702210883Spjd		case 1:
703204076Spjd			mynode = true;
704210883Spjd			break;
705210883Spjd		default:
706229509Strociny			PJDLOG_ABORT("invalid isitme() return value");
707210883Spjd		}
708214274Spjd		free($1);
709204076Spjd	}
710204076Spjd	;
711204076Spjd
712204076Spjdnode_entries:
713204076Spjd	|
714204076Spjd	node_entries node_entry
715204076Spjd	;
716204076Spjd
717204076Spjdnode_entry:
718204076Spjd	control_statement
719204076Spjd	|
720229509Strociny	pidfile_statement
721229509Strociny	|
722204076Spjd	listen_statement
723204076Spjd	;
724204076Spjd
725204076Spjdresource_statement:	RESOURCE resource_start OB resource_entries CB
726204076Spjd	{
727204076Spjd		if (curres != NULL) {
728204076Spjd			/*
729216721Spjd			 * There must be section for this node, at least with
730216721Spjd			 * remote address configuration.
731216721Spjd			 */
732216721Spjd			if (!hadmynode) {
733216721Spjd				char *names;
734216721Spjd
735216721Spjd				if (node_names(&names) != 0)
736216721Spjd					return (1);
737216721Spjd				pjdlog_error("No resource %s configuration for this node (acceptable node names: %s).",
738216721Spjd				    curres->hr_name, names);
739216721Spjd				return (1);
740216721Spjd			}
741216721Spjd
742216721Spjd			/*
743229509Strociny			 * Let's see if there are some resource-level settings
744204076Spjd			 * that we can use for node-level settings.
745204076Spjd			 */
746204076Spjd			if (curres->hr_provname[0] == '\0' &&
747204076Spjd			    depth1_provname[0] != '\0') {
748204076Spjd				/*
749204076Spjd				 * Provider name is not set at node-level,
750204076Spjd				 * but is set at resource-level, use it.
751204076Spjd				 */
752204076Spjd				strlcpy(curres->hr_provname, depth1_provname,
753204076Spjd				    sizeof(curres->hr_provname));
754204076Spjd			}
755204076Spjd			if (curres->hr_localpath[0] == '\0' &&
756204076Spjd			    depth1_localpath[0] != '\0') {
757204076Spjd				/*
758204076Spjd				 * Path to local provider is not set at
759204076Spjd				 * node-level, but is set at resource-level,
760204076Spjd				 * use it.
761204076Spjd				 */
762204076Spjd				strlcpy(curres->hr_localpath, depth1_localpath,
763204076Spjd				    sizeof(curres->hr_localpath));
764204076Spjd			}
765229509Strociny			if (curres->hr_metaflush == -1 && depth1_metaflush != -1) {
766229509Strociny				/*
767229509Strociny				 * Metaflush is not set at node-level,
768229509Strociny				 * but is set at resource-level, use it.
769229509Strociny				 */
770229509Strociny				curres->hr_metaflush = depth1_metaflush;
771229509Strociny			}
772204076Spjd
773204076Spjd			/*
774204076Spjd			 * If provider name is not given, use resource name
775204076Spjd			 * as provider name.
776204076Spjd			 */
777204076Spjd			if (curres->hr_provname[0] == '\0') {
778204076Spjd				strlcpy(curres->hr_provname, curres->hr_name,
779204076Spjd				    sizeof(curres->hr_provname));
780204076Spjd			}
781204076Spjd
782204076Spjd			/*
783204076Spjd			 * Remote address has to be configured at this point.
784204076Spjd			 */
785204076Spjd			if (curres->hr_remoteaddr[0] == '\0') {
786210883Spjd				pjdlog_error("Remote address not configured for resource %s.",
787204076Spjd				    curres->hr_name);
788210883Spjd				return (1);
789204076Spjd			}
790204076Spjd			/*
791204076Spjd			 * Path to local provider has to be configured at this
792204076Spjd			 * point.
793204076Spjd			 */
794204076Spjd			if (curres->hr_localpath[0] == '\0') {
795210883Spjd				pjdlog_error("Path to local component not configured for resource %s.",
796204076Spjd				    curres->hr_name);
797210883Spjd				return (1);
798204076Spjd			}
799204076Spjd
800204076Spjd			/* Put it onto resource list. */
801210883Spjd			TAILQ_INSERT_TAIL(&lconfig->hc_resources, curres, hr_next);
802204076Spjd			curres = NULL;
803204076Spjd		}
804204076Spjd	}
805204076Spjd	;
806204076Spjd
807204076Spjdresource_start:	STR
808204076Spjd	{
809216722Spjd		/* Check if there is no duplicate entry. */
810216722Spjd		TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) {
811216722Spjd			if (strcmp(curres->hr_name, $1) == 0) {
812216722Spjd				pjdlog_error("Resource %s configured more than once.",
813216722Spjd				    curres->hr_name);
814216722Spjd				free($1);
815216722Spjd				return (1);
816216722Spjd			}
817216722Spjd		}
818216722Spjd
819204076Spjd		/*
820204076Spjd		 * Clear those, so we can tell if they were set at
821204076Spjd		 * resource-level or not.
822204076Spjd		 */
823204076Spjd		depth1_provname[0] = '\0';
824204076Spjd		depth1_localpath[0] = '\0';
825229509Strociny		depth1_metaflush = -1;
826216721Spjd		hadmynode = false;
827204076Spjd
828204076Spjd		curres = calloc(1, sizeof(*curres));
829204076Spjd		if (curres == NULL) {
830210883Spjd			pjdlog_error("Unable to allocate memory for resource.");
831214274Spjd			free($1);
832210883Spjd			return (1);
833204076Spjd		}
834204076Spjd		if (strlcpy(curres->hr_name, $1,
835204076Spjd		    sizeof(curres->hr_name)) >=
836204076Spjd		    sizeof(curres->hr_name)) {
837210883Spjd			pjdlog_error("Resource name is too long.");
838231017Strociny			free(curres);
839214274Spjd			free($1);
840210883Spjd			return (1);
841204076Spjd		}
842214274Spjd		free($1);
843204076Spjd		curres->hr_role = HAST_ROLE_INIT;
844204076Spjd		curres->hr_previous_role = HAST_ROLE_INIT;
845204076Spjd		curres->hr_replication = -1;
846249236Strociny		curres->hr_original_replication = -1;
847219351Spjd		curres->hr_checksum = -1;
848219354Spjd		curres->hr_compression = -1;
849249236Strociny		curres->hr_version = 1;
850207371Spjd		curres->hr_timeout = -1;
851211886Spjd		curres->hr_exec[0] = '\0';
852204076Spjd		curres->hr_provname[0] = '\0';
853204076Spjd		curres->hr_localpath[0] = '\0';
854204076Spjd		curres->hr_localfd = -1;
855229509Strociny		curres->hr_localflush = true;
856229509Strociny		curres->hr_metaflush = -1;
857204076Spjd		curres->hr_remoteaddr[0] = '\0';
858219818Spjd		curres->hr_sourceaddr[0] = '\0';
859204076Spjd		curres->hr_ggateunit = -1;
860204076Spjd	}
861204076Spjd	;
862204076Spjd
863204076Spjdresource_entries:
864204076Spjd	|
865204076Spjd	resource_entries resource_entry
866204076Spjd	;
867204076Spjd
868204076Spjdresource_entry:
869204076Spjd	replication_statement
870204076Spjd	|
871219351Spjd	checksum_statement
872219351Spjd	|
873219354Spjd	compression_statement
874219354Spjd	|
875207371Spjd	timeout_statement
876207371Spjd	|
877211886Spjd	exec_statement
878211886Spjd	|
879229509Strociny	metaflush_statement
880229509Strociny	|
881204076Spjd	name_statement
882204076Spjd	|
883204076Spjd	local_statement
884204076Spjd	|
885204076Spjd	resource_node_statement
886204076Spjd	;
887204076Spjd
888204076Spjdname_statement:		NAME STR
889204076Spjd	{
890204076Spjd		switch (depth) {
891204076Spjd		case 1:
892204076Spjd			if (strlcpy(depth1_provname, $2,
893204076Spjd			    sizeof(depth1_provname)) >=
894204076Spjd			    sizeof(depth1_provname)) {
895210883Spjd				pjdlog_error("name argument is too long.");
896214274Spjd				free($2);
897210883Spjd				return (1);
898204076Spjd			}
899204076Spjd			break;
900204076Spjd		case 2:
901211883Spjd			if (!mynode)
902211883Spjd				break;
903229509Strociny			PJDLOG_ASSERT(curres != NULL);
904211883Spjd			if (strlcpy(curres->hr_provname, $2,
905211883Spjd			    sizeof(curres->hr_provname)) >=
906211883Spjd			    sizeof(curres->hr_provname)) {
907211883Spjd				pjdlog_error("name argument is too long.");
908214274Spjd				free($2);
909211883Spjd				return (1);
910204076Spjd			}
911204076Spjd			break;
912204076Spjd		default:
913229509Strociny			PJDLOG_ABORT("name at wrong depth level");
914204076Spjd		}
915214274Spjd		free($2);
916204076Spjd	}
917204076Spjd	;
918204076Spjd
919204076Spjdlocal_statement:	LOCAL STR
920204076Spjd	{
921204076Spjd		switch (depth) {
922204076Spjd		case 1:
923204076Spjd			if (strlcpy(depth1_localpath, $2,
924204076Spjd			    sizeof(depth1_localpath)) >=
925204076Spjd			    sizeof(depth1_localpath)) {
926210883Spjd				pjdlog_error("local argument is too long.");
927214274Spjd				free($2);
928210883Spjd				return (1);
929204076Spjd			}
930204076Spjd			break;
931204076Spjd		case 2:
932211883Spjd			if (!mynode)
933211883Spjd				break;
934229509Strociny			PJDLOG_ASSERT(curres != NULL);
935211883Spjd			if (strlcpy(curres->hr_localpath, $2,
936211883Spjd			    sizeof(curres->hr_localpath)) >=
937211883Spjd			    sizeof(curres->hr_localpath)) {
938211883Spjd				pjdlog_error("local argument is too long.");
939214274Spjd				free($2);
940211883Spjd				return (1);
941204076Spjd			}
942204076Spjd			break;
943204076Spjd		default:
944229509Strociny			PJDLOG_ABORT("local at wrong depth level");
945204076Spjd		}
946214274Spjd		free($2);
947204076Spjd	}
948204076Spjd	;
949204076Spjd
950204076Spjdresource_node_statement:ON resource_node_start OB resource_node_entries CB
951204076Spjd	{
952204076Spjd		mynode = false;
953204076Spjd	}
954204076Spjd	;
955204076Spjd
956204076Spjdresource_node_start:	STR
957204076Spjd	{
958210883Spjd		if (curres != NULL) {
959210883Spjd			switch (isitme($1)) {
960210883Spjd			case -1:
961214274Spjd				free($1);
962210883Spjd				return (1);
963210883Spjd			case 0:
964210883Spjd				break;
965210883Spjd			case 1:
966216721Spjd				mynode = hadmynode = true;
967210883Spjd				break;
968210883Spjd			default:
969229509Strociny				PJDLOG_ABORT("invalid isitme() return value");
970210883Spjd			}
971210883Spjd		}
972214274Spjd		free($1);
973204076Spjd	}
974204076Spjd	;
975204076Spjd
976204076Spjdresource_node_entries:
977204076Spjd	|
978204076Spjd	resource_node_entries resource_node_entry
979204076Spjd	;
980204076Spjd
981204076Spjdresource_node_entry:
982204076Spjd	name_statement
983204076Spjd	|
984204076Spjd	local_statement
985204076Spjd	|
986204076Spjd	remote_statement
987219818Spjd	|
988219818Spjd	source_statement
989229509Strociny	|
990229509Strociny	metaflush_statement
991204076Spjd	;
992204076Spjd
993221643Spjdremote_statement:	REMOTE remote_str
994204076Spjd	{
995229509Strociny		PJDLOG_ASSERT(depth == 2);
996204076Spjd		if (mynode) {
997229509Strociny			PJDLOG_ASSERT(curres != NULL);
998204076Spjd			if (strlcpy(curres->hr_remoteaddr, $2,
999204076Spjd			    sizeof(curres->hr_remoteaddr)) >=
1000204076Spjd			    sizeof(curres->hr_remoteaddr)) {
1001210883Spjd				pjdlog_error("remote argument is too long.");
1002214274Spjd				free($2);
1003210883Spjd				return (1);
1004204076Spjd			}
1005204076Spjd		}
1006214274Spjd		free($2);
1007204076Spjd	}
1008204076Spjd	;
1009219818Spjd
1010221643Spjdremote_str:
1011221643Spjd	NONE		{ $$ = strdup("none"); }
1012221643Spjd	|
1013221643Spjd	STR		{ }
1014221643Spjd	;
1015221643Spjd
1016219818Spjdsource_statement:	SOURCE STR
1017219818Spjd	{
1018229509Strociny		PJDLOG_ASSERT(depth == 2);
1019219818Spjd		if (mynode) {
1020229509Strociny			PJDLOG_ASSERT(curres != NULL);
1021219818Spjd			if (strlcpy(curres->hr_sourceaddr, $2,
1022219818Spjd			    sizeof(curres->hr_sourceaddr)) >=
1023219818Spjd			    sizeof(curres->hr_sourceaddr)) {
1024219818Spjd				pjdlog_error("source argument is too long.");
1025219818Spjd				free($2);
1026219818Spjd				return (1);
1027219818Spjd			}
1028219818Spjd		}
1029219818Spjd		free($2);
1030219818Spjd	}
1031219818Spjd	;
1032