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