parse.y revision 219351
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 219351 2011-03-06 22:56:14Z 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;
65207371Spjdstatic int depth0_timeout;
66211886Spjdstatic char depth0_exec[PATH_MAX];
67204076Spjd
68204076Spjdstatic char depth1_provname[PATH_MAX];
69204076Spjdstatic char depth1_localpath[PATH_MAX];
70204076Spjd
71210883Spjdextern void yyrestart(FILE *);
72210883Spjd
73210883Spjdstatic int
74204076Spjdisitme(const char *name)
75204076Spjd{
76204076Spjd	char buf[MAXHOSTNAMELEN];
77204076Spjd	char *pos;
78204076Spjd	size_t bufsize;
79204076Spjd
80204076Spjd	/*
81204076Spjd	 * First check if the give name matches our full hostname.
82204076Spjd	 */
83210883Spjd	if (gethostname(buf, sizeof(buf)) < 0) {
84210883Spjd		pjdlog_errno(LOG_ERR, "gethostname() failed");
85210883Spjd		return (-1);
86210883Spjd	}
87204076Spjd	if (strcmp(buf, name) == 0)
88210883Spjd		return (1);
89204076Spjd
90204076Spjd	/*
91204076Spjd	 * Now check if it matches first part of the host name.
92204076Spjd	 */
93204076Spjd	pos = strchr(buf, '.');
94204076Spjd	if (pos != NULL && pos != buf && strncmp(buf, name, pos - buf) == 0)
95210883Spjd		return (1);
96204076Spjd
97204076Spjd	/*
98204076Spjd	 * At the end check if name is equal to our host's UUID.
99204076Spjd	 */
100204076Spjd	bufsize = sizeof(buf);
101210883Spjd	if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) {
102210883Spjd		pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed");
103210883Spjd		return (-1);
104210883Spjd	}
105204076Spjd	if (strcasecmp(buf, name) == 0)
106210883Spjd		return (1);
107204076Spjd
108204076Spjd	/*
109204076Spjd	 * Looks like this isn't about us.
110204076Spjd	 */
111210883Spjd	return (0);
112204076Spjd}
113204076Spjd
114216721Spjdstatic int
115216721Spjdnode_names(char **namesp)
116216721Spjd{
117216721Spjd	static char names[MAXHOSTNAMELEN * 3];
118216721Spjd	char buf[MAXHOSTNAMELEN];
119216721Spjd	char *pos;
120216721Spjd	size_t bufsize;
121216721Spjd
122216721Spjd	if (gethostname(buf, sizeof(buf)) < 0) {
123216721Spjd		pjdlog_errno(LOG_ERR, "gethostname() failed");
124216721Spjd		return (-1);
125216721Spjd	}
126216721Spjd
127216721Spjd	/* First component of the host name. */
128216721Spjd	pos = strchr(buf, '.');
129216721Spjd	if (pos != NULL && pos != buf) {
130216721Spjd		(void)strlcpy(names, buf, MIN((size_t)(pos - buf + 1),
131216721Spjd		    sizeof(names)));
132216721Spjd		(void)strlcat(names, ", ", sizeof(names));
133216721Spjd	}
134216721Spjd
135216721Spjd	/* Full host name. */
136216721Spjd	(void)strlcat(names, buf, sizeof(names));
137216721Spjd	(void)strlcat(names, ", ", sizeof(names));
138216721Spjd
139216721Spjd	/* Host UUID. */
140216721Spjd	bufsize = sizeof(buf);
141216721Spjd	if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) {
142216721Spjd		pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed");
143216721Spjd		return (-1);
144216721Spjd	}
145216721Spjd	(void)strlcat(names, buf, sizeof(names));
146216721Spjd
147216721Spjd	*namesp = names;
148216721Spjd
149216721Spjd	return (0);
150216721Spjd}
151216721Spjd
152204076Spjdvoid
153204076Spjdyyerror(const char *str)
154204076Spjd{
155204076Spjd
156210883Spjd	pjdlog_error("Unable to parse configuration file at line %d near '%s': %s",
157204076Spjd	    lineno, yytext, str);
158204076Spjd}
159204076Spjd
160204076Spjdstruct hastd_config *
161210883Spjdyy_config_parse(const char *config, bool exitonerror)
162204076Spjd{
163204076Spjd	int ret;
164204076Spjd
165204076Spjd	curres = NULL;
166204076Spjd	mynode = false;
167210883Spjd	depth = 0;
168210883Spjd	lineno = 0;
169204076Spjd
170207371Spjd	depth0_timeout = HAST_TIMEOUT;
171204076Spjd	depth0_replication = HAST_REPLICATION_MEMSYNC;
172219351Spjd	depth0_checksum = HAST_CHECKSUM_NONE;
173204076Spjd	strlcpy(depth0_control, HAST_CONTROL, sizeof(depth0_control));
174204076Spjd	strlcpy(depth0_listen, HASTD_LISTEN, sizeof(depth0_listen));
175211886Spjd	depth0_exec[0] = '\0';
176204076Spjd
177210883Spjd	lconfig = calloc(1, sizeof(*lconfig));
178210883Spjd	if (lconfig == NULL) {
179210883Spjd		pjdlog_error("Unable to allocate memory for configuration.");
180210883Spjd		if (exitonerror)
181210883Spjd			exit(EX_TEMPFAIL);
182210883Spjd		return (NULL);
183210883Spjd	}
184204076Spjd
185210883Spjd	TAILQ_INIT(&lconfig->hc_resources);
186210883Spjd
187204076Spjd	yyin = fopen(config, "r");
188210883Spjd	if (yyin == NULL) {
189210883Spjd		pjdlog_errno(LOG_ERR, "Unable to open configuration file %s",
190210883Spjd		    config);
191210883Spjd		yy_config_free(lconfig);
192210883Spjd		if (exitonerror)
193210883Spjd			exit(EX_OSFILE);
194210883Spjd		return (NULL);
195210883Spjd	}
196210883Spjd	yyrestart(yyin);
197204076Spjd	ret = yyparse();
198204076Spjd	fclose(yyin);
199204076Spjd	if (ret != 0) {
200210883Spjd		yy_config_free(lconfig);
201210883Spjd		if (exitonerror)
202210883Spjd			exit(EX_CONFIG);
203210883Spjd		return (NULL);
204204076Spjd	}
205204076Spjd
206204076Spjd	/*
207204076Spjd	 * Let's see if everything is set up.
208204076Spjd	 */
209210883Spjd	if (lconfig->hc_controladdr[0] == '\0') {
210210883Spjd		strlcpy(lconfig->hc_controladdr, depth0_control,
211210883Spjd		    sizeof(lconfig->hc_controladdr));
212204076Spjd	}
213210883Spjd	if (lconfig->hc_listenaddr[0] == '\0') {
214210883Spjd		strlcpy(lconfig->hc_listenaddr, depth0_listen,
215210883Spjd		    sizeof(lconfig->hc_listenaddr));
216204076Spjd	}
217210883Spjd	TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) {
218204076Spjd		assert(curres->hr_provname[0] != '\0');
219204076Spjd		assert(curres->hr_localpath[0] != '\0');
220204076Spjd		assert(curres->hr_remoteaddr[0] != '\0');
221204076Spjd
222204076Spjd		if (curres->hr_replication == -1) {
223204076Spjd			/*
224204076Spjd			 * Replication is not set at resource-level.
225204076Spjd			 * Use global or default setting.
226204076Spjd			 */
227204076Spjd			curres->hr_replication = depth0_replication;
228204076Spjd		}
229219351Spjd		if (curres->hr_checksum == -1) {
230219351Spjd			/*
231219351Spjd			 * Checksum is not set at resource-level.
232219351Spjd			 * Use global or default setting.
233219351Spjd			 */
234219351Spjd			curres->hr_checksum = depth0_checksum;
235219351Spjd		}
236207371Spjd		if (curres->hr_timeout == -1) {
237207371Spjd			/*
238207371Spjd			 * Timeout is not set at resource-level.
239207371Spjd			 * Use global or default setting.
240207371Spjd			 */
241207371Spjd			curres->hr_timeout = depth0_timeout;
242207371Spjd		}
243211886Spjd		if (curres->hr_exec[0] == '\0') {
244211886Spjd			/*
245211886Spjd			 * Exec is not set at resource-level.
246211886Spjd			 * Use global or default setting.
247211886Spjd			 */
248211886Spjd			strlcpy(curres->hr_exec, depth0_exec,
249211886Spjd			    sizeof(curres->hr_exec));
250211886Spjd		}
251204076Spjd	}
252204076Spjd
253210883Spjd	return (lconfig);
254204076Spjd}
255204076Spjd
256204076Spjdvoid
257204076Spjdyy_config_free(struct hastd_config *config)
258204076Spjd{
259204076Spjd	struct hast_resource *res;
260204076Spjd
261204076Spjd	while ((res = TAILQ_FIRST(&config->hc_resources)) != NULL) {
262204076Spjd		TAILQ_REMOVE(&config->hc_resources, res, hr_next);
263204076Spjd		free(res);
264204076Spjd	}
265210883Spjd	free(config);
266204076Spjd}
267204076Spjd%}
268204076Spjd
269219351Spjd%token CONTROL LISTEN PORT REPLICATION CHECKSUM
270219351Spjd%token TIMEOUT EXEC EXTENTSIZE RESOURCE NAME LOCAL REMOTE ON
271219351Spjd%token FULLSYNC MEMSYNC ASYNC NONE CRC32 SHA256
272204076Spjd%token NUM STR OB CB
273204076Spjd
274204076Spjd%type <num> replication_type
275219351Spjd%type <num> checksum_type
276204076Spjd
277204076Spjd%union
278204076Spjd{
279204076Spjd	int num;
280204076Spjd	char *str;
281204076Spjd}
282204076Spjd
283204076Spjd%token <num> NUM
284204076Spjd%token <str> STR
285204076Spjd
286204076Spjd%%
287204076Spjd
288204076Spjdstatements:
289204076Spjd	|
290204076Spjd	statements statement
291204076Spjd	;
292204076Spjd
293204076Spjdstatement:
294204076Spjd	control_statement
295204076Spjd	|
296204076Spjd	listen_statement
297204076Spjd	|
298204076Spjd	replication_statement
299204076Spjd	|
300219351Spjd	checksum_statement
301219351Spjd	|
302207371Spjd	timeout_statement
303207371Spjd	|
304211886Spjd	exec_statement
305211886Spjd	|
306204076Spjd	node_statement
307204076Spjd	|
308204076Spjd	resource_statement
309204076Spjd	;
310204076Spjd
311204076Spjdcontrol_statement:	CONTROL STR
312204076Spjd	{
313204076Spjd		switch (depth) {
314204076Spjd		case 0:
315204076Spjd			if (strlcpy(depth0_control, $2,
316204076Spjd			    sizeof(depth0_control)) >=
317204076Spjd			    sizeof(depth0_control)) {
318210883Spjd				pjdlog_error("control argument is too long.");
319214274Spjd				free($2);
320210883Spjd				return (1);
321204076Spjd			}
322204076Spjd			break;
323204076Spjd		case 1:
324211883Spjd			if (!mynode)
325211883Spjd				break;
326211883Spjd			if (strlcpy(lconfig->hc_controladdr, $2,
327211883Spjd			    sizeof(lconfig->hc_controladdr)) >=
328211883Spjd			    sizeof(lconfig->hc_controladdr)) {
329211883Spjd				pjdlog_error("control argument is too long.");
330214274Spjd				free($2);
331211883Spjd				return (1);
332204076Spjd			}
333204076Spjd			break;
334204076Spjd		default:
335204076Spjd			assert(!"control at wrong depth level");
336204076Spjd		}
337214274Spjd		free($2);
338204076Spjd	}
339204076Spjd	;
340204076Spjd
341204076Spjdlisten_statement:	LISTEN STR
342204076Spjd	{
343204076Spjd		switch (depth) {
344204076Spjd		case 0:
345204076Spjd			if (strlcpy(depth0_listen, $2,
346204076Spjd			    sizeof(depth0_listen)) >=
347204076Spjd			    sizeof(depth0_listen)) {
348210883Spjd				pjdlog_error("listen argument is too long.");
349214274Spjd				free($2);
350210883Spjd				return (1);
351204076Spjd			}
352204076Spjd			break;
353204076Spjd		case 1:
354211883Spjd			if (!mynode)
355211883Spjd				break;
356211883Spjd			if (strlcpy(lconfig->hc_listenaddr, $2,
357211883Spjd			    sizeof(lconfig->hc_listenaddr)) >=
358211883Spjd			    sizeof(lconfig->hc_listenaddr)) {
359211883Spjd				pjdlog_error("listen argument is too long.");
360214274Spjd				free($2);
361211883Spjd				return (1);
362204076Spjd			}
363204076Spjd			break;
364204076Spjd		default:
365204076Spjd			assert(!"listen at wrong depth level");
366204076Spjd		}
367214274Spjd		free($2);
368204076Spjd	}
369204076Spjd	;
370204076Spjd
371204076Spjdreplication_statement:	REPLICATION replication_type
372204076Spjd	{
373204076Spjd		switch (depth) {
374204076Spjd		case 0:
375204076Spjd			depth0_replication = $2;
376204076Spjd			break;
377204076Spjd		case 1:
378204076Spjd			if (curres != NULL)
379204076Spjd				curres->hr_replication = $2;
380204076Spjd			break;
381204076Spjd		default:
382204076Spjd			assert(!"replication at wrong depth level");
383204076Spjd		}
384204076Spjd	}
385204076Spjd	;
386204076Spjd
387204076Spjdreplication_type:
388204076Spjd	FULLSYNC	{ $$ = HAST_REPLICATION_FULLSYNC; }
389204076Spjd	|
390204076Spjd	MEMSYNC		{ $$ = HAST_REPLICATION_MEMSYNC; }
391204076Spjd	|
392204076Spjd	ASYNC		{ $$ = HAST_REPLICATION_ASYNC; }
393204076Spjd	;
394204076Spjd
395219351Spjdchecksum_statement:	CHECKSUM checksum_type
396219351Spjd	{
397219351Spjd		switch (depth) {
398219351Spjd		case 0:
399219351Spjd			depth0_checksum = $2;
400219351Spjd			break;
401219351Spjd		case 1:
402219351Spjd			if (curres != NULL)
403219351Spjd				curres->hr_checksum = $2;
404219351Spjd			break;
405219351Spjd		default:
406219351Spjd			assert(!"checksum at wrong depth level");
407219351Spjd		}
408219351Spjd	}
409219351Spjd	;
410219351Spjd
411219351Spjdchecksum_type:
412219351Spjd	NONE		{ $$ = HAST_CHECKSUM_NONE; }
413219351Spjd	|
414219351Spjd	CRC32		{ $$ = HAST_CHECKSUM_CRC32; }
415219351Spjd	|
416219351Spjd	SHA256		{ $$ = HAST_CHECKSUM_SHA256; }
417219351Spjd	;
418219351Spjd
419207371Spjdtimeout_statement:	TIMEOUT NUM
420207371Spjd	{
421207371Spjd		switch (depth) {
422207371Spjd		case 0:
423207371Spjd			depth0_timeout = $2;
424207371Spjd			break;
425207371Spjd		case 1:
426207371Spjd			if (curres != NULL)
427207371Spjd				curres->hr_timeout = $2;
428207371Spjd			break;
429207371Spjd		default:
430207371Spjd			assert(!"timeout at wrong depth level");
431207371Spjd		}
432207371Spjd	}
433207371Spjd	;
434207371Spjd
435211886Spjdexec_statement:		EXEC STR
436211886Spjd	{
437211886Spjd		switch (depth) {
438211886Spjd		case 0:
439211886Spjd			if (strlcpy(depth0_exec, $2, sizeof(depth0_exec)) >=
440211886Spjd			    sizeof(depth0_exec)) {
441211886Spjd				pjdlog_error("Exec path is too long.");
442214274Spjd				free($2);
443211886Spjd				return (1);
444211886Spjd			}
445211886Spjd			break;
446211886Spjd		case 1:
447211886Spjd			if (curres == NULL)
448211886Spjd				break;
449211886Spjd			if (strlcpy(curres->hr_exec, $2,
450211886Spjd			    sizeof(curres->hr_exec)) >=
451211886Spjd			    sizeof(curres->hr_exec)) {
452211886Spjd				pjdlog_error("Exec path is too long.");
453214274Spjd				free($2);
454211886Spjd				return (1);
455211886Spjd			}
456211886Spjd			break;
457211886Spjd		default:
458211886Spjd			assert(!"exec at wrong depth level");
459211886Spjd		}
460214274Spjd		free($2);
461211886Spjd	}
462211886Spjd	;
463211886Spjd
464204076Spjdnode_statement:		ON node_start OB node_entries CB
465204076Spjd	{
466204076Spjd		mynode = false;
467204076Spjd	}
468204076Spjd	;
469204076Spjd
470204076Spjdnode_start:	STR
471204076Spjd	{
472210883Spjd		switch (isitme($1)) {
473210883Spjd		case -1:
474214274Spjd			free($1);
475210883Spjd			return (1);
476210883Spjd		case 0:
477210883Spjd			break;
478210883Spjd		case 1:
479204076Spjd			mynode = true;
480210883Spjd			break;
481210883Spjd		default:
482210883Spjd			assert(!"invalid isitme() return value");
483210883Spjd		}
484214274Spjd		free($1);
485204076Spjd	}
486204076Spjd	;
487204076Spjd
488204076Spjdnode_entries:
489204076Spjd	|
490204076Spjd	node_entries node_entry
491204076Spjd	;
492204076Spjd
493204076Spjdnode_entry:
494204076Spjd	control_statement
495204076Spjd	|
496204076Spjd	listen_statement
497204076Spjd	;
498204076Spjd
499204076Spjdresource_statement:	RESOURCE resource_start OB resource_entries CB
500204076Spjd	{
501204076Spjd		if (curres != NULL) {
502204076Spjd			/*
503216721Spjd			 * There must be section for this node, at least with
504216721Spjd			 * remote address configuration.
505216721Spjd			 */
506216721Spjd			if (!hadmynode) {
507216721Spjd				char *names;
508216721Spjd
509216721Spjd				if (node_names(&names) != 0)
510216721Spjd					return (1);
511216721Spjd				pjdlog_error("No resource %s configuration for this node (acceptable node names: %s).",
512216721Spjd				    curres->hr_name, names);
513216721Spjd				return (1);
514216721Spjd			}
515216721Spjd
516216721Spjd			/*
517204076Spjd			 * Let's see there are some resource-level settings
518204076Spjd			 * that we can use for node-level settings.
519204076Spjd			 */
520204076Spjd			if (curres->hr_provname[0] == '\0' &&
521204076Spjd			    depth1_provname[0] != '\0') {
522204076Spjd				/*
523204076Spjd				 * Provider name is not set at node-level,
524204076Spjd				 * but is set at resource-level, use it.
525204076Spjd				 */
526204076Spjd				strlcpy(curres->hr_provname, depth1_provname,
527204076Spjd				    sizeof(curres->hr_provname));
528204076Spjd			}
529204076Spjd			if (curres->hr_localpath[0] == '\0' &&
530204076Spjd			    depth1_localpath[0] != '\0') {
531204076Spjd				/*
532204076Spjd				 * Path to local provider is not set at
533204076Spjd				 * node-level, but is set at resource-level,
534204076Spjd				 * use it.
535204076Spjd				 */
536204076Spjd				strlcpy(curres->hr_localpath, depth1_localpath,
537204076Spjd				    sizeof(curres->hr_localpath));
538204076Spjd			}
539204076Spjd
540204076Spjd			/*
541204076Spjd			 * If provider name is not given, use resource name
542204076Spjd			 * as provider name.
543204076Spjd			 */
544204076Spjd			if (curres->hr_provname[0] == '\0') {
545204076Spjd				strlcpy(curres->hr_provname, curres->hr_name,
546204076Spjd				    sizeof(curres->hr_provname));
547204076Spjd			}
548204076Spjd
549204076Spjd			/*
550204076Spjd			 * Remote address has to be configured at this point.
551204076Spjd			 */
552204076Spjd			if (curres->hr_remoteaddr[0] == '\0') {
553210883Spjd				pjdlog_error("Remote address not configured for resource %s.",
554204076Spjd				    curres->hr_name);
555210883Spjd				return (1);
556204076Spjd			}
557204076Spjd			/*
558204076Spjd			 * Path to local provider has to be configured at this
559204076Spjd			 * point.
560204076Spjd			 */
561204076Spjd			if (curres->hr_localpath[0] == '\0') {
562210883Spjd				pjdlog_error("Path to local component not configured for resource %s.",
563204076Spjd				    curres->hr_name);
564210883Spjd				return (1);
565204076Spjd			}
566204076Spjd
567204076Spjd			/* Put it onto resource list. */
568210883Spjd			TAILQ_INSERT_TAIL(&lconfig->hc_resources, curres, hr_next);
569204076Spjd			curres = NULL;
570204076Spjd		}
571204076Spjd	}
572204076Spjd	;
573204076Spjd
574204076Spjdresource_start:	STR
575204076Spjd	{
576216722Spjd		/* Check if there is no duplicate entry. */
577216722Spjd		TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) {
578216722Spjd			if (strcmp(curres->hr_name, $1) == 0) {
579216722Spjd				pjdlog_error("Resource %s configured more than once.",
580216722Spjd				    curres->hr_name);
581216722Spjd				free($1);
582216722Spjd				return (1);
583216722Spjd			}
584216722Spjd		}
585216722Spjd
586204076Spjd		/*
587204076Spjd		 * Clear those, so we can tell if they were set at
588204076Spjd		 * resource-level or not.
589204076Spjd		 */
590204076Spjd		depth1_provname[0] = '\0';
591204076Spjd		depth1_localpath[0] = '\0';
592216721Spjd		hadmynode = false;
593204076Spjd
594204076Spjd		curres = calloc(1, sizeof(*curres));
595204076Spjd		if (curres == NULL) {
596210883Spjd			pjdlog_error("Unable to allocate memory for resource.");
597214274Spjd			free($1);
598210883Spjd			return (1);
599204076Spjd		}
600204076Spjd		if (strlcpy(curres->hr_name, $1,
601204076Spjd		    sizeof(curres->hr_name)) >=
602204076Spjd		    sizeof(curres->hr_name)) {
603210883Spjd			pjdlog_error("Resource name is too long.");
604214274Spjd			free($1);
605210883Spjd			return (1);
606204076Spjd		}
607214274Spjd		free($1);
608204076Spjd		curres->hr_role = HAST_ROLE_INIT;
609204076Spjd		curres->hr_previous_role = HAST_ROLE_INIT;
610204076Spjd		curres->hr_replication = -1;
611219351Spjd		curres->hr_checksum = -1;
612207371Spjd		curres->hr_timeout = -1;
613211886Spjd		curres->hr_exec[0] = '\0';
614204076Spjd		curres->hr_provname[0] = '\0';
615204076Spjd		curres->hr_localpath[0] = '\0';
616204076Spjd		curres->hr_localfd = -1;
617204076Spjd		curres->hr_remoteaddr[0] = '\0';
618204076Spjd		curres->hr_ggateunit = -1;
619204076Spjd	}
620204076Spjd	;
621204076Spjd
622204076Spjdresource_entries:
623204076Spjd	|
624204076Spjd	resource_entries resource_entry
625204076Spjd	;
626204076Spjd
627204076Spjdresource_entry:
628204076Spjd	replication_statement
629204076Spjd	|
630219351Spjd	checksum_statement
631219351Spjd	|
632207371Spjd	timeout_statement
633207371Spjd	|
634211886Spjd	exec_statement
635211886Spjd	|
636204076Spjd	name_statement
637204076Spjd	|
638204076Spjd	local_statement
639204076Spjd	|
640204076Spjd	resource_node_statement
641204076Spjd	;
642204076Spjd
643204076Spjdname_statement:		NAME STR
644204076Spjd	{
645204076Spjd		switch (depth) {
646204076Spjd		case 1:
647204076Spjd			if (strlcpy(depth1_provname, $2,
648204076Spjd			    sizeof(depth1_provname)) >=
649204076Spjd			    sizeof(depth1_provname)) {
650210883Spjd				pjdlog_error("name argument is too long.");
651214274Spjd				free($2);
652210883Spjd				return (1);
653204076Spjd			}
654204076Spjd			break;
655204076Spjd		case 2:
656211883Spjd			if (!mynode)
657211883Spjd				break;
658211883Spjd			assert(curres != NULL);
659211883Spjd			if (strlcpy(curres->hr_provname, $2,
660211883Spjd			    sizeof(curres->hr_provname)) >=
661211883Spjd			    sizeof(curres->hr_provname)) {
662211883Spjd				pjdlog_error("name argument is too long.");
663214274Spjd				free($2);
664211883Spjd				return (1);
665204076Spjd			}
666204076Spjd			break;
667204076Spjd		default:
668204076Spjd			assert(!"name at wrong depth level");
669204076Spjd		}
670214274Spjd		free($2);
671204076Spjd	}
672204076Spjd	;
673204076Spjd
674204076Spjdlocal_statement:	LOCAL STR
675204076Spjd	{
676204076Spjd		switch (depth) {
677204076Spjd		case 1:
678204076Spjd			if (strlcpy(depth1_localpath, $2,
679204076Spjd			    sizeof(depth1_localpath)) >=
680204076Spjd			    sizeof(depth1_localpath)) {
681210883Spjd				pjdlog_error("local argument is too long.");
682214274Spjd				free($2);
683210883Spjd				return (1);
684204076Spjd			}
685204076Spjd			break;
686204076Spjd		case 2:
687211883Spjd			if (!mynode)
688211883Spjd				break;
689211883Spjd			assert(curres != NULL);
690211883Spjd			if (strlcpy(curres->hr_localpath, $2,
691211883Spjd			    sizeof(curres->hr_localpath)) >=
692211883Spjd			    sizeof(curres->hr_localpath)) {
693211883Spjd				pjdlog_error("local argument is too long.");
694214274Spjd				free($2);
695211883Spjd				return (1);
696204076Spjd			}
697204076Spjd			break;
698204076Spjd		default:
699204076Spjd			assert(!"local at wrong depth level");
700204076Spjd		}
701214274Spjd		free($2);
702204076Spjd	}
703204076Spjd	;
704204076Spjd
705204076Spjdresource_node_statement:ON resource_node_start OB resource_node_entries CB
706204076Spjd	{
707204076Spjd		mynode = false;
708204076Spjd	}
709204076Spjd	;
710204076Spjd
711204076Spjdresource_node_start:	STR
712204076Spjd	{
713210883Spjd		if (curres != NULL) {
714210883Spjd			switch (isitme($1)) {
715210883Spjd			case -1:
716214274Spjd				free($1);
717210883Spjd				return (1);
718210883Spjd			case 0:
719210883Spjd				break;
720210883Spjd			case 1:
721216721Spjd				mynode = hadmynode = true;
722210883Spjd				break;
723210883Spjd			default:
724210883Spjd				assert(!"invalid isitme() return value");
725210883Spjd			}
726210883Spjd		}
727214274Spjd		free($1);
728204076Spjd	}
729204076Spjd	;
730204076Spjd
731204076Spjdresource_node_entries:
732204076Spjd	|
733204076Spjd	resource_node_entries resource_node_entry
734204076Spjd	;
735204076Spjd
736204076Spjdresource_node_entry:
737204076Spjd	name_statement
738204076Spjd	|
739204076Spjd	local_statement
740204076Spjd	|
741204076Spjd	remote_statement
742204076Spjd	;
743204076Spjd
744204076Spjdremote_statement:	REMOTE STR
745204076Spjd	{
746204076Spjd		assert(depth == 2);
747204076Spjd		if (mynode) {
748204076Spjd			assert(curres != NULL);
749204076Spjd			if (strlcpy(curres->hr_remoteaddr, $2,
750204076Spjd			    sizeof(curres->hr_remoteaddr)) >=
751204076Spjd			    sizeof(curres->hr_remoteaddr)) {
752210883Spjd				pjdlog_error("remote argument is too long.");
753214274Spjd				free($2);
754210883Spjd				return (1);
755204076Spjd			}
756204076Spjd		}
757214274Spjd		free($2);
758204076Spjd	}
759204076Spjd	;
760