parse.y revision 219818
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 219818 2011-03-21 08:54:59Z pjd $
32204076Spjd */
33204076Spjd
34204076Spjd#include <sys/param.h>	/* MAXHOSTNAMELEN */
35204076Spjd#include <sys/queue.h>
36204076Spjd#include <sys/sysctl.h>
37204076Spjd
38204076Spjd#include <arpa/inet.h>
39204076Spjd
40204076Spjd#include <assert.h>
41204076Spjd#include <err.h>
42204076Spjd#include <stdio.h>
43204076Spjd#include <string.h>
44204076Spjd#include <sysexits.h>
45204076Spjd#include <unistd.h>
46204076Spjd
47210883Spjd#include <pjdlog.h>
48210883Spjd
49204076Spjd#include "hast.h"
50204076Spjd
51204076Spjdextern int depth;
52204076Spjdextern int lineno;
53204076Spjd
54204076Spjdextern FILE *yyin;
55204076Spjdextern char *yytext;
56204076Spjd
57210883Spjdstatic struct hastd_config *lconfig;
58204076Spjdstatic struct hast_resource *curres;
59216721Spjdstatic bool mynode, hadmynode;
60204076Spjd
61204076Spjdstatic char depth0_control[HAST_ADDRSIZE];
62204076Spjdstatic char depth0_listen[HAST_ADDRSIZE];
63204076Spjdstatic int depth0_replication;
64219351Spjdstatic int depth0_checksum;
65219354Spjdstatic int depth0_compression;
66207371Spjdstatic int depth0_timeout;
67211886Spjdstatic char depth0_exec[PATH_MAX];
68204076Spjd
69204076Spjdstatic char depth1_provname[PATH_MAX];
70204076Spjdstatic char depth1_localpath[PATH_MAX];
71204076Spjd
72210883Spjdextern void yyrestart(FILE *);
73210883Spjd
74210883Spjdstatic int
75204076Spjdisitme(const char *name)
76204076Spjd{
77204076Spjd	char buf[MAXHOSTNAMELEN];
78204076Spjd	char *pos;
79204076Spjd	size_t bufsize;
80204076Spjd
81204076Spjd	/*
82204076Spjd	 * First check if the give name matches our full hostname.
83204076Spjd	 */
84210883Spjd	if (gethostname(buf, sizeof(buf)) < 0) {
85210883Spjd		pjdlog_errno(LOG_ERR, "gethostname() failed");
86210883Spjd		return (-1);
87210883Spjd	}
88204076Spjd	if (strcmp(buf, name) == 0)
89210883Spjd		return (1);
90204076Spjd
91204076Spjd	/*
92204076Spjd	 * Now check if it matches first part of the host name.
93204076Spjd	 */
94204076Spjd	pos = strchr(buf, '.');
95204076Spjd	if (pos != NULL && pos != buf && strncmp(buf, name, pos - buf) == 0)
96210883Spjd		return (1);
97204076Spjd
98204076Spjd	/*
99204076Spjd	 * At the end check if name is equal to our host's UUID.
100204076Spjd	 */
101204076Spjd	bufsize = sizeof(buf);
102210883Spjd	if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) {
103210883Spjd		pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed");
104210883Spjd		return (-1);
105210883Spjd	}
106204076Spjd	if (strcasecmp(buf, name) == 0)
107210883Spjd		return (1);
108204076Spjd
109204076Spjd	/*
110204076Spjd	 * Looks like this isn't about us.
111204076Spjd	 */
112210883Spjd	return (0);
113204076Spjd}
114204076Spjd
115216721Spjdstatic int
116216721Spjdnode_names(char **namesp)
117216721Spjd{
118216721Spjd	static char names[MAXHOSTNAMELEN * 3];
119216721Spjd	char buf[MAXHOSTNAMELEN];
120216721Spjd	char *pos;
121216721Spjd	size_t bufsize;
122216721Spjd
123216721Spjd	if (gethostname(buf, sizeof(buf)) < 0) {
124216721Spjd		pjdlog_errno(LOG_ERR, "gethostname() failed");
125216721Spjd		return (-1);
126216721Spjd	}
127216721Spjd
128216721Spjd	/* First component of the host name. */
129216721Spjd	pos = strchr(buf, '.');
130216721Spjd	if (pos != NULL && pos != buf) {
131216721Spjd		(void)strlcpy(names, buf, MIN((size_t)(pos - buf + 1),
132216721Spjd		    sizeof(names)));
133216721Spjd		(void)strlcat(names, ", ", sizeof(names));
134216721Spjd	}
135216721Spjd
136216721Spjd	/* Full host name. */
137216721Spjd	(void)strlcat(names, buf, sizeof(names));
138216721Spjd	(void)strlcat(names, ", ", sizeof(names));
139216721Spjd
140216721Spjd	/* Host UUID. */
141216721Spjd	bufsize = sizeof(buf);
142216721Spjd	if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) {
143216721Spjd		pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed");
144216721Spjd		return (-1);
145216721Spjd	}
146216721Spjd	(void)strlcat(names, buf, sizeof(names));
147216721Spjd
148216721Spjd	*namesp = names;
149216721Spjd
150216721Spjd	return (0);
151216721Spjd}
152216721Spjd
153204076Spjdvoid
154204076Spjdyyerror(const char *str)
155204076Spjd{
156204076Spjd
157210883Spjd	pjdlog_error("Unable to parse configuration file at line %d near '%s': %s",
158204076Spjd	    lineno, yytext, str);
159204076Spjd}
160204076Spjd
161204076Spjdstruct hastd_config *
162210883Spjdyy_config_parse(const char *config, bool exitonerror)
163204076Spjd{
164204076Spjd	int ret;
165204076Spjd
166204076Spjd	curres = NULL;
167204076Spjd	mynode = false;
168210883Spjd	depth = 0;
169210883Spjd	lineno = 0;
170204076Spjd
171207371Spjd	depth0_timeout = HAST_TIMEOUT;
172204076Spjd	depth0_replication = HAST_REPLICATION_MEMSYNC;
173219351Spjd	depth0_checksum = HAST_CHECKSUM_NONE;
174219354Spjd	depth0_compression = HAST_COMPRESSION_HOLE;
175204076Spjd	strlcpy(depth0_control, HAST_CONTROL, sizeof(depth0_control));
176204076Spjd	strlcpy(depth0_listen, HASTD_LISTEN, sizeof(depth0_listen));
177211886Spjd	depth0_exec[0] = '\0';
178204076Spjd
179210883Spjd	lconfig = calloc(1, sizeof(*lconfig));
180210883Spjd	if (lconfig == NULL) {
181210883Spjd		pjdlog_error("Unable to allocate memory for configuration.");
182210883Spjd		if (exitonerror)
183210883Spjd			exit(EX_TEMPFAIL);
184210883Spjd		return (NULL);
185210883Spjd	}
186204076Spjd
187210883Spjd	TAILQ_INIT(&lconfig->hc_resources);
188210883Spjd
189204076Spjd	yyin = fopen(config, "r");
190210883Spjd	if (yyin == NULL) {
191210883Spjd		pjdlog_errno(LOG_ERR, "Unable to open configuration file %s",
192210883Spjd		    config);
193210883Spjd		yy_config_free(lconfig);
194210883Spjd		if (exitonerror)
195210883Spjd			exit(EX_OSFILE);
196210883Spjd		return (NULL);
197210883Spjd	}
198210883Spjd	yyrestart(yyin);
199204076Spjd	ret = yyparse();
200204076Spjd	fclose(yyin);
201204076Spjd	if (ret != 0) {
202210883Spjd		yy_config_free(lconfig);
203210883Spjd		if (exitonerror)
204210883Spjd			exit(EX_CONFIG);
205210883Spjd		return (NULL);
206204076Spjd	}
207204076Spjd
208204076Spjd	/*
209204076Spjd	 * Let's see if everything is set up.
210204076Spjd	 */
211210883Spjd	if (lconfig->hc_controladdr[0] == '\0') {
212210883Spjd		strlcpy(lconfig->hc_controladdr, depth0_control,
213210883Spjd		    sizeof(lconfig->hc_controladdr));
214204076Spjd	}
215210883Spjd	if (lconfig->hc_listenaddr[0] == '\0') {
216210883Spjd		strlcpy(lconfig->hc_listenaddr, depth0_listen,
217210883Spjd		    sizeof(lconfig->hc_listenaddr));
218204076Spjd	}
219210883Spjd	TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) {
220204076Spjd		assert(curres->hr_provname[0] != '\0');
221204076Spjd		assert(curres->hr_localpath[0] != '\0');
222204076Spjd		assert(curres->hr_remoteaddr[0] != '\0');
223204076Spjd
224204076Spjd		if (curres->hr_replication == -1) {
225204076Spjd			/*
226204076Spjd			 * Replication is not set at resource-level.
227204076Spjd			 * Use global or default setting.
228204076Spjd			 */
229204076Spjd			curres->hr_replication = depth0_replication;
230204076Spjd		}
231219351Spjd		if (curres->hr_checksum == -1) {
232219351Spjd			/*
233219351Spjd			 * Checksum is not set at resource-level.
234219351Spjd			 * Use global or default setting.
235219351Spjd			 */
236219351Spjd			curres->hr_checksum = depth0_checksum;
237219351Spjd		}
238219354Spjd		if (curres->hr_compression == -1) {
239219354Spjd			/*
240219354Spjd			 * Compression is not set at resource-level.
241219354Spjd			 * Use global or default setting.
242219354Spjd			 */
243219354Spjd			curres->hr_compression = depth0_compression;
244219354Spjd		}
245207371Spjd		if (curres->hr_timeout == -1) {
246207371Spjd			/*
247207371Spjd			 * Timeout is not set at resource-level.
248207371Spjd			 * Use global or default setting.
249207371Spjd			 */
250207371Spjd			curres->hr_timeout = depth0_timeout;
251207371Spjd		}
252211886Spjd		if (curres->hr_exec[0] == '\0') {
253211886Spjd			/*
254211886Spjd			 * Exec is not set at resource-level.
255211886Spjd			 * Use global or default setting.
256211886Spjd			 */
257211886Spjd			strlcpy(curres->hr_exec, depth0_exec,
258211886Spjd			    sizeof(curres->hr_exec));
259211886Spjd		}
260204076Spjd	}
261204076Spjd
262210883Spjd	return (lconfig);
263204076Spjd}
264204076Spjd
265204076Spjdvoid
266204076Spjdyy_config_free(struct hastd_config *config)
267204076Spjd{
268204076Spjd	struct hast_resource *res;
269204076Spjd
270204076Spjd	while ((res = TAILQ_FIRST(&config->hc_resources)) != NULL) {
271204076Spjd		TAILQ_REMOVE(&config->hc_resources, res, hr_next);
272204076Spjd		free(res);
273204076Spjd	}
274210883Spjd	free(config);
275204076Spjd}
276204076Spjd%}
277204076Spjd
278219354Spjd%token CONTROL LISTEN PORT REPLICATION CHECKSUM COMPRESSION
279219818Spjd%token TIMEOUT EXEC EXTENTSIZE RESOURCE NAME LOCAL REMOTE SOURCE ON
280219354Spjd%token FULLSYNC MEMSYNC ASYNC NONE CRC32 SHA256 HOLE LZF
281204076Spjd%token NUM STR OB CB
282204076Spjd
283204076Spjd%type <num> replication_type
284219351Spjd%type <num> checksum_type
285219354Spjd%type <num> compression_type
286204076Spjd
287204076Spjd%union
288204076Spjd{
289204076Spjd	int num;
290204076Spjd	char *str;
291204076Spjd}
292204076Spjd
293204076Spjd%token <num> NUM
294204076Spjd%token <str> STR
295204076Spjd
296204076Spjd%%
297204076Spjd
298204076Spjdstatements:
299204076Spjd	|
300204076Spjd	statements statement
301204076Spjd	;
302204076Spjd
303204076Spjdstatement:
304204076Spjd	control_statement
305204076Spjd	|
306204076Spjd	listen_statement
307204076Spjd	|
308204076Spjd	replication_statement
309204076Spjd	|
310219351Spjd	checksum_statement
311219351Spjd	|
312219354Spjd	compression_statement
313219354Spjd	|
314207371Spjd	timeout_statement
315207371Spjd	|
316211886Spjd	exec_statement
317211886Spjd	|
318204076Spjd	node_statement
319204076Spjd	|
320204076Spjd	resource_statement
321204076Spjd	;
322204076Spjd
323204076Spjdcontrol_statement:	CONTROL STR
324204076Spjd	{
325204076Spjd		switch (depth) {
326204076Spjd		case 0:
327204076Spjd			if (strlcpy(depth0_control, $2,
328204076Spjd			    sizeof(depth0_control)) >=
329204076Spjd			    sizeof(depth0_control)) {
330210883Spjd				pjdlog_error("control argument is too long.");
331214274Spjd				free($2);
332210883Spjd				return (1);
333204076Spjd			}
334204076Spjd			break;
335204076Spjd		case 1:
336211883Spjd			if (!mynode)
337211883Spjd				break;
338211883Spjd			if (strlcpy(lconfig->hc_controladdr, $2,
339211883Spjd			    sizeof(lconfig->hc_controladdr)) >=
340211883Spjd			    sizeof(lconfig->hc_controladdr)) {
341211883Spjd				pjdlog_error("control argument is too long.");
342214274Spjd				free($2);
343211883Spjd				return (1);
344204076Spjd			}
345204076Spjd			break;
346204076Spjd		default:
347204076Spjd			assert(!"control at wrong depth level");
348204076Spjd		}
349214274Spjd		free($2);
350204076Spjd	}
351204076Spjd	;
352204076Spjd
353204076Spjdlisten_statement:	LISTEN STR
354204076Spjd	{
355204076Spjd		switch (depth) {
356204076Spjd		case 0:
357204076Spjd			if (strlcpy(depth0_listen, $2,
358204076Spjd			    sizeof(depth0_listen)) >=
359204076Spjd			    sizeof(depth0_listen)) {
360210883Spjd				pjdlog_error("listen argument is too long.");
361214274Spjd				free($2);
362210883Spjd				return (1);
363204076Spjd			}
364204076Spjd			break;
365204076Spjd		case 1:
366211883Spjd			if (!mynode)
367211883Spjd				break;
368211883Spjd			if (strlcpy(lconfig->hc_listenaddr, $2,
369211883Spjd			    sizeof(lconfig->hc_listenaddr)) >=
370211883Spjd			    sizeof(lconfig->hc_listenaddr)) {
371211883Spjd				pjdlog_error("listen argument is too long.");
372214274Spjd				free($2);
373211883Spjd				return (1);
374204076Spjd			}
375204076Spjd			break;
376204076Spjd		default:
377204076Spjd			assert(!"listen at wrong depth level");
378204076Spjd		}
379214274Spjd		free($2);
380204076Spjd	}
381204076Spjd	;
382204076Spjd
383204076Spjdreplication_statement:	REPLICATION replication_type
384204076Spjd	{
385204076Spjd		switch (depth) {
386204076Spjd		case 0:
387204076Spjd			depth0_replication = $2;
388204076Spjd			break;
389204076Spjd		case 1:
390204076Spjd			if (curres != NULL)
391204076Spjd				curres->hr_replication = $2;
392204076Spjd			break;
393204076Spjd		default:
394204076Spjd			assert(!"replication at wrong depth level");
395204076Spjd		}
396204076Spjd	}
397204076Spjd	;
398204076Spjd
399204076Spjdreplication_type:
400204076Spjd	FULLSYNC	{ $$ = HAST_REPLICATION_FULLSYNC; }
401204076Spjd	|
402204076Spjd	MEMSYNC		{ $$ = HAST_REPLICATION_MEMSYNC; }
403204076Spjd	|
404204076Spjd	ASYNC		{ $$ = HAST_REPLICATION_ASYNC; }
405204076Spjd	;
406204076Spjd
407219351Spjdchecksum_statement:	CHECKSUM checksum_type
408219351Spjd	{
409219351Spjd		switch (depth) {
410219351Spjd		case 0:
411219351Spjd			depth0_checksum = $2;
412219351Spjd			break;
413219351Spjd		case 1:
414219351Spjd			if (curres != NULL)
415219351Spjd				curres->hr_checksum = $2;
416219351Spjd			break;
417219351Spjd		default:
418219351Spjd			assert(!"checksum at wrong depth level");
419219351Spjd		}
420219351Spjd	}
421219351Spjd	;
422219351Spjd
423219351Spjdchecksum_type:
424219351Spjd	NONE		{ $$ = HAST_CHECKSUM_NONE; }
425219351Spjd	|
426219351Spjd	CRC32		{ $$ = HAST_CHECKSUM_CRC32; }
427219351Spjd	|
428219351Spjd	SHA256		{ $$ = HAST_CHECKSUM_SHA256; }
429219351Spjd	;
430219351Spjd
431219354Spjdcompression_statement:	COMPRESSION compression_type
432219354Spjd	{
433219354Spjd		switch (depth) {
434219354Spjd		case 0:
435219354Spjd			depth0_compression = $2;
436219354Spjd			break;
437219354Spjd		case 1:
438219354Spjd			if (curres != NULL)
439219354Spjd				curres->hr_compression = $2;
440219354Spjd			break;
441219354Spjd		default:
442219354Spjd			assert(!"compression at wrong depth level");
443219354Spjd		}
444219354Spjd	}
445219354Spjd	;
446219354Spjd
447219354Spjdcompression_type:
448219354Spjd	NONE		{ $$ = HAST_COMPRESSION_NONE; }
449219354Spjd	|
450219354Spjd	HOLE		{ $$ = HAST_COMPRESSION_HOLE; }
451219354Spjd	|
452219354Spjd	LZF		{ $$ = HAST_COMPRESSION_LZF; }
453219354Spjd	;
454219354Spjd
455207371Spjdtimeout_statement:	TIMEOUT NUM
456207371Spjd	{
457207371Spjd		switch (depth) {
458207371Spjd		case 0:
459207371Spjd			depth0_timeout = $2;
460207371Spjd			break;
461207371Spjd		case 1:
462207371Spjd			if (curres != NULL)
463207371Spjd				curres->hr_timeout = $2;
464207371Spjd			break;
465207371Spjd		default:
466207371Spjd			assert(!"timeout at wrong depth level");
467207371Spjd		}
468207371Spjd	}
469207371Spjd	;
470207371Spjd
471211886Spjdexec_statement:		EXEC STR
472211886Spjd	{
473211886Spjd		switch (depth) {
474211886Spjd		case 0:
475211886Spjd			if (strlcpy(depth0_exec, $2, sizeof(depth0_exec)) >=
476211886Spjd			    sizeof(depth0_exec)) {
477211886Spjd				pjdlog_error("Exec path is too long.");
478214274Spjd				free($2);
479211886Spjd				return (1);
480211886Spjd			}
481211886Spjd			break;
482211886Spjd		case 1:
483211886Spjd			if (curres == NULL)
484211886Spjd				break;
485211886Spjd			if (strlcpy(curres->hr_exec, $2,
486211886Spjd			    sizeof(curres->hr_exec)) >=
487211886Spjd			    sizeof(curres->hr_exec)) {
488211886Spjd				pjdlog_error("Exec path is too long.");
489214274Spjd				free($2);
490211886Spjd				return (1);
491211886Spjd			}
492211886Spjd			break;
493211886Spjd		default:
494211886Spjd			assert(!"exec at wrong depth level");
495211886Spjd		}
496214274Spjd		free($2);
497211886Spjd	}
498211886Spjd	;
499211886Spjd
500204076Spjdnode_statement:		ON node_start OB node_entries CB
501204076Spjd	{
502204076Spjd		mynode = false;
503204076Spjd	}
504204076Spjd	;
505204076Spjd
506204076Spjdnode_start:	STR
507204076Spjd	{
508210883Spjd		switch (isitme($1)) {
509210883Spjd		case -1:
510214274Spjd			free($1);
511210883Spjd			return (1);
512210883Spjd		case 0:
513210883Spjd			break;
514210883Spjd		case 1:
515204076Spjd			mynode = true;
516210883Spjd			break;
517210883Spjd		default:
518210883Spjd			assert(!"invalid isitme() return value");
519210883Spjd		}
520214274Spjd		free($1);
521204076Spjd	}
522204076Spjd	;
523204076Spjd
524204076Spjdnode_entries:
525204076Spjd	|
526204076Spjd	node_entries node_entry
527204076Spjd	;
528204076Spjd
529204076Spjdnode_entry:
530204076Spjd	control_statement
531204076Spjd	|
532204076Spjd	listen_statement
533204076Spjd	;
534204076Spjd
535204076Spjdresource_statement:	RESOURCE resource_start OB resource_entries CB
536204076Spjd	{
537204076Spjd		if (curres != NULL) {
538204076Spjd			/*
539216721Spjd			 * There must be section for this node, at least with
540216721Spjd			 * remote address configuration.
541216721Spjd			 */
542216721Spjd			if (!hadmynode) {
543216721Spjd				char *names;
544216721Spjd
545216721Spjd				if (node_names(&names) != 0)
546216721Spjd					return (1);
547216721Spjd				pjdlog_error("No resource %s configuration for this node (acceptable node names: %s).",
548216721Spjd				    curres->hr_name, names);
549216721Spjd				return (1);
550216721Spjd			}
551216721Spjd
552216721Spjd			/*
553204076Spjd			 * Let's see there are some resource-level settings
554204076Spjd			 * that we can use for node-level settings.
555204076Spjd			 */
556204076Spjd			if (curres->hr_provname[0] == '\0' &&
557204076Spjd			    depth1_provname[0] != '\0') {
558204076Spjd				/*
559204076Spjd				 * Provider name is not set at node-level,
560204076Spjd				 * but is set at resource-level, use it.
561204076Spjd				 */
562204076Spjd				strlcpy(curres->hr_provname, depth1_provname,
563204076Spjd				    sizeof(curres->hr_provname));
564204076Spjd			}
565204076Spjd			if (curres->hr_localpath[0] == '\0' &&
566204076Spjd			    depth1_localpath[0] != '\0') {
567204076Spjd				/*
568204076Spjd				 * Path to local provider is not set at
569204076Spjd				 * node-level, but is set at resource-level,
570204076Spjd				 * use it.
571204076Spjd				 */
572204076Spjd				strlcpy(curres->hr_localpath, depth1_localpath,
573204076Spjd				    sizeof(curres->hr_localpath));
574204076Spjd			}
575204076Spjd
576204076Spjd			/*
577204076Spjd			 * If provider name is not given, use resource name
578204076Spjd			 * as provider name.
579204076Spjd			 */
580204076Spjd			if (curres->hr_provname[0] == '\0') {
581204076Spjd				strlcpy(curres->hr_provname, curres->hr_name,
582204076Spjd				    sizeof(curres->hr_provname));
583204076Spjd			}
584204076Spjd
585204076Spjd			/*
586204076Spjd			 * Remote address has to be configured at this point.
587204076Spjd			 */
588204076Spjd			if (curres->hr_remoteaddr[0] == '\0') {
589210883Spjd				pjdlog_error("Remote address not configured for resource %s.",
590204076Spjd				    curres->hr_name);
591210883Spjd				return (1);
592204076Spjd			}
593204076Spjd			/*
594204076Spjd			 * Path to local provider has to be configured at this
595204076Spjd			 * point.
596204076Spjd			 */
597204076Spjd			if (curres->hr_localpath[0] == '\0') {
598210883Spjd				pjdlog_error("Path to local component not configured for resource %s.",
599204076Spjd				    curres->hr_name);
600210883Spjd				return (1);
601204076Spjd			}
602204076Spjd
603204076Spjd			/* Put it onto resource list. */
604210883Spjd			TAILQ_INSERT_TAIL(&lconfig->hc_resources, curres, hr_next);
605204076Spjd			curres = NULL;
606204076Spjd		}
607204076Spjd	}
608204076Spjd	;
609204076Spjd
610204076Spjdresource_start:	STR
611204076Spjd	{
612216722Spjd		/* Check if there is no duplicate entry. */
613216722Spjd		TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) {
614216722Spjd			if (strcmp(curres->hr_name, $1) == 0) {
615216722Spjd				pjdlog_error("Resource %s configured more than once.",
616216722Spjd				    curres->hr_name);
617216722Spjd				free($1);
618216722Spjd				return (1);
619216722Spjd			}
620216722Spjd		}
621216722Spjd
622204076Spjd		/*
623204076Spjd		 * Clear those, so we can tell if they were set at
624204076Spjd		 * resource-level or not.
625204076Spjd		 */
626204076Spjd		depth1_provname[0] = '\0';
627204076Spjd		depth1_localpath[0] = '\0';
628216721Spjd		hadmynode = false;
629204076Spjd
630204076Spjd		curres = calloc(1, sizeof(*curres));
631204076Spjd		if (curres == NULL) {
632210883Spjd			pjdlog_error("Unable to allocate memory for resource.");
633214274Spjd			free($1);
634210883Spjd			return (1);
635204076Spjd		}
636204076Spjd		if (strlcpy(curres->hr_name, $1,
637204076Spjd		    sizeof(curres->hr_name)) >=
638204076Spjd		    sizeof(curres->hr_name)) {
639210883Spjd			pjdlog_error("Resource name is too long.");
640214274Spjd			free($1);
641210883Spjd			return (1);
642204076Spjd		}
643214274Spjd		free($1);
644204076Spjd		curres->hr_role = HAST_ROLE_INIT;
645204076Spjd		curres->hr_previous_role = HAST_ROLE_INIT;
646204076Spjd		curres->hr_replication = -1;
647219351Spjd		curres->hr_checksum = -1;
648219354Spjd		curres->hr_compression = -1;
649207371Spjd		curres->hr_timeout = -1;
650211886Spjd		curres->hr_exec[0] = '\0';
651204076Spjd		curres->hr_provname[0] = '\0';
652204076Spjd		curres->hr_localpath[0] = '\0';
653204076Spjd		curres->hr_localfd = -1;
654204076Spjd		curres->hr_remoteaddr[0] = '\0';
655219818Spjd		curres->hr_sourceaddr[0] = '\0';
656204076Spjd		curres->hr_ggateunit = -1;
657204076Spjd	}
658204076Spjd	;
659204076Spjd
660204076Spjdresource_entries:
661204076Spjd	|
662204076Spjd	resource_entries resource_entry
663204076Spjd	;
664204076Spjd
665204076Spjdresource_entry:
666204076Spjd	replication_statement
667204076Spjd	|
668219351Spjd	checksum_statement
669219351Spjd	|
670219354Spjd	compression_statement
671219354Spjd	|
672207371Spjd	timeout_statement
673207371Spjd	|
674211886Spjd	exec_statement
675211886Spjd	|
676204076Spjd	name_statement
677204076Spjd	|
678204076Spjd	local_statement
679204076Spjd	|
680204076Spjd	resource_node_statement
681204076Spjd	;
682204076Spjd
683204076Spjdname_statement:		NAME STR
684204076Spjd	{
685204076Spjd		switch (depth) {
686204076Spjd		case 1:
687204076Spjd			if (strlcpy(depth1_provname, $2,
688204076Spjd			    sizeof(depth1_provname)) >=
689204076Spjd			    sizeof(depth1_provname)) {
690210883Spjd				pjdlog_error("name argument is too long.");
691214274Spjd				free($2);
692210883Spjd				return (1);
693204076Spjd			}
694204076Spjd			break;
695204076Spjd		case 2:
696211883Spjd			if (!mynode)
697211883Spjd				break;
698211883Spjd			assert(curres != NULL);
699211883Spjd			if (strlcpy(curres->hr_provname, $2,
700211883Spjd			    sizeof(curres->hr_provname)) >=
701211883Spjd			    sizeof(curres->hr_provname)) {
702211883Spjd				pjdlog_error("name argument is too long.");
703214274Spjd				free($2);
704211883Spjd				return (1);
705204076Spjd			}
706204076Spjd			break;
707204076Spjd		default:
708204076Spjd			assert(!"name at wrong depth level");
709204076Spjd		}
710214274Spjd		free($2);
711204076Spjd	}
712204076Spjd	;
713204076Spjd
714204076Spjdlocal_statement:	LOCAL STR
715204076Spjd	{
716204076Spjd		switch (depth) {
717204076Spjd		case 1:
718204076Spjd			if (strlcpy(depth1_localpath, $2,
719204076Spjd			    sizeof(depth1_localpath)) >=
720204076Spjd			    sizeof(depth1_localpath)) {
721210883Spjd				pjdlog_error("local argument is too long.");
722214274Spjd				free($2);
723210883Spjd				return (1);
724204076Spjd			}
725204076Spjd			break;
726204076Spjd		case 2:
727211883Spjd			if (!mynode)
728211883Spjd				break;
729211883Spjd			assert(curres != NULL);
730211883Spjd			if (strlcpy(curres->hr_localpath, $2,
731211883Spjd			    sizeof(curres->hr_localpath)) >=
732211883Spjd			    sizeof(curres->hr_localpath)) {
733211883Spjd				pjdlog_error("local argument is too long.");
734214274Spjd				free($2);
735211883Spjd				return (1);
736204076Spjd			}
737204076Spjd			break;
738204076Spjd		default:
739204076Spjd			assert(!"local at wrong depth level");
740204076Spjd		}
741214274Spjd		free($2);
742204076Spjd	}
743204076Spjd	;
744204076Spjd
745204076Spjdresource_node_statement:ON resource_node_start OB resource_node_entries CB
746204076Spjd	{
747204076Spjd		mynode = false;
748204076Spjd	}
749204076Spjd	;
750204076Spjd
751204076Spjdresource_node_start:	STR
752204076Spjd	{
753210883Spjd		if (curres != NULL) {
754210883Spjd			switch (isitme($1)) {
755210883Spjd			case -1:
756214274Spjd				free($1);
757210883Spjd				return (1);
758210883Spjd			case 0:
759210883Spjd				break;
760210883Spjd			case 1:
761216721Spjd				mynode = hadmynode = true;
762210883Spjd				break;
763210883Spjd			default:
764210883Spjd				assert(!"invalid isitme() return value");
765210883Spjd			}
766210883Spjd		}
767214274Spjd		free($1);
768204076Spjd	}
769204076Spjd	;
770204076Spjd
771204076Spjdresource_node_entries:
772204076Spjd	|
773204076Spjd	resource_node_entries resource_node_entry
774204076Spjd	;
775204076Spjd
776204076Spjdresource_node_entry:
777204076Spjd	name_statement
778204076Spjd	|
779204076Spjd	local_statement
780204076Spjd	|
781204076Spjd	remote_statement
782219818Spjd	|
783219818Spjd	source_statement
784204076Spjd	;
785204076Spjd
786204076Spjdremote_statement:	REMOTE STR
787204076Spjd	{
788204076Spjd		assert(depth == 2);
789204076Spjd		if (mynode) {
790204076Spjd			assert(curres != NULL);
791204076Spjd			if (strlcpy(curres->hr_remoteaddr, $2,
792204076Spjd			    sizeof(curres->hr_remoteaddr)) >=
793204076Spjd			    sizeof(curres->hr_remoteaddr)) {
794210883Spjd				pjdlog_error("remote argument is too long.");
795214274Spjd				free($2);
796210883Spjd				return (1);
797204076Spjd			}
798204076Spjd		}
799214274Spjd		free($2);
800204076Spjd	}
801204076Spjd	;
802219818Spjd
803219818Spjdsource_statement:	SOURCE STR
804219818Spjd	{
805219818Spjd		assert(depth == 2);
806219818Spjd		if (mynode) {
807219818Spjd			assert(curres != NULL);
808219818Spjd			if (strlcpy(curres->hr_sourceaddr, $2,
809219818Spjd			    sizeof(curres->hr_sourceaddr)) >=
810219818Spjd			    sizeof(curres->hr_sourceaddr)) {
811219818Spjd				pjdlog_error("source argument is too long.");
812219818Spjd				free($2);
813219818Spjd				return (1);
814219818Spjd			}
815219818Spjd		}
816219818Spjd		free($2);
817219818Spjd	}
818219818Spjd	;
819