xref: /freebsd/sbin/hastd/parse.y (revision c2bce4a2fcf3083607e00a1734b47c249751c8a8)
1 %{
2 /*-
3  * Copyright (c) 2009-2010 The FreeBSD Foundation
4  * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>
5  * All rights reserved.
6  *
7  * This software was developed by Pawel Jakub Dawidek under sponsorship from
8  * the FreeBSD Foundation.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  * $FreeBSD$
32  */
33 
34 #include <sys/param.h>	/* MAXHOSTNAMELEN */
35 #include <sys/queue.h>
36 #include <sys/sysctl.h>
37 
38 #include <arpa/inet.h>
39 
40 #include <assert.h>
41 #include <err.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <sysexits.h>
45 #include <unistd.h>
46 
47 #include <pjdlog.h>
48 
49 #include "hast.h"
50 
51 extern int depth;
52 extern int lineno;
53 
54 extern FILE *yyin;
55 extern char *yytext;
56 
57 static struct hastd_config *lconfig;
58 static struct hast_resource *curres;
59 static bool mynode, hadmynode;
60 
61 static char depth0_control[HAST_ADDRSIZE];
62 static char depth0_listen[HAST_ADDRSIZE];
63 static int depth0_replication;
64 static int depth0_checksum;
65 static int depth0_compression;
66 static int depth0_timeout;
67 static char depth0_exec[PATH_MAX];
68 
69 static char depth1_provname[PATH_MAX];
70 static char depth1_localpath[PATH_MAX];
71 
72 extern void yyrestart(FILE *);
73 
74 static int
75 isitme(const char *name)
76 {
77 	char buf[MAXHOSTNAMELEN];
78 	char *pos;
79 	size_t bufsize;
80 
81 	/*
82 	 * First check if the give name matches our full hostname.
83 	 */
84 	if (gethostname(buf, sizeof(buf)) < 0) {
85 		pjdlog_errno(LOG_ERR, "gethostname() failed");
86 		return (-1);
87 	}
88 	if (strcmp(buf, name) == 0)
89 		return (1);
90 
91 	/*
92 	 * Now check if it matches first part of the host name.
93 	 */
94 	pos = strchr(buf, '.');
95 	if (pos != NULL && pos != buf && strncmp(buf, name, pos - buf) == 0)
96 		return (1);
97 
98 	/*
99 	 * At the end check if name is equal to our host's UUID.
100 	 */
101 	bufsize = sizeof(buf);
102 	if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) {
103 		pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed");
104 		return (-1);
105 	}
106 	if (strcasecmp(buf, name) == 0)
107 		return (1);
108 
109 	/*
110 	 * Looks like this isn't about us.
111 	 */
112 	return (0);
113 }
114 
115 static int
116 node_names(char **namesp)
117 {
118 	static char names[MAXHOSTNAMELEN * 3];
119 	char buf[MAXHOSTNAMELEN];
120 	char *pos;
121 	size_t bufsize;
122 
123 	if (gethostname(buf, sizeof(buf)) < 0) {
124 		pjdlog_errno(LOG_ERR, "gethostname() failed");
125 		return (-1);
126 	}
127 
128 	/* First component of the host name. */
129 	pos = strchr(buf, '.');
130 	if (pos != NULL && pos != buf) {
131 		(void)strlcpy(names, buf, MIN((size_t)(pos - buf + 1),
132 		    sizeof(names)));
133 		(void)strlcat(names, ", ", sizeof(names));
134 	}
135 
136 	/* Full host name. */
137 	(void)strlcat(names, buf, sizeof(names));
138 	(void)strlcat(names, ", ", sizeof(names));
139 
140 	/* Host UUID. */
141 	bufsize = sizeof(buf);
142 	if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) {
143 		pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed");
144 		return (-1);
145 	}
146 	(void)strlcat(names, buf, sizeof(names));
147 
148 	*namesp = names;
149 
150 	return (0);
151 }
152 
153 void
154 yyerror(const char *str)
155 {
156 
157 	pjdlog_error("Unable to parse configuration file at line %d near '%s': %s",
158 	    lineno, yytext, str);
159 }
160 
161 struct hastd_config *
162 yy_config_parse(const char *config, bool exitonerror)
163 {
164 	int ret;
165 
166 	curres = NULL;
167 	mynode = false;
168 	depth = 0;
169 	lineno = 0;
170 
171 	depth0_timeout = HAST_TIMEOUT;
172 	depth0_replication = HAST_REPLICATION_FULLSYNC;
173 	depth0_checksum = HAST_CHECKSUM_NONE;
174 	depth0_compression = HAST_COMPRESSION_HOLE;
175 	strlcpy(depth0_control, HAST_CONTROL, sizeof(depth0_control));
176 	strlcpy(depth0_listen, HASTD_LISTEN, sizeof(depth0_listen));
177 	depth0_exec[0] = '\0';
178 
179 	lconfig = calloc(1, sizeof(*lconfig));
180 	if (lconfig == NULL) {
181 		pjdlog_error("Unable to allocate memory for configuration.");
182 		if (exitonerror)
183 			exit(EX_TEMPFAIL);
184 		return (NULL);
185 	}
186 
187 	TAILQ_INIT(&lconfig->hc_resources);
188 
189 	yyin = fopen(config, "r");
190 	if (yyin == NULL) {
191 		pjdlog_errno(LOG_ERR, "Unable to open configuration file %s",
192 		    config);
193 		yy_config_free(lconfig);
194 		if (exitonerror)
195 			exit(EX_OSFILE);
196 		return (NULL);
197 	}
198 	yyrestart(yyin);
199 	ret = yyparse();
200 	fclose(yyin);
201 	if (ret != 0) {
202 		yy_config_free(lconfig);
203 		if (exitonerror)
204 			exit(EX_CONFIG);
205 		return (NULL);
206 	}
207 
208 	/*
209 	 * Let's see if everything is set up.
210 	 */
211 	if (lconfig->hc_controladdr[0] == '\0') {
212 		strlcpy(lconfig->hc_controladdr, depth0_control,
213 		    sizeof(lconfig->hc_controladdr));
214 	}
215 	if (lconfig->hc_listenaddr[0] == '\0') {
216 		strlcpy(lconfig->hc_listenaddr, depth0_listen,
217 		    sizeof(lconfig->hc_listenaddr));
218 	}
219 	TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) {
220 		assert(curres->hr_provname[0] != '\0');
221 		assert(curres->hr_localpath[0] != '\0');
222 		assert(curres->hr_remoteaddr[0] != '\0');
223 
224 		if (curres->hr_replication == -1) {
225 			/*
226 			 * Replication is not set at resource-level.
227 			 * Use global or default setting.
228 			 */
229 			curres->hr_replication = depth0_replication;
230 		}
231 		if (curres->hr_replication == HAST_REPLICATION_MEMSYNC ||
232 		    curres->hr_replication == HAST_REPLICATION_ASYNC) {
233 			pjdlog_warning("Replication mode \"%s\" is not implemented, falling back to \"%s\".",
234 			    curres->hr_replication == HAST_REPLICATION_MEMSYNC ?
235 			    "memsync" : "async", "fullsync");
236 			curres->hr_replication = HAST_REPLICATION_FULLSYNC;
237 		}
238 		if (curres->hr_checksum == -1) {
239 			/*
240 			 * Checksum is not set at resource-level.
241 			 * Use global or default setting.
242 			 */
243 			curres->hr_checksum = depth0_checksum;
244 		}
245 		if (curres->hr_compression == -1) {
246 			/*
247 			 * Compression is not set at resource-level.
248 			 * Use global or default setting.
249 			 */
250 			curres->hr_compression = depth0_compression;
251 		}
252 		if (curres->hr_timeout == -1) {
253 			/*
254 			 * Timeout is not set at resource-level.
255 			 * Use global or default setting.
256 			 */
257 			curres->hr_timeout = depth0_timeout;
258 		}
259 		if (curres->hr_exec[0] == '\0') {
260 			/*
261 			 * Exec is not set at resource-level.
262 			 * Use global or default setting.
263 			 */
264 			strlcpy(curres->hr_exec, depth0_exec,
265 			    sizeof(curres->hr_exec));
266 		}
267 	}
268 
269 	return (lconfig);
270 }
271 
272 void
273 yy_config_free(struct hastd_config *config)
274 {
275 	struct hast_resource *res;
276 
277 	while ((res = TAILQ_FIRST(&config->hc_resources)) != NULL) {
278 		TAILQ_REMOVE(&config->hc_resources, res, hr_next);
279 		free(res);
280 	}
281 	free(config);
282 }
283 %}
284 
285 %token CONTROL LISTEN PORT REPLICATION CHECKSUM COMPRESSION
286 %token TIMEOUT EXEC EXTENTSIZE RESOURCE NAME LOCAL REMOTE SOURCE ON
287 %token FULLSYNC MEMSYNC ASYNC NONE CRC32 SHA256 HOLE LZF
288 %token NUM STR OB CB
289 
290 %type <num> replication_type
291 %type <num> checksum_type
292 %type <num> compression_type
293 
294 %union
295 {
296 	int num;
297 	char *str;
298 }
299 
300 %token <num> NUM
301 %token <str> STR
302 
303 %%
304 
305 statements:
306 	|
307 	statements statement
308 	;
309 
310 statement:
311 	control_statement
312 	|
313 	listen_statement
314 	|
315 	replication_statement
316 	|
317 	checksum_statement
318 	|
319 	compression_statement
320 	|
321 	timeout_statement
322 	|
323 	exec_statement
324 	|
325 	node_statement
326 	|
327 	resource_statement
328 	;
329 
330 control_statement:	CONTROL STR
331 	{
332 		switch (depth) {
333 		case 0:
334 			if (strlcpy(depth0_control, $2,
335 			    sizeof(depth0_control)) >=
336 			    sizeof(depth0_control)) {
337 				pjdlog_error("control argument is too long.");
338 				free($2);
339 				return (1);
340 			}
341 			break;
342 		case 1:
343 			if (!mynode)
344 				break;
345 			if (strlcpy(lconfig->hc_controladdr, $2,
346 			    sizeof(lconfig->hc_controladdr)) >=
347 			    sizeof(lconfig->hc_controladdr)) {
348 				pjdlog_error("control argument is too long.");
349 				free($2);
350 				return (1);
351 			}
352 			break;
353 		default:
354 			assert(!"control at wrong depth level");
355 		}
356 		free($2);
357 	}
358 	;
359 
360 listen_statement:	LISTEN STR
361 	{
362 		switch (depth) {
363 		case 0:
364 			if (strlcpy(depth0_listen, $2,
365 			    sizeof(depth0_listen)) >=
366 			    sizeof(depth0_listen)) {
367 				pjdlog_error("listen argument is too long.");
368 				free($2);
369 				return (1);
370 			}
371 			break;
372 		case 1:
373 			if (!mynode)
374 				break;
375 			if (strlcpy(lconfig->hc_listenaddr, $2,
376 			    sizeof(lconfig->hc_listenaddr)) >=
377 			    sizeof(lconfig->hc_listenaddr)) {
378 				pjdlog_error("listen argument is too long.");
379 				free($2);
380 				return (1);
381 			}
382 			break;
383 		default:
384 			assert(!"listen at wrong depth level");
385 		}
386 		free($2);
387 	}
388 	;
389 
390 replication_statement:	REPLICATION replication_type
391 	{
392 		switch (depth) {
393 		case 0:
394 			depth0_replication = $2;
395 			break;
396 		case 1:
397 			if (curres != NULL)
398 				curres->hr_replication = $2;
399 			break;
400 		default:
401 			assert(!"replication at wrong depth level");
402 		}
403 	}
404 	;
405 
406 replication_type:
407 	FULLSYNC	{ $$ = HAST_REPLICATION_FULLSYNC; }
408 	|
409 	MEMSYNC		{ $$ = HAST_REPLICATION_MEMSYNC; }
410 	|
411 	ASYNC		{ $$ = HAST_REPLICATION_ASYNC; }
412 	;
413 
414 checksum_statement:	CHECKSUM checksum_type
415 	{
416 		switch (depth) {
417 		case 0:
418 			depth0_checksum = $2;
419 			break;
420 		case 1:
421 			if (curres != NULL)
422 				curres->hr_checksum = $2;
423 			break;
424 		default:
425 			assert(!"checksum at wrong depth level");
426 		}
427 	}
428 	;
429 
430 checksum_type:
431 	NONE		{ $$ = HAST_CHECKSUM_NONE; }
432 	|
433 	CRC32		{ $$ = HAST_CHECKSUM_CRC32; }
434 	|
435 	SHA256		{ $$ = HAST_CHECKSUM_SHA256; }
436 	;
437 
438 compression_statement:	COMPRESSION compression_type
439 	{
440 		switch (depth) {
441 		case 0:
442 			depth0_compression = $2;
443 			break;
444 		case 1:
445 			if (curres != NULL)
446 				curres->hr_compression = $2;
447 			break;
448 		default:
449 			assert(!"compression at wrong depth level");
450 		}
451 	}
452 	;
453 
454 compression_type:
455 	NONE		{ $$ = HAST_COMPRESSION_NONE; }
456 	|
457 	HOLE		{ $$ = HAST_COMPRESSION_HOLE; }
458 	|
459 	LZF		{ $$ = HAST_COMPRESSION_LZF; }
460 	;
461 
462 timeout_statement:	TIMEOUT NUM
463 	{
464 		if ($2 <= 0) {
465 			pjdlog_error("Negative or zero timeout.");
466 			return (1);
467 		}
468 		switch (depth) {
469 		case 0:
470 			depth0_timeout = $2;
471 			break;
472 		case 1:
473 			if (curres != NULL)
474 				curres->hr_timeout = $2;
475 			break;
476 		default:
477 			assert(!"timeout at wrong depth level");
478 		}
479 	}
480 	;
481 
482 exec_statement:		EXEC STR
483 	{
484 		switch (depth) {
485 		case 0:
486 			if (strlcpy(depth0_exec, $2, sizeof(depth0_exec)) >=
487 			    sizeof(depth0_exec)) {
488 				pjdlog_error("Exec path is too long.");
489 				free($2);
490 				return (1);
491 			}
492 			break;
493 		case 1:
494 			if (curres == NULL)
495 				break;
496 			if (strlcpy(curres->hr_exec, $2,
497 			    sizeof(curres->hr_exec)) >=
498 			    sizeof(curres->hr_exec)) {
499 				pjdlog_error("Exec path is too long.");
500 				free($2);
501 				return (1);
502 			}
503 			break;
504 		default:
505 			assert(!"exec at wrong depth level");
506 		}
507 		free($2);
508 	}
509 	;
510 
511 node_statement:		ON node_start OB node_entries CB
512 	{
513 		mynode = false;
514 	}
515 	;
516 
517 node_start:	STR
518 	{
519 		switch (isitme($1)) {
520 		case -1:
521 			free($1);
522 			return (1);
523 		case 0:
524 			break;
525 		case 1:
526 			mynode = true;
527 			break;
528 		default:
529 			assert(!"invalid isitme() return value");
530 		}
531 		free($1);
532 	}
533 	;
534 
535 node_entries:
536 	|
537 	node_entries node_entry
538 	;
539 
540 node_entry:
541 	control_statement
542 	|
543 	listen_statement
544 	;
545 
546 resource_statement:	RESOURCE resource_start OB resource_entries CB
547 	{
548 		if (curres != NULL) {
549 			/*
550 			 * There must be section for this node, at least with
551 			 * remote address configuration.
552 			 */
553 			if (!hadmynode) {
554 				char *names;
555 
556 				if (node_names(&names) != 0)
557 					return (1);
558 				pjdlog_error("No resource %s configuration for this node (acceptable node names: %s).",
559 				    curres->hr_name, names);
560 				return (1);
561 			}
562 
563 			/*
564 			 * Let's see there are some resource-level settings
565 			 * that we can use for node-level settings.
566 			 */
567 			if (curres->hr_provname[0] == '\0' &&
568 			    depth1_provname[0] != '\0') {
569 				/*
570 				 * Provider name is not set at node-level,
571 				 * but is set at resource-level, use it.
572 				 */
573 				strlcpy(curres->hr_provname, depth1_provname,
574 				    sizeof(curres->hr_provname));
575 			}
576 			if (curres->hr_localpath[0] == '\0' &&
577 			    depth1_localpath[0] != '\0') {
578 				/*
579 				 * Path to local provider is not set at
580 				 * node-level, but is set at resource-level,
581 				 * use it.
582 				 */
583 				strlcpy(curres->hr_localpath, depth1_localpath,
584 				    sizeof(curres->hr_localpath));
585 			}
586 
587 			/*
588 			 * If provider name is not given, use resource name
589 			 * as provider name.
590 			 */
591 			if (curres->hr_provname[0] == '\0') {
592 				strlcpy(curres->hr_provname, curres->hr_name,
593 				    sizeof(curres->hr_provname));
594 			}
595 
596 			/*
597 			 * Remote address has to be configured at this point.
598 			 */
599 			if (curres->hr_remoteaddr[0] == '\0') {
600 				pjdlog_error("Remote address not configured for resource %s.",
601 				    curres->hr_name);
602 				return (1);
603 			}
604 			/*
605 			 * Path to local provider has to be configured at this
606 			 * point.
607 			 */
608 			if (curres->hr_localpath[0] == '\0') {
609 				pjdlog_error("Path to local component not configured for resource %s.",
610 				    curres->hr_name);
611 				return (1);
612 			}
613 
614 			/* Put it onto resource list. */
615 			TAILQ_INSERT_TAIL(&lconfig->hc_resources, curres, hr_next);
616 			curres = NULL;
617 		}
618 	}
619 	;
620 
621 resource_start:	STR
622 	{
623 		/* Check if there is no duplicate entry. */
624 		TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) {
625 			if (strcmp(curres->hr_name, $1) == 0) {
626 				pjdlog_error("Resource %s configured more than once.",
627 				    curres->hr_name);
628 				free($1);
629 				return (1);
630 			}
631 		}
632 
633 		/*
634 		 * Clear those, so we can tell if they were set at
635 		 * resource-level or not.
636 		 */
637 		depth1_provname[0] = '\0';
638 		depth1_localpath[0] = '\0';
639 		hadmynode = false;
640 
641 		curres = calloc(1, sizeof(*curres));
642 		if (curres == NULL) {
643 			pjdlog_error("Unable to allocate memory for resource.");
644 			free($1);
645 			return (1);
646 		}
647 		if (strlcpy(curres->hr_name, $1,
648 		    sizeof(curres->hr_name)) >=
649 		    sizeof(curres->hr_name)) {
650 			pjdlog_error("Resource name is too long.");
651 			free($1);
652 			return (1);
653 		}
654 		free($1);
655 		curres->hr_role = HAST_ROLE_INIT;
656 		curres->hr_previous_role = HAST_ROLE_INIT;
657 		curres->hr_replication = -1;
658 		curres->hr_checksum = -1;
659 		curres->hr_compression = -1;
660 		curres->hr_timeout = -1;
661 		curres->hr_exec[0] = '\0';
662 		curres->hr_provname[0] = '\0';
663 		curres->hr_localpath[0] = '\0';
664 		curres->hr_localfd = -1;
665 		curres->hr_remoteaddr[0] = '\0';
666 		curres->hr_sourceaddr[0] = '\0';
667 		curres->hr_ggateunit = -1;
668 	}
669 	;
670 
671 resource_entries:
672 	|
673 	resource_entries resource_entry
674 	;
675 
676 resource_entry:
677 	replication_statement
678 	|
679 	checksum_statement
680 	|
681 	compression_statement
682 	|
683 	timeout_statement
684 	|
685 	exec_statement
686 	|
687 	name_statement
688 	|
689 	local_statement
690 	|
691 	resource_node_statement
692 	;
693 
694 name_statement:		NAME STR
695 	{
696 		switch (depth) {
697 		case 1:
698 			if (strlcpy(depth1_provname, $2,
699 			    sizeof(depth1_provname)) >=
700 			    sizeof(depth1_provname)) {
701 				pjdlog_error("name argument is too long.");
702 				free($2);
703 				return (1);
704 			}
705 			break;
706 		case 2:
707 			if (!mynode)
708 				break;
709 			assert(curres != NULL);
710 			if (strlcpy(curres->hr_provname, $2,
711 			    sizeof(curres->hr_provname)) >=
712 			    sizeof(curres->hr_provname)) {
713 				pjdlog_error("name argument is too long.");
714 				free($2);
715 				return (1);
716 			}
717 			break;
718 		default:
719 			assert(!"name at wrong depth level");
720 		}
721 		free($2);
722 	}
723 	;
724 
725 local_statement:	LOCAL STR
726 	{
727 		switch (depth) {
728 		case 1:
729 			if (strlcpy(depth1_localpath, $2,
730 			    sizeof(depth1_localpath)) >=
731 			    sizeof(depth1_localpath)) {
732 				pjdlog_error("local argument is too long.");
733 				free($2);
734 				return (1);
735 			}
736 			break;
737 		case 2:
738 			if (!mynode)
739 				break;
740 			assert(curres != NULL);
741 			if (strlcpy(curres->hr_localpath, $2,
742 			    sizeof(curres->hr_localpath)) >=
743 			    sizeof(curres->hr_localpath)) {
744 				pjdlog_error("local argument is too long.");
745 				free($2);
746 				return (1);
747 			}
748 			break;
749 		default:
750 			assert(!"local at wrong depth level");
751 		}
752 		free($2);
753 	}
754 	;
755 
756 resource_node_statement:ON resource_node_start OB resource_node_entries CB
757 	{
758 		mynode = false;
759 	}
760 	;
761 
762 resource_node_start:	STR
763 	{
764 		if (curres != NULL) {
765 			switch (isitme($1)) {
766 			case -1:
767 				free($1);
768 				return (1);
769 			case 0:
770 				break;
771 			case 1:
772 				mynode = hadmynode = true;
773 				break;
774 			default:
775 				assert(!"invalid isitme() return value");
776 			}
777 		}
778 		free($1);
779 	}
780 	;
781 
782 resource_node_entries:
783 	|
784 	resource_node_entries resource_node_entry
785 	;
786 
787 resource_node_entry:
788 	name_statement
789 	|
790 	local_statement
791 	|
792 	remote_statement
793 	|
794 	source_statement
795 	;
796 
797 remote_statement:	REMOTE STR
798 	{
799 		assert(depth == 2);
800 		if (mynode) {
801 			assert(curres != NULL);
802 			if (strlcpy(curres->hr_remoteaddr, $2,
803 			    sizeof(curres->hr_remoteaddr)) >=
804 			    sizeof(curres->hr_remoteaddr)) {
805 				pjdlog_error("remote argument is too long.");
806 				free($2);
807 				return (1);
808 			}
809 		}
810 		free($2);
811 	}
812 	;
813 
814 source_statement:	SOURCE STR
815 	{
816 		assert(depth == 2);
817 		if (mynode) {
818 			assert(curres != NULL);
819 			if (strlcpy(curres->hr_sourceaddr, $2,
820 			    sizeof(curres->hr_sourceaddr)) >=
821 			    sizeof(curres->hr_sourceaddr)) {
822 				pjdlog_error("source argument is too long.");
823 				free($2);
824 				return (1);
825 			}
826 		}
827 		free($2);
828 	}
829 	;
830