parse.y revision 220889
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 220889 2011-04-20 16:36: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;
172220573Spjd	depth0_replication = HAST_REPLICATION_FULLSYNC;
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		}
231220573Spjd		if (curres->hr_replication == HAST_REPLICATION_MEMSYNC ||
232220573Spjd		    curres->hr_replication == HAST_REPLICATION_ASYNC) {
233220573Spjd			pjdlog_warning("Replication mode \"%s\" is not implemented, falling back to \"%s\".",
234220573Spjd			    curres->hr_replication == HAST_REPLICATION_MEMSYNC ?
235220573Spjd			    "memsync" : "async", "fullsync");
236220573Spjd			curres->hr_replication = HAST_REPLICATION_FULLSYNC;
237220573Spjd		}
238219351Spjd		if (curres->hr_checksum == -1) {
239219351Spjd			/*
240219351Spjd			 * Checksum is not set at resource-level.
241219351Spjd			 * Use global or default setting.
242219351Spjd			 */
243219351Spjd			curres->hr_checksum = depth0_checksum;
244219351Spjd		}
245219354Spjd		if (curres->hr_compression == -1) {
246219354Spjd			/*
247219354Spjd			 * Compression is not set at resource-level.
248219354Spjd			 * Use global or default setting.
249219354Spjd			 */
250219354Spjd			curres->hr_compression = depth0_compression;
251219354Spjd		}
252207371Spjd		if (curres->hr_timeout == -1) {
253207371Spjd			/*
254207371Spjd			 * Timeout is not set at resource-level.
255207371Spjd			 * Use global or default setting.
256207371Spjd			 */
257207371Spjd			curres->hr_timeout = depth0_timeout;
258207371Spjd		}
259211886Spjd		if (curres->hr_exec[0] == '\0') {
260211886Spjd			/*
261211886Spjd			 * Exec is not set at resource-level.
262211886Spjd			 * Use global or default setting.
263211886Spjd			 */
264211886Spjd			strlcpy(curres->hr_exec, depth0_exec,
265211886Spjd			    sizeof(curres->hr_exec));
266211886Spjd		}
267204076Spjd	}
268204076Spjd
269210883Spjd	return (lconfig);
270204076Spjd}
271204076Spjd
272204076Spjdvoid
273204076Spjdyy_config_free(struct hastd_config *config)
274204076Spjd{
275204076Spjd	struct hast_resource *res;
276204076Spjd
277204076Spjd	while ((res = TAILQ_FIRST(&config->hc_resources)) != NULL) {
278204076Spjd		TAILQ_REMOVE(&config->hc_resources, res, hr_next);
279204076Spjd		free(res);
280204076Spjd	}
281210883Spjd	free(config);
282204076Spjd}
283204076Spjd%}
284204076Spjd
285219354Spjd%token CONTROL LISTEN PORT REPLICATION CHECKSUM COMPRESSION
286219818Spjd%token TIMEOUT EXEC EXTENTSIZE RESOURCE NAME LOCAL REMOTE SOURCE ON
287219354Spjd%token FULLSYNC MEMSYNC ASYNC NONE CRC32 SHA256 HOLE LZF
288204076Spjd%token NUM STR OB CB
289204076Spjd
290204076Spjd%type <num> replication_type
291219351Spjd%type <num> checksum_type
292219354Spjd%type <num> compression_type
293204076Spjd
294204076Spjd%union
295204076Spjd{
296204076Spjd	int num;
297204076Spjd	char *str;
298204076Spjd}
299204076Spjd
300204076Spjd%token <num> NUM
301204076Spjd%token <str> STR
302204076Spjd
303204076Spjd%%
304204076Spjd
305204076Spjdstatements:
306204076Spjd	|
307204076Spjd	statements statement
308204076Spjd	;
309204076Spjd
310204076Spjdstatement:
311204076Spjd	control_statement
312204076Spjd	|
313204076Spjd	listen_statement
314204076Spjd	|
315204076Spjd	replication_statement
316204076Spjd	|
317219351Spjd	checksum_statement
318219351Spjd	|
319219354Spjd	compression_statement
320219354Spjd	|
321207371Spjd	timeout_statement
322207371Spjd	|
323211886Spjd	exec_statement
324211886Spjd	|
325204076Spjd	node_statement
326204076Spjd	|
327204076Spjd	resource_statement
328204076Spjd	;
329204076Spjd
330204076Spjdcontrol_statement:	CONTROL STR
331204076Spjd	{
332204076Spjd		switch (depth) {
333204076Spjd		case 0:
334204076Spjd			if (strlcpy(depth0_control, $2,
335204076Spjd			    sizeof(depth0_control)) >=
336204076Spjd			    sizeof(depth0_control)) {
337210883Spjd				pjdlog_error("control argument is too long.");
338214274Spjd				free($2);
339210883Spjd				return (1);
340204076Spjd			}
341204076Spjd			break;
342204076Spjd		case 1:
343211883Spjd			if (!mynode)
344211883Spjd				break;
345211883Spjd			if (strlcpy(lconfig->hc_controladdr, $2,
346211883Spjd			    sizeof(lconfig->hc_controladdr)) >=
347211883Spjd			    sizeof(lconfig->hc_controladdr)) {
348211883Spjd				pjdlog_error("control argument is too long.");
349214274Spjd				free($2);
350211883Spjd				return (1);
351204076Spjd			}
352204076Spjd			break;
353204076Spjd		default:
354204076Spjd			assert(!"control at wrong depth level");
355204076Spjd		}
356214274Spjd		free($2);
357204076Spjd	}
358204076Spjd	;
359204076Spjd
360204076Spjdlisten_statement:	LISTEN STR
361204076Spjd	{
362204076Spjd		switch (depth) {
363204076Spjd		case 0:
364204076Spjd			if (strlcpy(depth0_listen, $2,
365204076Spjd			    sizeof(depth0_listen)) >=
366204076Spjd			    sizeof(depth0_listen)) {
367210883Spjd				pjdlog_error("listen argument is too long.");
368214274Spjd				free($2);
369210883Spjd				return (1);
370204076Spjd			}
371204076Spjd			break;
372204076Spjd		case 1:
373211883Spjd			if (!mynode)
374211883Spjd				break;
375211883Spjd			if (strlcpy(lconfig->hc_listenaddr, $2,
376211883Spjd			    sizeof(lconfig->hc_listenaddr)) >=
377211883Spjd			    sizeof(lconfig->hc_listenaddr)) {
378211883Spjd				pjdlog_error("listen argument is too long.");
379214274Spjd				free($2);
380211883Spjd				return (1);
381204076Spjd			}
382204076Spjd			break;
383204076Spjd		default:
384204076Spjd			assert(!"listen at wrong depth level");
385204076Spjd		}
386214274Spjd		free($2);
387204076Spjd	}
388204076Spjd	;
389204076Spjd
390204076Spjdreplication_statement:	REPLICATION replication_type
391204076Spjd	{
392204076Spjd		switch (depth) {
393204076Spjd		case 0:
394204076Spjd			depth0_replication = $2;
395204076Spjd			break;
396204076Spjd		case 1:
397204076Spjd			if (curres != NULL)
398204076Spjd				curres->hr_replication = $2;
399204076Spjd			break;
400204076Spjd		default:
401204076Spjd			assert(!"replication at wrong depth level");
402204076Spjd		}
403204076Spjd	}
404204076Spjd	;
405204076Spjd
406204076Spjdreplication_type:
407204076Spjd	FULLSYNC	{ $$ = HAST_REPLICATION_FULLSYNC; }
408204076Spjd	|
409204076Spjd	MEMSYNC		{ $$ = HAST_REPLICATION_MEMSYNC; }
410204076Spjd	|
411204076Spjd	ASYNC		{ $$ = HAST_REPLICATION_ASYNC; }
412204076Spjd	;
413204076Spjd
414219351Spjdchecksum_statement:	CHECKSUM checksum_type
415219351Spjd	{
416219351Spjd		switch (depth) {
417219351Spjd		case 0:
418219351Spjd			depth0_checksum = $2;
419219351Spjd			break;
420219351Spjd		case 1:
421219351Spjd			if (curres != NULL)
422219351Spjd				curres->hr_checksum = $2;
423219351Spjd			break;
424219351Spjd		default:
425219351Spjd			assert(!"checksum at wrong depth level");
426219351Spjd		}
427219351Spjd	}
428219351Spjd	;
429219351Spjd
430219351Spjdchecksum_type:
431219351Spjd	NONE		{ $$ = HAST_CHECKSUM_NONE; }
432219351Spjd	|
433219351Spjd	CRC32		{ $$ = HAST_CHECKSUM_CRC32; }
434219351Spjd	|
435219351Spjd	SHA256		{ $$ = HAST_CHECKSUM_SHA256; }
436219351Spjd	;
437219351Spjd
438219354Spjdcompression_statement:	COMPRESSION compression_type
439219354Spjd	{
440219354Spjd		switch (depth) {
441219354Spjd		case 0:
442219354Spjd			depth0_compression = $2;
443219354Spjd			break;
444219354Spjd		case 1:
445219354Spjd			if (curres != NULL)
446219354Spjd				curres->hr_compression = $2;
447219354Spjd			break;
448219354Spjd		default:
449219354Spjd			assert(!"compression at wrong depth level");
450219354Spjd		}
451219354Spjd	}
452219354Spjd	;
453219354Spjd
454219354Spjdcompression_type:
455219354Spjd	NONE		{ $$ = HAST_COMPRESSION_NONE; }
456219354Spjd	|
457219354Spjd	HOLE		{ $$ = HAST_COMPRESSION_HOLE; }
458219354Spjd	|
459219354Spjd	LZF		{ $$ = HAST_COMPRESSION_LZF; }
460219354Spjd	;
461219354Spjd
462207371Spjdtimeout_statement:	TIMEOUT NUM
463207371Spjd	{
464220889Spjd		if ($2 <= 0) {
465220889Spjd			pjdlog_error("Negative or zero timeout.");
466220889Spjd			return (1);
467220889Spjd		}
468207371Spjd		switch (depth) {
469207371Spjd		case 0:
470207371Spjd			depth0_timeout = $2;
471207371Spjd			break;
472207371Spjd		case 1:
473207371Spjd			if (curres != NULL)
474207371Spjd				curres->hr_timeout = $2;
475207371Spjd			break;
476207371Spjd		default:
477207371Spjd			assert(!"timeout at wrong depth level");
478207371Spjd		}
479207371Spjd	}
480207371Spjd	;
481207371Spjd
482211886Spjdexec_statement:		EXEC STR
483211886Spjd	{
484211886Spjd		switch (depth) {
485211886Spjd		case 0:
486211886Spjd			if (strlcpy(depth0_exec, $2, sizeof(depth0_exec)) >=
487211886Spjd			    sizeof(depth0_exec)) {
488211886Spjd				pjdlog_error("Exec path is too long.");
489214274Spjd				free($2);
490211886Spjd				return (1);
491211886Spjd			}
492211886Spjd			break;
493211886Spjd		case 1:
494211886Spjd			if (curres == NULL)
495211886Spjd				break;
496211886Spjd			if (strlcpy(curres->hr_exec, $2,
497211886Spjd			    sizeof(curres->hr_exec)) >=
498211886Spjd			    sizeof(curres->hr_exec)) {
499211886Spjd				pjdlog_error("Exec path is too long.");
500214274Spjd				free($2);
501211886Spjd				return (1);
502211886Spjd			}
503211886Spjd			break;
504211886Spjd		default:
505211886Spjd			assert(!"exec at wrong depth level");
506211886Spjd		}
507214274Spjd		free($2);
508211886Spjd	}
509211886Spjd	;
510211886Spjd
511204076Spjdnode_statement:		ON node_start OB node_entries CB
512204076Spjd	{
513204076Spjd		mynode = false;
514204076Spjd	}
515204076Spjd	;
516204076Spjd
517204076Spjdnode_start:	STR
518204076Spjd	{
519210883Spjd		switch (isitme($1)) {
520210883Spjd		case -1:
521214274Spjd			free($1);
522210883Spjd			return (1);
523210883Spjd		case 0:
524210883Spjd			break;
525210883Spjd		case 1:
526204076Spjd			mynode = true;
527210883Spjd			break;
528210883Spjd		default:
529210883Spjd			assert(!"invalid isitme() return value");
530210883Spjd		}
531214274Spjd		free($1);
532204076Spjd	}
533204076Spjd	;
534204076Spjd
535204076Spjdnode_entries:
536204076Spjd	|
537204076Spjd	node_entries node_entry
538204076Spjd	;
539204076Spjd
540204076Spjdnode_entry:
541204076Spjd	control_statement
542204076Spjd	|
543204076Spjd	listen_statement
544204076Spjd	;
545204076Spjd
546204076Spjdresource_statement:	RESOURCE resource_start OB resource_entries CB
547204076Spjd	{
548204076Spjd		if (curres != NULL) {
549204076Spjd			/*
550216721Spjd			 * There must be section for this node, at least with
551216721Spjd			 * remote address configuration.
552216721Spjd			 */
553216721Spjd			if (!hadmynode) {
554216721Spjd				char *names;
555216721Spjd
556216721Spjd				if (node_names(&names) != 0)
557216721Spjd					return (1);
558216721Spjd				pjdlog_error("No resource %s configuration for this node (acceptable node names: %s).",
559216721Spjd				    curres->hr_name, names);
560216721Spjd				return (1);
561216721Spjd			}
562216721Spjd
563216721Spjd			/*
564204076Spjd			 * Let's see there are some resource-level settings
565204076Spjd			 * that we can use for node-level settings.
566204076Spjd			 */
567204076Spjd			if (curres->hr_provname[0] == '\0' &&
568204076Spjd			    depth1_provname[0] != '\0') {
569204076Spjd				/*
570204076Spjd				 * Provider name is not set at node-level,
571204076Spjd				 * but is set at resource-level, use it.
572204076Spjd				 */
573204076Spjd				strlcpy(curres->hr_provname, depth1_provname,
574204076Spjd				    sizeof(curres->hr_provname));
575204076Spjd			}
576204076Spjd			if (curres->hr_localpath[0] == '\0' &&
577204076Spjd			    depth1_localpath[0] != '\0') {
578204076Spjd				/*
579204076Spjd				 * Path to local provider is not set at
580204076Spjd				 * node-level, but is set at resource-level,
581204076Spjd				 * use it.
582204076Spjd				 */
583204076Spjd				strlcpy(curres->hr_localpath, depth1_localpath,
584204076Spjd				    sizeof(curres->hr_localpath));
585204076Spjd			}
586204076Spjd
587204076Spjd			/*
588204076Spjd			 * If provider name is not given, use resource name
589204076Spjd			 * as provider name.
590204076Spjd			 */
591204076Spjd			if (curres->hr_provname[0] == '\0') {
592204076Spjd				strlcpy(curres->hr_provname, curres->hr_name,
593204076Spjd				    sizeof(curres->hr_provname));
594204076Spjd			}
595204076Spjd
596204076Spjd			/*
597204076Spjd			 * Remote address has to be configured at this point.
598204076Spjd			 */
599204076Spjd			if (curres->hr_remoteaddr[0] == '\0') {
600210883Spjd				pjdlog_error("Remote address not configured for resource %s.",
601204076Spjd				    curres->hr_name);
602210883Spjd				return (1);
603204076Spjd			}
604204076Spjd			/*
605204076Spjd			 * Path to local provider has to be configured at this
606204076Spjd			 * point.
607204076Spjd			 */
608204076Spjd			if (curres->hr_localpath[0] == '\0') {
609210883Spjd				pjdlog_error("Path to local component not configured for resource %s.",
610204076Spjd				    curres->hr_name);
611210883Spjd				return (1);
612204076Spjd			}
613204076Spjd
614204076Spjd			/* Put it onto resource list. */
615210883Spjd			TAILQ_INSERT_TAIL(&lconfig->hc_resources, curres, hr_next);
616204076Spjd			curres = NULL;
617204076Spjd		}
618204076Spjd	}
619204076Spjd	;
620204076Spjd
621204076Spjdresource_start:	STR
622204076Spjd	{
623216722Spjd		/* Check if there is no duplicate entry. */
624216722Spjd		TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) {
625216722Spjd			if (strcmp(curres->hr_name, $1) == 0) {
626216722Spjd				pjdlog_error("Resource %s configured more than once.",
627216722Spjd				    curres->hr_name);
628216722Spjd				free($1);
629216722Spjd				return (1);
630216722Spjd			}
631216722Spjd		}
632216722Spjd
633204076Spjd		/*
634204076Spjd		 * Clear those, so we can tell if they were set at
635204076Spjd		 * resource-level or not.
636204076Spjd		 */
637204076Spjd		depth1_provname[0] = '\0';
638204076Spjd		depth1_localpath[0] = '\0';
639216721Spjd		hadmynode = false;
640204076Spjd
641204076Spjd		curres = calloc(1, sizeof(*curres));
642204076Spjd		if (curres == NULL) {
643210883Spjd			pjdlog_error("Unable to allocate memory for resource.");
644214274Spjd			free($1);
645210883Spjd			return (1);
646204076Spjd		}
647204076Spjd		if (strlcpy(curres->hr_name, $1,
648204076Spjd		    sizeof(curres->hr_name)) >=
649204076Spjd		    sizeof(curres->hr_name)) {
650210883Spjd			pjdlog_error("Resource name is too long.");
651214274Spjd			free($1);
652210883Spjd			return (1);
653204076Spjd		}
654214274Spjd		free($1);
655204076Spjd		curres->hr_role = HAST_ROLE_INIT;
656204076Spjd		curres->hr_previous_role = HAST_ROLE_INIT;
657204076Spjd		curres->hr_replication = -1;
658219351Spjd		curres->hr_checksum = -1;
659219354Spjd		curres->hr_compression = -1;
660207371Spjd		curres->hr_timeout = -1;
661211886Spjd		curres->hr_exec[0] = '\0';
662204076Spjd		curres->hr_provname[0] = '\0';
663204076Spjd		curres->hr_localpath[0] = '\0';
664204076Spjd		curres->hr_localfd = -1;
665204076Spjd		curres->hr_remoteaddr[0] = '\0';
666219818Spjd		curres->hr_sourceaddr[0] = '\0';
667204076Spjd		curres->hr_ggateunit = -1;
668204076Spjd	}
669204076Spjd	;
670204076Spjd
671204076Spjdresource_entries:
672204076Spjd	|
673204076Spjd	resource_entries resource_entry
674204076Spjd	;
675204076Spjd
676204076Spjdresource_entry:
677204076Spjd	replication_statement
678204076Spjd	|
679219351Spjd	checksum_statement
680219351Spjd	|
681219354Spjd	compression_statement
682219354Spjd	|
683207371Spjd	timeout_statement
684207371Spjd	|
685211886Spjd	exec_statement
686211886Spjd	|
687204076Spjd	name_statement
688204076Spjd	|
689204076Spjd	local_statement
690204076Spjd	|
691204076Spjd	resource_node_statement
692204076Spjd	;
693204076Spjd
694204076Spjdname_statement:		NAME STR
695204076Spjd	{
696204076Spjd		switch (depth) {
697204076Spjd		case 1:
698204076Spjd			if (strlcpy(depth1_provname, $2,
699204076Spjd			    sizeof(depth1_provname)) >=
700204076Spjd			    sizeof(depth1_provname)) {
701210883Spjd				pjdlog_error("name argument is too long.");
702214274Spjd				free($2);
703210883Spjd				return (1);
704204076Spjd			}
705204076Spjd			break;
706204076Spjd		case 2:
707211883Spjd			if (!mynode)
708211883Spjd				break;
709211883Spjd			assert(curres != NULL);
710211883Spjd			if (strlcpy(curres->hr_provname, $2,
711211883Spjd			    sizeof(curres->hr_provname)) >=
712211883Spjd			    sizeof(curres->hr_provname)) {
713211883Spjd				pjdlog_error("name argument is too long.");
714214274Spjd				free($2);
715211883Spjd				return (1);
716204076Spjd			}
717204076Spjd			break;
718204076Spjd		default:
719204076Spjd			assert(!"name at wrong depth level");
720204076Spjd		}
721214274Spjd		free($2);
722204076Spjd	}
723204076Spjd	;
724204076Spjd
725204076Spjdlocal_statement:	LOCAL STR
726204076Spjd	{
727204076Spjd		switch (depth) {
728204076Spjd		case 1:
729204076Spjd			if (strlcpy(depth1_localpath, $2,
730204076Spjd			    sizeof(depth1_localpath)) >=
731204076Spjd			    sizeof(depth1_localpath)) {
732210883Spjd				pjdlog_error("local argument is too long.");
733214274Spjd				free($2);
734210883Spjd				return (1);
735204076Spjd			}
736204076Spjd			break;
737204076Spjd		case 2:
738211883Spjd			if (!mynode)
739211883Spjd				break;
740211883Spjd			assert(curres != NULL);
741211883Spjd			if (strlcpy(curres->hr_localpath, $2,
742211883Spjd			    sizeof(curres->hr_localpath)) >=
743211883Spjd			    sizeof(curres->hr_localpath)) {
744211883Spjd				pjdlog_error("local argument is too long.");
745214274Spjd				free($2);
746211883Spjd				return (1);
747204076Spjd			}
748204076Spjd			break;
749204076Spjd		default:
750204076Spjd			assert(!"local at wrong depth level");
751204076Spjd		}
752214274Spjd		free($2);
753204076Spjd	}
754204076Spjd	;
755204076Spjd
756204076Spjdresource_node_statement:ON resource_node_start OB resource_node_entries CB
757204076Spjd	{
758204076Spjd		mynode = false;
759204076Spjd	}
760204076Spjd	;
761204076Spjd
762204076Spjdresource_node_start:	STR
763204076Spjd	{
764210883Spjd		if (curres != NULL) {
765210883Spjd			switch (isitme($1)) {
766210883Spjd			case -1:
767214274Spjd				free($1);
768210883Spjd				return (1);
769210883Spjd			case 0:
770210883Spjd				break;
771210883Spjd			case 1:
772216721Spjd				mynode = hadmynode = true;
773210883Spjd				break;
774210883Spjd			default:
775210883Spjd				assert(!"invalid isitme() return value");
776210883Spjd			}
777210883Spjd		}
778214274Spjd		free($1);
779204076Spjd	}
780204076Spjd	;
781204076Spjd
782204076Spjdresource_node_entries:
783204076Spjd	|
784204076Spjd	resource_node_entries resource_node_entry
785204076Spjd	;
786204076Spjd
787204076Spjdresource_node_entry:
788204076Spjd	name_statement
789204076Spjd	|
790204076Spjd	local_statement
791204076Spjd	|
792204076Spjd	remote_statement
793219818Spjd	|
794219818Spjd	source_statement
795204076Spjd	;
796204076Spjd
797204076Spjdremote_statement:	REMOTE STR
798204076Spjd	{
799204076Spjd		assert(depth == 2);
800204076Spjd		if (mynode) {
801204076Spjd			assert(curres != NULL);
802204076Spjd			if (strlcpy(curres->hr_remoteaddr, $2,
803204076Spjd			    sizeof(curres->hr_remoteaddr)) >=
804204076Spjd			    sizeof(curres->hr_remoteaddr)) {
805210883Spjd				pjdlog_error("remote argument is too long.");
806214274Spjd				free($2);
807210883Spjd				return (1);
808204076Spjd			}
809204076Spjd		}
810214274Spjd		free($2);
811204076Spjd	}
812204076Spjd	;
813219818Spjd
814219818Spjdsource_statement:	SOURCE STR
815219818Spjd	{
816219818Spjd		assert(depth == 2);
817219818Spjd		if (mynode) {
818219818Spjd			assert(curres != NULL);
819219818Spjd			if (strlcpy(curres->hr_sourceaddr, $2,
820219818Spjd			    sizeof(curres->hr_sourceaddr)) >=
821219818Spjd			    sizeof(curres->hr_sourceaddr)) {
822219818Spjd				pjdlog_error("source argument is too long.");
823219818Spjd				free($2);
824219818Spjd				return (1);
825219818Spjd			}
826219818Spjd		}
827219818Spjd		free($2);
828219818Spjd	}
829219818Spjd	;
830