parse.y revision 222108
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: head/sbin/hastd/parse.y 222108 2011-05-19 23:18:42Z pjd $
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 <assert.h>
42204076Spjd#include <err.h>
43222108Spjd#include <errno.h>
44204076Spjd#include <stdio.h>
45204076Spjd#include <string.h>
46204076Spjd#include <sysexits.h>
47204076Spjd#include <unistd.h>
48204076Spjd
49210883Spjd#include <pjdlog.h>
50210883Spjd
51204076Spjd#include "hast.h"
52204076Spjd
53204076Spjdextern int depth;
54204076Spjdextern int lineno;
55204076Spjd
56204076Spjdextern FILE *yyin;
57204076Spjdextern char *yytext;
58204076Spjd
59210883Spjdstatic struct hastd_config *lconfig;
60204076Spjdstatic struct hast_resource *curres;
61216721Spjdstatic bool mynode, hadmynode;
62204076Spjd
63204076Spjdstatic char depth0_control[HAST_ADDRSIZE];
64222108Spjdstatic char depth0_listen_ipv4[HAST_ADDRSIZE];
65222108Spjdstatic char depth0_listen_ipv6[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];
72204076Spjd
73204076Spjdstatic char depth1_provname[PATH_MAX];
74204076Spjdstatic char depth1_localpath[PATH_MAX];
75204076Spjd
76210883Spjdextern void yyrestart(FILE *);
77210883Spjd
78210883Spjdstatic int
79204076Spjdisitme(const char *name)
80204076Spjd{
81204076Spjd	char buf[MAXHOSTNAMELEN];
82204076Spjd	char *pos;
83204076Spjd	size_t bufsize;
84204076Spjd
85204076Spjd	/*
86204076Spjd	 * First check if the give name matches our full hostname.
87204076Spjd	 */
88210883Spjd	if (gethostname(buf, sizeof(buf)) < 0) {
89210883Spjd		pjdlog_errno(LOG_ERR, "gethostname() failed");
90210883Spjd		return (-1);
91210883Spjd	}
92204076Spjd	if (strcmp(buf, name) == 0)
93210883Spjd		return (1);
94204076Spjd
95204076Spjd	/*
96204076Spjd	 * Now check if it matches first part of the host name.
97204076Spjd	 */
98204076Spjd	pos = strchr(buf, '.');
99221632Strociny	if (pos != NULL && (size_t)(pos - buf) == strlen(name) &&
100221632Strociny	    strncmp(buf, name, pos - buf) == 0) {
101210883Spjd		return (1);
102221632Strociny	}
103204076Spjd
104204076Spjd	/*
105204076Spjd	 * At the end check if name is equal to our host's UUID.
106204076Spjd	 */
107204076Spjd	bufsize = sizeof(buf);
108210883Spjd	if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) {
109210883Spjd		pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed");
110210883Spjd		return (-1);
111210883Spjd	}
112204076Spjd	if (strcasecmp(buf, name) == 0)
113210883Spjd		return (1);
114204076Spjd
115204076Spjd	/*
116204076Spjd	 * Looks like this isn't about us.
117204076Spjd	 */
118210883Spjd	return (0);
119204076Spjd}
120204076Spjd
121222108Spjdstatic bool
122222108Spjdfamily_supported(int family)
123222108Spjd{
124222108Spjd	int sock;
125222108Spjd
126222108Spjd	sock = socket(family, SOCK_STREAM, 0);
127222108Spjd	if (sock == -1 && errno == EPROTONOSUPPORT)
128222108Spjd		return (false);
129222108Spjd	if (sock >= 0)
130222108Spjd		(void)close(sock);
131222108Spjd	return (true);
132222108Spjd}
133222108Spjd
134216721Spjdstatic int
135216721Spjdnode_names(char **namesp)
136216721Spjd{
137216721Spjd	static char names[MAXHOSTNAMELEN * 3];
138216721Spjd	char buf[MAXHOSTNAMELEN];
139216721Spjd	char *pos;
140216721Spjd	size_t bufsize;
141216721Spjd
142216721Spjd	if (gethostname(buf, sizeof(buf)) < 0) {
143216721Spjd		pjdlog_errno(LOG_ERR, "gethostname() failed");
144216721Spjd		return (-1);
145216721Spjd	}
146216721Spjd
147216721Spjd	/* First component of the host name. */
148216721Spjd	pos = strchr(buf, '.');
149216721Spjd	if (pos != NULL && pos != buf) {
150216721Spjd		(void)strlcpy(names, buf, MIN((size_t)(pos - buf + 1),
151216721Spjd		    sizeof(names)));
152216721Spjd		(void)strlcat(names, ", ", sizeof(names));
153216721Spjd	}
154216721Spjd
155216721Spjd	/* Full host name. */
156216721Spjd	(void)strlcat(names, buf, sizeof(names));
157216721Spjd	(void)strlcat(names, ", ", sizeof(names));
158216721Spjd
159216721Spjd	/* Host UUID. */
160216721Spjd	bufsize = sizeof(buf);
161216721Spjd	if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) {
162216721Spjd		pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed");
163216721Spjd		return (-1);
164216721Spjd	}
165216721Spjd	(void)strlcat(names, buf, sizeof(names));
166216721Spjd
167216721Spjd	*namesp = names;
168216721Spjd
169216721Spjd	return (0);
170216721Spjd}
171216721Spjd
172204076Spjdvoid
173204076Spjdyyerror(const char *str)
174204076Spjd{
175204076Spjd
176210883Spjd	pjdlog_error("Unable to parse configuration file at line %d near '%s': %s",
177204076Spjd	    lineno, yytext, str);
178204076Spjd}
179204076Spjd
180204076Spjdstruct hastd_config *
181210883Spjdyy_config_parse(const char *config, bool exitonerror)
182204076Spjd{
183204076Spjd	int ret;
184204076Spjd
185204076Spjd	curres = NULL;
186204076Spjd	mynode = false;
187210883Spjd	depth = 0;
188210883Spjd	lineno = 0;
189204076Spjd
190207371Spjd	depth0_timeout = HAST_TIMEOUT;
191220573Spjd	depth0_replication = HAST_REPLICATION_FULLSYNC;
192219351Spjd	depth0_checksum = HAST_CHECKSUM_NONE;
193219354Spjd	depth0_compression = HAST_COMPRESSION_HOLE;
194204076Spjd	strlcpy(depth0_control, HAST_CONTROL, sizeof(depth0_control));
195222108Spjd	TAILQ_INIT(&depth0_listen);
196222108Spjd	strlcpy(depth0_listen_ipv4, HASTD_LISTEN_IPV4,
197222108Spjd	    sizeof(depth0_listen_ipv4));
198222108Spjd	strlcpy(depth0_listen_ipv6, HASTD_LISTEN_IPV6,
199222108Spjd	    sizeof(depth0_listen_ipv6));
200211886Spjd	depth0_exec[0] = '\0';
201204076Spjd
202210883Spjd	lconfig = calloc(1, sizeof(*lconfig));
203210883Spjd	if (lconfig == NULL) {
204210883Spjd		pjdlog_error("Unable to allocate memory for configuration.");
205210883Spjd		if (exitonerror)
206210883Spjd			exit(EX_TEMPFAIL);
207210883Spjd		return (NULL);
208210883Spjd	}
209204076Spjd
210222108Spjd	TAILQ_INIT(&lconfig->hc_listen);
211210883Spjd	TAILQ_INIT(&lconfig->hc_resources);
212210883Spjd
213204076Spjd	yyin = fopen(config, "r");
214210883Spjd	if (yyin == NULL) {
215210883Spjd		pjdlog_errno(LOG_ERR, "Unable to open configuration file %s",
216210883Spjd		    config);
217210883Spjd		yy_config_free(lconfig);
218210883Spjd		if (exitonerror)
219210883Spjd			exit(EX_OSFILE);
220210883Spjd		return (NULL);
221210883Spjd	}
222210883Spjd	yyrestart(yyin);
223204076Spjd	ret = yyparse();
224204076Spjd	fclose(yyin);
225204076Spjd	if (ret != 0) {
226210883Spjd		yy_config_free(lconfig);
227210883Spjd		if (exitonerror)
228210883Spjd			exit(EX_CONFIG);
229210883Spjd		return (NULL);
230204076Spjd	}
231204076Spjd
232204076Spjd	/*
233204076Spjd	 * Let's see if everything is set up.
234204076Spjd	 */
235210883Spjd	if (lconfig->hc_controladdr[0] == '\0') {
236210883Spjd		strlcpy(lconfig->hc_controladdr, depth0_control,
237210883Spjd		    sizeof(lconfig->hc_controladdr));
238204076Spjd	}
239222108Spjd	if (!TAILQ_EMPTY(&depth0_listen))
240222108Spjd		TAILQ_CONCAT(&lconfig->hc_listen, &depth0_listen, hl_next);
241222108Spjd	if (TAILQ_EMPTY(&lconfig->hc_listen)) {
242222108Spjd		struct hastd_listen *lst;
243222108Spjd
244222108Spjd		if (family_supported(AF_INET)) {
245222108Spjd			lst = calloc(1, sizeof(*lst));
246222108Spjd			if (lst == NULL) {
247222108Spjd				pjdlog_error("Unable to allocate memory for listen address.");
248222108Spjd				yy_config_free(lconfig);
249222108Spjd				if (exitonerror)
250222108Spjd					exit(EX_TEMPFAIL);
251222108Spjd				return (NULL);
252222108Spjd			}
253222108Spjd			(void)strlcpy(lst->hl_addr, depth0_listen_ipv4,
254222108Spjd			    sizeof(lst->hl_addr));
255222108Spjd			TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next);
256222108Spjd		} else {
257222108Spjd			pjdlog_debug(1,
258222108Spjd			    "No IPv4 support in the kernel, not listening on IPv4 address.");
259222108Spjd		}
260222108Spjd#ifdef notyet
261222108Spjd		if (family_supported(AF_INET6)) {
262222108Spjd			lst = calloc(1, sizeof(*lst));
263222108Spjd			if (lst == NULL) {
264222108Spjd				pjdlog_error("Unable to allocate memory for listen address.");
265222108Spjd				yy_config_free(lconfig);
266222108Spjd				if (exitonerror)
267222108Spjd					exit(EX_TEMPFAIL);
268222108Spjd				return (NULL);
269222108Spjd			}
270222108Spjd			(void)strlcpy(lst->hl_addr, depth0_listen_ipv6,
271222108Spjd			    sizeof(lst->hl_addr));
272222108Spjd			TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next);
273222108Spjd		} else {
274222108Spjd			pjdlog_debug(1,
275222108Spjd			    "No IPv6 support in the kernel, not listening on IPv6 address.");
276222108Spjd		}
277222108Spjd#endif
278222108Spjd		if (TAILQ_EMPTY(&lconfig->hc_listen)) {
279222108Spjd			pjdlog_error("No address to listen on.");
280222108Spjd			yy_config_free(lconfig);
281222108Spjd			if (exitonerror)
282222108Spjd				exit(EX_TEMPFAIL);
283222108Spjd			return (NULL);
284222108Spjd		}
285204076Spjd	}
286210883Spjd	TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) {
287204076Spjd		assert(curres->hr_provname[0] != '\0');
288204076Spjd		assert(curres->hr_localpath[0] != '\0');
289204076Spjd		assert(curres->hr_remoteaddr[0] != '\0');
290204076Spjd
291204076Spjd		if (curres->hr_replication == -1) {
292204076Spjd			/*
293204076Spjd			 * Replication is not set at resource-level.
294204076Spjd			 * Use global or default setting.
295204076Spjd			 */
296204076Spjd			curres->hr_replication = depth0_replication;
297204076Spjd		}
298220573Spjd		if (curres->hr_replication == HAST_REPLICATION_MEMSYNC ||
299220573Spjd		    curres->hr_replication == HAST_REPLICATION_ASYNC) {
300220573Spjd			pjdlog_warning("Replication mode \"%s\" is not implemented, falling back to \"%s\".",
301220573Spjd			    curres->hr_replication == HAST_REPLICATION_MEMSYNC ?
302220573Spjd			    "memsync" : "async", "fullsync");
303220573Spjd			curres->hr_replication = HAST_REPLICATION_FULLSYNC;
304220573Spjd		}
305219351Spjd		if (curres->hr_checksum == -1) {
306219351Spjd			/*
307219351Spjd			 * Checksum is not set at resource-level.
308219351Spjd			 * Use global or default setting.
309219351Spjd			 */
310219351Spjd			curres->hr_checksum = depth0_checksum;
311219351Spjd		}
312219354Spjd		if (curres->hr_compression == -1) {
313219354Spjd			/*
314219354Spjd			 * Compression is not set at resource-level.
315219354Spjd			 * Use global or default setting.
316219354Spjd			 */
317219354Spjd			curres->hr_compression = depth0_compression;
318219354Spjd		}
319207371Spjd		if (curres->hr_timeout == -1) {
320207371Spjd			/*
321207371Spjd			 * Timeout is not set at resource-level.
322207371Spjd			 * Use global or default setting.
323207371Spjd			 */
324207371Spjd			curres->hr_timeout = depth0_timeout;
325207371Spjd		}
326211886Spjd		if (curres->hr_exec[0] == '\0') {
327211886Spjd			/*
328211886Spjd			 * Exec is not set at resource-level.
329211886Spjd			 * Use global or default setting.
330211886Spjd			 */
331211886Spjd			strlcpy(curres->hr_exec, depth0_exec,
332211886Spjd			    sizeof(curres->hr_exec));
333211886Spjd		}
334204076Spjd	}
335204076Spjd
336210883Spjd	return (lconfig);
337204076Spjd}
338204076Spjd
339204076Spjdvoid
340204076Spjdyy_config_free(struct hastd_config *config)
341204076Spjd{
342222108Spjd	struct hastd_listen *lst;
343204076Spjd	struct hast_resource *res;
344204076Spjd
345222108Spjd	while ((lst = TAILQ_FIRST(&depth0_listen)) != NULL) {
346222108Spjd		TAILQ_REMOVE(&depth0_listen, lst, hl_next);
347222108Spjd		free(lst);
348222108Spjd	}
349222108Spjd	while ((lst = TAILQ_FIRST(&config->hc_listen)) != NULL) {
350222108Spjd		TAILQ_REMOVE(&config->hc_listen, lst, hl_next);
351222108Spjd		free(lst);
352222108Spjd	}
353204076Spjd	while ((res = TAILQ_FIRST(&config->hc_resources)) != NULL) {
354204076Spjd		TAILQ_REMOVE(&config->hc_resources, res, hr_next);
355204076Spjd		free(res);
356204076Spjd	}
357210883Spjd	free(config);
358204076Spjd}
359204076Spjd%}
360204076Spjd
361219354Spjd%token CONTROL LISTEN PORT REPLICATION CHECKSUM COMPRESSION
362219818Spjd%token TIMEOUT EXEC EXTENTSIZE RESOURCE NAME LOCAL REMOTE SOURCE ON
363219354Spjd%token FULLSYNC MEMSYNC ASYNC NONE CRC32 SHA256 HOLE LZF
364204076Spjd%token NUM STR OB CB
365204076Spjd
366221643Spjd%type <str> remote_str
367204076Spjd%type <num> replication_type
368219351Spjd%type <num> checksum_type
369219354Spjd%type <num> compression_type
370204076Spjd
371204076Spjd%union
372204076Spjd{
373204076Spjd	int num;
374204076Spjd	char *str;
375204076Spjd}
376204076Spjd
377204076Spjd%token <num> NUM
378204076Spjd%token <str> STR
379204076Spjd
380204076Spjd%%
381204076Spjd
382204076Spjdstatements:
383204076Spjd	|
384204076Spjd	statements statement
385204076Spjd	;
386204076Spjd
387204076Spjdstatement:
388204076Spjd	control_statement
389204076Spjd	|
390204076Spjd	listen_statement
391204076Spjd	|
392204076Spjd	replication_statement
393204076Spjd	|
394219351Spjd	checksum_statement
395219351Spjd	|
396219354Spjd	compression_statement
397219354Spjd	|
398207371Spjd	timeout_statement
399207371Spjd	|
400211886Spjd	exec_statement
401211886Spjd	|
402204076Spjd	node_statement
403204076Spjd	|
404204076Spjd	resource_statement
405204076Spjd	;
406204076Spjd
407204076Spjdcontrol_statement:	CONTROL STR
408204076Spjd	{
409204076Spjd		switch (depth) {
410204076Spjd		case 0:
411204076Spjd			if (strlcpy(depth0_control, $2,
412204076Spjd			    sizeof(depth0_control)) >=
413204076Spjd			    sizeof(depth0_control)) {
414210883Spjd				pjdlog_error("control argument is too long.");
415214274Spjd				free($2);
416210883Spjd				return (1);
417204076Spjd			}
418204076Spjd			break;
419204076Spjd		case 1:
420211883Spjd			if (!mynode)
421211883Spjd				break;
422211883Spjd			if (strlcpy(lconfig->hc_controladdr, $2,
423211883Spjd			    sizeof(lconfig->hc_controladdr)) >=
424211883Spjd			    sizeof(lconfig->hc_controladdr)) {
425211883Spjd				pjdlog_error("control argument is too long.");
426214274Spjd				free($2);
427211883Spjd				return (1);
428204076Spjd			}
429204076Spjd			break;
430204076Spjd		default:
431204076Spjd			assert(!"control at wrong depth level");
432204076Spjd		}
433214274Spjd		free($2);
434204076Spjd	}
435204076Spjd	;
436204076Spjd
437204076Spjdlisten_statement:	LISTEN STR
438204076Spjd	{
439222108Spjd		struct hastd_listen *lst;
440222108Spjd
441222108Spjd		lst = calloc(1, sizeof(*lst));
442222108Spjd		if (lst == NULL) {
443222108Spjd			pjdlog_error("Unable to allocate memory for listen address.");
444222108Spjd			free($2);
445222108Spjd			return (1);
446222108Spjd		}
447222108Spjd		if (strlcpy(lst->hl_addr, $2, sizeof(lst->hl_addr)) >=
448222108Spjd		    sizeof(lst->hl_addr)) {
449222108Spjd			pjdlog_error("listen argument is too long.");
450222108Spjd			free($2);
451222108Spjd			free(lst);
452222108Spjd			return (1);
453222108Spjd		}
454204076Spjd		switch (depth) {
455204076Spjd		case 0:
456222108Spjd			TAILQ_INSERT_TAIL(&depth0_listen, lst, hl_next);
457204076Spjd			break;
458204076Spjd		case 1:
459222108Spjd			if (mynode)
460222108Spjd				TAILQ_INSERT_TAIL(&depth0_listen, lst, hl_next);
461222108Spjd			else
462222108Spjd				free(lst);
463204076Spjd			break;
464204076Spjd		default:
465204076Spjd			assert(!"listen at wrong depth level");
466204076Spjd		}
467214274Spjd		free($2);
468204076Spjd	}
469204076Spjd	;
470204076Spjd
471204076Spjdreplication_statement:	REPLICATION replication_type
472204076Spjd	{
473204076Spjd		switch (depth) {
474204076Spjd		case 0:
475204076Spjd			depth0_replication = $2;
476204076Spjd			break;
477204076Spjd		case 1:
478204076Spjd			if (curres != NULL)
479204076Spjd				curres->hr_replication = $2;
480204076Spjd			break;
481204076Spjd		default:
482204076Spjd			assert(!"replication at wrong depth level");
483204076Spjd		}
484204076Spjd	}
485204076Spjd	;
486204076Spjd
487204076Spjdreplication_type:
488204076Spjd	FULLSYNC	{ $$ = HAST_REPLICATION_FULLSYNC; }
489204076Spjd	|
490204076Spjd	MEMSYNC		{ $$ = HAST_REPLICATION_MEMSYNC; }
491204076Spjd	|
492204076Spjd	ASYNC		{ $$ = HAST_REPLICATION_ASYNC; }
493204076Spjd	;
494204076Spjd
495219351Spjdchecksum_statement:	CHECKSUM checksum_type
496219351Spjd	{
497219351Spjd		switch (depth) {
498219351Spjd		case 0:
499219351Spjd			depth0_checksum = $2;
500219351Spjd			break;
501219351Spjd		case 1:
502219351Spjd			if (curres != NULL)
503219351Spjd				curres->hr_checksum = $2;
504219351Spjd			break;
505219351Spjd		default:
506219351Spjd			assert(!"checksum at wrong depth level");
507219351Spjd		}
508219351Spjd	}
509219351Spjd	;
510219351Spjd
511219351Spjdchecksum_type:
512219351Spjd	NONE		{ $$ = HAST_CHECKSUM_NONE; }
513219351Spjd	|
514219351Spjd	CRC32		{ $$ = HAST_CHECKSUM_CRC32; }
515219351Spjd	|
516219351Spjd	SHA256		{ $$ = HAST_CHECKSUM_SHA256; }
517219351Spjd	;
518219351Spjd
519219354Spjdcompression_statement:	COMPRESSION compression_type
520219354Spjd	{
521219354Spjd		switch (depth) {
522219354Spjd		case 0:
523219354Spjd			depth0_compression = $2;
524219354Spjd			break;
525219354Spjd		case 1:
526219354Spjd			if (curres != NULL)
527219354Spjd				curres->hr_compression = $2;
528219354Spjd			break;
529219354Spjd		default:
530219354Spjd			assert(!"compression at wrong depth level");
531219354Spjd		}
532219354Spjd	}
533219354Spjd	;
534219354Spjd
535219354Spjdcompression_type:
536219354Spjd	NONE		{ $$ = HAST_COMPRESSION_NONE; }
537219354Spjd	|
538219354Spjd	HOLE		{ $$ = HAST_COMPRESSION_HOLE; }
539219354Spjd	|
540219354Spjd	LZF		{ $$ = HAST_COMPRESSION_LZF; }
541219354Spjd	;
542219354Spjd
543207371Spjdtimeout_statement:	TIMEOUT NUM
544207371Spjd	{
545220889Spjd		if ($2 <= 0) {
546220889Spjd			pjdlog_error("Negative or zero timeout.");
547220889Spjd			return (1);
548220889Spjd		}
549207371Spjd		switch (depth) {
550207371Spjd		case 0:
551207371Spjd			depth0_timeout = $2;
552207371Spjd			break;
553207371Spjd		case 1:
554207371Spjd			if (curres != NULL)
555207371Spjd				curres->hr_timeout = $2;
556207371Spjd			break;
557207371Spjd		default:
558207371Spjd			assert(!"timeout at wrong depth level");
559207371Spjd		}
560207371Spjd	}
561207371Spjd	;
562207371Spjd
563211886Spjdexec_statement:		EXEC STR
564211886Spjd	{
565211886Spjd		switch (depth) {
566211886Spjd		case 0:
567211886Spjd			if (strlcpy(depth0_exec, $2, sizeof(depth0_exec)) >=
568211886Spjd			    sizeof(depth0_exec)) {
569211886Spjd				pjdlog_error("Exec path is too long.");
570214274Spjd				free($2);
571211886Spjd				return (1);
572211886Spjd			}
573211886Spjd			break;
574211886Spjd		case 1:
575211886Spjd			if (curres == NULL)
576211886Spjd				break;
577211886Spjd			if (strlcpy(curres->hr_exec, $2,
578211886Spjd			    sizeof(curres->hr_exec)) >=
579211886Spjd			    sizeof(curres->hr_exec)) {
580211886Spjd				pjdlog_error("Exec path is too long.");
581214274Spjd				free($2);
582211886Spjd				return (1);
583211886Spjd			}
584211886Spjd			break;
585211886Spjd		default:
586211886Spjd			assert(!"exec at wrong depth level");
587211886Spjd		}
588214274Spjd		free($2);
589211886Spjd	}
590211886Spjd	;
591211886Spjd
592204076Spjdnode_statement:		ON node_start OB node_entries CB
593204076Spjd	{
594204076Spjd		mynode = false;
595204076Spjd	}
596204076Spjd	;
597204076Spjd
598204076Spjdnode_start:	STR
599204076Spjd	{
600210883Spjd		switch (isitme($1)) {
601210883Spjd		case -1:
602214274Spjd			free($1);
603210883Spjd			return (1);
604210883Spjd		case 0:
605210883Spjd			break;
606210883Spjd		case 1:
607204076Spjd			mynode = true;
608210883Spjd			break;
609210883Spjd		default:
610210883Spjd			assert(!"invalid isitme() return value");
611210883Spjd		}
612214274Spjd		free($1);
613204076Spjd	}
614204076Spjd	;
615204076Spjd
616204076Spjdnode_entries:
617204076Spjd	|
618204076Spjd	node_entries node_entry
619204076Spjd	;
620204076Spjd
621204076Spjdnode_entry:
622204076Spjd	control_statement
623204076Spjd	|
624204076Spjd	listen_statement
625204076Spjd	;
626204076Spjd
627204076Spjdresource_statement:	RESOURCE resource_start OB resource_entries CB
628204076Spjd	{
629204076Spjd		if (curres != NULL) {
630204076Spjd			/*
631216721Spjd			 * There must be section for this node, at least with
632216721Spjd			 * remote address configuration.
633216721Spjd			 */
634216721Spjd			if (!hadmynode) {
635216721Spjd				char *names;
636216721Spjd
637216721Spjd				if (node_names(&names) != 0)
638216721Spjd					return (1);
639216721Spjd				pjdlog_error("No resource %s configuration for this node (acceptable node names: %s).",
640216721Spjd				    curres->hr_name, names);
641216721Spjd				return (1);
642216721Spjd			}
643216721Spjd
644216721Spjd			/*
645204076Spjd			 * Let's see there are some resource-level settings
646204076Spjd			 * that we can use for node-level settings.
647204076Spjd			 */
648204076Spjd			if (curres->hr_provname[0] == '\0' &&
649204076Spjd			    depth1_provname[0] != '\0') {
650204076Spjd				/*
651204076Spjd				 * Provider name is not set at node-level,
652204076Spjd				 * but is set at resource-level, use it.
653204076Spjd				 */
654204076Spjd				strlcpy(curres->hr_provname, depth1_provname,
655204076Spjd				    sizeof(curres->hr_provname));
656204076Spjd			}
657204076Spjd			if (curres->hr_localpath[0] == '\0' &&
658204076Spjd			    depth1_localpath[0] != '\0') {
659204076Spjd				/*
660204076Spjd				 * Path to local provider is not set at
661204076Spjd				 * node-level, but is set at resource-level,
662204076Spjd				 * use it.
663204076Spjd				 */
664204076Spjd				strlcpy(curres->hr_localpath, depth1_localpath,
665204076Spjd				    sizeof(curres->hr_localpath));
666204076Spjd			}
667204076Spjd
668204076Spjd			/*
669204076Spjd			 * If provider name is not given, use resource name
670204076Spjd			 * as provider name.
671204076Spjd			 */
672204076Spjd			if (curres->hr_provname[0] == '\0') {
673204076Spjd				strlcpy(curres->hr_provname, curres->hr_name,
674204076Spjd				    sizeof(curres->hr_provname));
675204076Spjd			}
676204076Spjd
677204076Spjd			/*
678204076Spjd			 * Remote address has to be configured at this point.
679204076Spjd			 */
680204076Spjd			if (curres->hr_remoteaddr[0] == '\0') {
681210883Spjd				pjdlog_error("Remote address not configured for resource %s.",
682204076Spjd				    curres->hr_name);
683210883Spjd				return (1);
684204076Spjd			}
685204076Spjd			/*
686204076Spjd			 * Path to local provider has to be configured at this
687204076Spjd			 * point.
688204076Spjd			 */
689204076Spjd			if (curres->hr_localpath[0] == '\0') {
690210883Spjd				pjdlog_error("Path to local component not configured for resource %s.",
691204076Spjd				    curres->hr_name);
692210883Spjd				return (1);
693204076Spjd			}
694204076Spjd
695204076Spjd			/* Put it onto resource list. */
696210883Spjd			TAILQ_INSERT_TAIL(&lconfig->hc_resources, curres, hr_next);
697204076Spjd			curres = NULL;
698204076Spjd		}
699204076Spjd	}
700204076Spjd	;
701204076Spjd
702204076Spjdresource_start:	STR
703204076Spjd	{
704216722Spjd		/* Check if there is no duplicate entry. */
705216722Spjd		TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) {
706216722Spjd			if (strcmp(curres->hr_name, $1) == 0) {
707216722Spjd				pjdlog_error("Resource %s configured more than once.",
708216722Spjd				    curres->hr_name);
709216722Spjd				free($1);
710216722Spjd				return (1);
711216722Spjd			}
712216722Spjd		}
713216722Spjd
714204076Spjd		/*
715204076Spjd		 * Clear those, so we can tell if they were set at
716204076Spjd		 * resource-level or not.
717204076Spjd		 */
718204076Spjd		depth1_provname[0] = '\0';
719204076Spjd		depth1_localpath[0] = '\0';
720216721Spjd		hadmynode = false;
721204076Spjd
722204076Spjd		curres = calloc(1, sizeof(*curres));
723204076Spjd		if (curres == NULL) {
724210883Spjd			pjdlog_error("Unable to allocate memory for resource.");
725214274Spjd			free($1);
726210883Spjd			return (1);
727204076Spjd		}
728204076Spjd		if (strlcpy(curres->hr_name, $1,
729204076Spjd		    sizeof(curres->hr_name)) >=
730204076Spjd		    sizeof(curres->hr_name)) {
731210883Spjd			pjdlog_error("Resource name is too long.");
732214274Spjd			free($1);
733210883Spjd			return (1);
734204076Spjd		}
735214274Spjd		free($1);
736204076Spjd		curres->hr_role = HAST_ROLE_INIT;
737204076Spjd		curres->hr_previous_role = HAST_ROLE_INIT;
738204076Spjd		curres->hr_replication = -1;
739219351Spjd		curres->hr_checksum = -1;
740219354Spjd		curres->hr_compression = -1;
741207371Spjd		curres->hr_timeout = -1;
742211886Spjd		curres->hr_exec[0] = '\0';
743204076Spjd		curres->hr_provname[0] = '\0';
744204076Spjd		curres->hr_localpath[0] = '\0';
745204076Spjd		curres->hr_localfd = -1;
746204076Spjd		curres->hr_remoteaddr[0] = '\0';
747219818Spjd		curres->hr_sourceaddr[0] = '\0';
748204076Spjd		curres->hr_ggateunit = -1;
749204076Spjd	}
750204076Spjd	;
751204076Spjd
752204076Spjdresource_entries:
753204076Spjd	|
754204076Spjd	resource_entries resource_entry
755204076Spjd	;
756204076Spjd
757204076Spjdresource_entry:
758204076Spjd	replication_statement
759204076Spjd	|
760219351Spjd	checksum_statement
761219351Spjd	|
762219354Spjd	compression_statement
763219354Spjd	|
764207371Spjd	timeout_statement
765207371Spjd	|
766211886Spjd	exec_statement
767211886Spjd	|
768204076Spjd	name_statement
769204076Spjd	|
770204076Spjd	local_statement
771204076Spjd	|
772204076Spjd	resource_node_statement
773204076Spjd	;
774204076Spjd
775204076Spjdname_statement:		NAME STR
776204076Spjd	{
777204076Spjd		switch (depth) {
778204076Spjd		case 1:
779204076Spjd			if (strlcpy(depth1_provname, $2,
780204076Spjd			    sizeof(depth1_provname)) >=
781204076Spjd			    sizeof(depth1_provname)) {
782210883Spjd				pjdlog_error("name argument is too long.");
783214274Spjd				free($2);
784210883Spjd				return (1);
785204076Spjd			}
786204076Spjd			break;
787204076Spjd		case 2:
788211883Spjd			if (!mynode)
789211883Spjd				break;
790211883Spjd			assert(curres != NULL);
791211883Spjd			if (strlcpy(curres->hr_provname, $2,
792211883Spjd			    sizeof(curres->hr_provname)) >=
793211883Spjd			    sizeof(curres->hr_provname)) {
794211883Spjd				pjdlog_error("name argument is too long.");
795214274Spjd				free($2);
796211883Spjd				return (1);
797204076Spjd			}
798204076Spjd			break;
799204076Spjd		default:
800204076Spjd			assert(!"name at wrong depth level");
801204076Spjd		}
802214274Spjd		free($2);
803204076Spjd	}
804204076Spjd	;
805204076Spjd
806204076Spjdlocal_statement:	LOCAL STR
807204076Spjd	{
808204076Spjd		switch (depth) {
809204076Spjd		case 1:
810204076Spjd			if (strlcpy(depth1_localpath, $2,
811204076Spjd			    sizeof(depth1_localpath)) >=
812204076Spjd			    sizeof(depth1_localpath)) {
813210883Spjd				pjdlog_error("local argument is too long.");
814214274Spjd				free($2);
815210883Spjd				return (1);
816204076Spjd			}
817204076Spjd			break;
818204076Spjd		case 2:
819211883Spjd			if (!mynode)
820211883Spjd				break;
821211883Spjd			assert(curres != NULL);
822211883Spjd			if (strlcpy(curres->hr_localpath, $2,
823211883Spjd			    sizeof(curres->hr_localpath)) >=
824211883Spjd			    sizeof(curres->hr_localpath)) {
825211883Spjd				pjdlog_error("local argument is too long.");
826214274Spjd				free($2);
827211883Spjd				return (1);
828204076Spjd			}
829204076Spjd			break;
830204076Spjd		default:
831204076Spjd			assert(!"local at wrong depth level");
832204076Spjd		}
833214274Spjd		free($2);
834204076Spjd	}
835204076Spjd	;
836204076Spjd
837204076Spjdresource_node_statement:ON resource_node_start OB resource_node_entries CB
838204076Spjd	{
839204076Spjd		mynode = false;
840204076Spjd	}
841204076Spjd	;
842204076Spjd
843204076Spjdresource_node_start:	STR
844204076Spjd	{
845210883Spjd		if (curres != NULL) {
846210883Spjd			switch (isitme($1)) {
847210883Spjd			case -1:
848214274Spjd				free($1);
849210883Spjd				return (1);
850210883Spjd			case 0:
851210883Spjd				break;
852210883Spjd			case 1:
853216721Spjd				mynode = hadmynode = true;
854210883Spjd				break;
855210883Spjd			default:
856210883Spjd				assert(!"invalid isitme() return value");
857210883Spjd			}
858210883Spjd		}
859214274Spjd		free($1);
860204076Spjd	}
861204076Spjd	;
862204076Spjd
863204076Spjdresource_node_entries:
864204076Spjd	|
865204076Spjd	resource_node_entries resource_node_entry
866204076Spjd	;
867204076Spjd
868204076Spjdresource_node_entry:
869204076Spjd	name_statement
870204076Spjd	|
871204076Spjd	local_statement
872204076Spjd	|
873204076Spjd	remote_statement
874219818Spjd	|
875219818Spjd	source_statement
876204076Spjd	;
877204076Spjd
878221643Spjdremote_statement:	REMOTE remote_str
879204076Spjd	{
880204076Spjd		assert(depth == 2);
881204076Spjd		if (mynode) {
882204076Spjd			assert(curres != NULL);
883204076Spjd			if (strlcpy(curres->hr_remoteaddr, $2,
884204076Spjd			    sizeof(curres->hr_remoteaddr)) >=
885204076Spjd			    sizeof(curres->hr_remoteaddr)) {
886210883Spjd				pjdlog_error("remote argument is too long.");
887214274Spjd				free($2);
888210883Spjd				return (1);
889204076Spjd			}
890204076Spjd		}
891214274Spjd		free($2);
892204076Spjd	}
893204076Spjd	;
894219818Spjd
895221643Spjdremote_str:
896221643Spjd	NONE		{ $$ = strdup("none"); }
897221643Spjd	|
898221643Spjd	STR		{ }
899221643Spjd	;
900221643Spjd
901219818Spjdsource_statement:	SOURCE STR
902219818Spjd	{
903219818Spjd		assert(depth == 2);
904219818Spjd		if (mynode) {
905219818Spjd			assert(curres != NULL);
906219818Spjd			if (strlcpy(curres->hr_sourceaddr, $2,
907219818Spjd			    sizeof(curres->hr_sourceaddr)) >=
908219818Spjd			    sizeof(curres->hr_sourceaddr)) {
909219818Spjd				pjdlog_error("source argument is too long.");
910219818Spjd				free($2);
911219818Spjd				return (1);
912219818Spjd			}
913219818Spjd		}
914219818Spjd		free($2);
915219818Spjd	}
916219818Spjd	;
917