1 %{
2 /*-
3 * Copyright (c) 2009-2010 The FreeBSD Foundation
4 * Copyright (c) 2010 Mikolaj Golub <to.my.trociny@gmail.com>
5 * All rights reserved.
6 *
7 * This software was developed by Mikolaj Golub. The source is derived
8 * from HAST developed by Pawel Jakub Dawidek under sponsorship from
9 * the FreeBSD Foundation.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * $FreeBSD$
33 */
34
35 #include <sys/param.h> /* MAXHOSTNAMELEN */
36 #ifdef HAVE_DEFINE_TAILQ_FOREACH_SAFE_SYS_QUEUE_H
37 #include <sys/queue.h>
38 #else
39 #include "queue.h"
40 #endif
41 #include <sys/sysctl.h>
42
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45
46 #include <err.h>
47 #include <stdio.h>
48 #include <string.h>
49 #include <sysexits.h>
50 #include <unistd.h>
51
52 #include <pjdlog.h>
53
54 #include "auth.h"
55 #include "hast.h"
56
57 extern int depth;
58 extern int lineno;
59
60 extern FILE *yyin;
61 extern char *yytext;
62
63 static struct hastmon_config *lconfig;
64 static struct hast_resource *curres;
65 static bool mynode, hadmynode;
66
67 static char depth0_control[HAST_ADDRSIZE];
68 static char depth0_listen[HAST_ADDRSIZE];
69 static char depth0_exec[PATH_MAX];
70 static int depth0_timeout;
71 static int depth0_attempts;
72 static int depth0_heartbeat_interval;
73 static int depth0_complaint_count;
74 static int depth0_complaint_interval;
75 static int depth0_role_on_start;
76 static struct hast_auth depth0_key;
77
78 extern void yyrestart(FILE *);
79
80 static int
isitme(const char * name)81 isitme(const char *name)
82 {
83 char buf[MAXHOSTNAMELEN];
84 char *pos;
85 #ifdef _KERN_HOSTUUID
86 size_t bufsize;
87 #endif
88
89 /*
90 * First check if the give name matches our full hostname.
91 */
92 if (gethostname(buf, sizeof(buf)) < 0) {
93 pjdlog_errno(LOG_ERR, "gethostname() failed");
94 return (-1);
95 }
96 if (strcmp(buf, name) == 0)
97 return (1);
98
99 /*
100 * Now check if it matches first part of the host name.
101 */
102 pos = strchr(buf, '.');
103 if (pos != NULL && pos != buf && strncmp(buf, name, pos - buf) == 0)
104 return (1);
105
106 #ifdef _KERN_HOSTUUID
107 /*
108 * At the end check if name is equal to our host's UUID.
109 */
110 bufsize = sizeof(buf);
111 if ((sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) == 0) &&
112 (strcasecmp(buf, name) == 0))
113 return (1);
114 #endif
115
116 /*
117 * Looks like this isn't about us.
118 */
119 return (0);
120 }
121
122 static int
node_names(char ** namesp)123 node_names(char **namesp)
124 {
125 static char names[MAXHOSTNAMELEN * 3];
126 char buf[MAXHOSTNAMELEN];
127 char *pos;
128 size_t bufsize;
129
130 if (gethostname(buf, sizeof(buf)) < 0) {
131 pjdlog_errno(LOG_ERR, "gethostname() failed");
132 return (-1);
133 }
134
135 /* First component of the host name. */
136 pos = strchr(buf, '.');
137 if (pos != NULL && pos != buf) {
138 (void)strlcpy(names, buf, MIN((size_t)(pos - buf + 1),
139 sizeof(names)));
140 (void)strlcat(names, ", ", sizeof(names));
141 }
142
143 /* Full host name. */
144 (void)strlcat(names, buf, sizeof(names));
145
146 #ifdef _KERN_HOSTUUID
147 /* Host UUID. */
148 bufsize = sizeof(buf);
149 if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) == 0) {
150 (void)strlcat(names, ", ", sizeof(names));
151 (void)strlcat(names, buf, sizeof(names));
152 }
153 #endif
154
155 *namesp = names;
156
157 return (0);
158 }
159
160 void
yyerror(const char * str)161 yyerror(const char *str)
162 {
163
164 pjdlog_error("Unable to parse configuration file at line %d near '%s': %s",
165 lineno, yytext, str);
166 }
167
168 struct hastmon_config *
yy_config_parse(const char * config,bool exitonerror)169 yy_config_parse(const char *config, bool exitonerror)
170 {
171 int ret;
172
173 curres = NULL;
174 mynode = false;
175 depth = 0;
176 lineno = 0;
177
178 depth0_timeout = HAST_TIMEOUT;
179 depth0_heartbeat_interval = HAST_HBEAT_INT;
180 depth0_complaint_count = HAST_CMPLNT_CNT;
181 depth0_complaint_interval = HAST_CMPLNT_INT;
182 depth0_role_on_start = HAST_ROLE_INIT;
183 strlcpy(depth0_control, HAST_CONTROL, sizeof(depth0_control));
184 strlcpy(depth0_listen, HAST_LISTEN, sizeof(depth0_listen));
185 depth0_exec[0] = '\0';
186 depth0_key.au_algo = HAST_AUTH_UNDEF;
187 depth0_key.au_secret[0] = '\0';
188
189 lconfig = calloc(1, sizeof(*lconfig));
190 if (lconfig == NULL) {
191 pjdlog_error("Unable to allocate memory for configuration.");
192 if (exitonerror)
193 exit(EX_TEMPFAIL);
194 return (NULL);
195 }
196 TAILQ_INIT(&lconfig->hc_friends);
197 TAILQ_INIT(&lconfig->hc_resources);
198
199 yyin = fopen(config, "r");
200 if (yyin == NULL) {
201 pjdlog_errno(LOG_ERR, "Unable to open configuration file %s",
202 config);
203 yy_config_free(lconfig);
204 if (exitonerror)
205 exit(EX_OSFILE);
206 return (NULL);
207 }
208 yyrestart(yyin);
209
210 ret = yyparse();
211 fclose(yyin);
212 if (ret != 0) {
213 yy_config_free(lconfig);
214 if (exitonerror)
215 exit(EX_CONFIG);
216 return (NULL);
217 }
218
219 /*
220 * Let's see if everything is set up.
221 */
222 if (lconfig->hc_controladdr[0] == '\0') {
223 strlcpy(lconfig->hc_controladdr, depth0_control,
224 sizeof(lconfig->hc_controladdr));
225 }
226 if (lconfig->hc_listenaddr[0] == '\0') {
227 strlcpy(lconfig->hc_listenaddr, depth0_listen,
228 sizeof(lconfig->hc_listenaddr));
229 }
230 TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) {
231 PJDLOG_ASSERT(TAILQ_FIRST(&curres->hr_remote) != NULL);
232
233 if (curres->hr_timeout == -1) {
234 /*
235 * Timeout is not set at resource-level.
236 * Use global or default setting.
237 */
238 curres->hr_timeout = depth0_timeout;
239 }
240 if (curres->hr_heartbeat_interval == -1) {
241 /*
242 * Heartbeat interval is not set at resource-level.
243 * Use global or default setting.
244 */
245 curres->hr_heartbeat_interval = depth0_heartbeat_interval;
246 }
247 if (curres->hr_key.au_algo == HAST_AUTH_UNDEF) {
248 /*
249 * Key is not set at resource-level.
250 * Use global setting.
251 */
252 curres->hr_key = depth0_key;
253 }
254 if (curres->hr_complaint_critical_cnt == -1) {
255 /*
256 * Complaint count is not set at resource-level.
257 * Use global or default setting.
258 */
259 curres->hr_complaint_critical_cnt = depth0_complaint_count;
260 }
261 if (curres->hr_complaint_interval == -1) {
262 /*
263 * Complaint interval is not set at resource-level.
264 * Use global or default setting.
265 */
266 curres->hr_complaint_interval = depth0_complaint_interval;
267 }
268 if (curres->hr_role_on_start == -1) {
269 /*
270 * Role on start is not set at resource-level.
271 * Use global or default setting.
272 */
273 curres->hr_role_on_start = depth0_role_on_start;
274 }
275 if (curres->hr_exec[0] == '\0') {
276 /*
277 * Exec is not set at resource-level.
278 * Use global or default setting.
279 */
280 strlcpy(curres->hr_exec, depth0_exec,
281 sizeof(curres->hr_exec));
282 }
283 }
284
285 return (lconfig);
286 }
287
288 void
yy_resource_free(struct hast_resource * res)289 yy_resource_free(struct hast_resource *res)
290 {
291 struct hast_address *addr;
292 struct hast_remote *remote;
293
294 while ((addr = TAILQ_FIRST(&res->hr_friends)) != NULL) {
295 TAILQ_REMOVE(&res->hr_friends, addr, a_next);
296 free(addr);
297 }
298 while ((remote = TAILQ_FIRST(&res->hr_remote)) != NULL) {
299 TAILQ_REMOVE(&res->hr_remote, remote, r_next);
300 free(remote);
301 }
302 free(res);
303 }
304
305 void
yy_config_free(struct hastmon_config * config)306 yy_config_free(struct hastmon_config *config)
307 {
308 struct hast_resource *res;
309 struct hast_address *addr;
310
311 while ((addr = TAILQ_FIRST(&config->hc_friends)) != NULL) {
312 TAILQ_REMOVE(&config->hc_friends, addr, a_next);
313 free(addr);
314 }
315 while ((res = TAILQ_FIRST(&config->hc_resources)) != NULL) {
316 TAILQ_REMOVE(&config->hc_resources, res, hr_next);
317 yy_resource_free(res);
318 }
319 free(config);
320 }
321 %}
322
323 %token ALGORITHM ATTEMPTS CB COMPLAINT_COUNT COMPLAINT_INTERVAL CONTROL EXEC
324 %token FRIENDS HEARTBEAT_INTERVAL KEY LISTEN NUM ON OB PORT PRIORITY
325 %token REMOTE RESOURCE ROLE_ON_START SECRET STR TIMEOUT
326 %token INIT PRIMARY SECONDARY WATCHDOG
327
328 %type <num> role
329
330 %union
331 {
332 int num;
333 char *str;
334 }
335
336 %token <num> NUM
337 %token <str> STR
338
339 %%
340
341 statements:
342 |
343 statements statement
344 ;
345
346 statement:
347 control_statement
348 |
349 listen_statement
350 |
351 timeout_statement
352 |
353 attempts_statement
354 |
355 friends_statement
356 |
357 heartbeat_interval_statement
358 |
359 key_statement
360 |
361 complaint_count_statement
362 |
363 complaint_interval_statement
364 |
365 role_on_start_statement
366 |
367 exec_statement
368 |
369 node_statement
370 |
371 resource_statement
372 ;
373
374 control_statement: CONTROL STR
375 {
376 switch (depth) {
377 case 0:
378 if (strlcpy(depth0_control, $2,
379 sizeof(depth0_control)) >=
380 sizeof(depth0_control)) {
381 pjdlog_error("control argument is too long.");
382 free($2);
383 return (1);
384 }
385 break;
386 case 1:
387 if (!mynode)
388 break;
389 if (strlcpy(lconfig->hc_controladdr, $2,
390 sizeof(lconfig->hc_controladdr)) >=
391 sizeof(lconfig->hc_controladdr)) {
392 pjdlog_error("control argument is too long.");
393 free($2);
394 return (1);
395 }
396 break;
397 default:
398 PJDLOG_ABORT("control at wrong depth level");
399 }
400 free($2);
401 }
402 ;
403
404 listen_statement: LISTEN STR
405 {
406 switch (depth) {
407 case 0:
408 if (strlcpy(depth0_listen, $2,
409 sizeof(depth0_listen)) >=
410 sizeof(depth0_listen)) {
411 pjdlog_error("listen argument is too long.");
412 free($2);
413 return (1);
414 }
415 break;
416 case 1:
417 if (!mynode)
418 break;
419 if (strlcpy(lconfig->hc_listenaddr, $2,
420 sizeof(lconfig->hc_listenaddr)) >=
421 sizeof(lconfig->hc_listenaddr)) {
422 pjdlog_error("listen argument is too long.");
423 free($2);
424 return (1);
425 }
426 break;
427 default:
428 PJDLOG_ABORT("listen at wrong depth level");
429 }
430 free($2);
431 }
432 ;
433
434 timeout_statement: TIMEOUT NUM
435 {
436 switch (depth) {
437 case 0:
438 depth0_timeout = $2;
439 break;
440 case 1:
441 if (curres != NULL)
442 curres->hr_timeout = $2;
443 break;
444 default:
445 PJDLOG_ABORT("timeout at wrong depth level");
446 }
447 }
448 ;
449
450 attempts_statement: ATTEMPTS NUM
451 {
452 switch (depth) {
453 case 0:
454 depth0_attempts = $2;
455 break;
456 case 2:
457 if (!mynode)
458 break;
459 /* FALLTHROUGH */
460 case 1:
461 if (curres != NULL)
462 curres->hr_local_attempts_max = $2;
463 break;
464 default:
465 PJDLOG_ABORT("attempts at wrong depth level");
466 }
467 }
468 ;
469
470 heartbeat_interval_statement: HEARTBEAT_INTERVAL NUM
471 {
472 switch (depth) {
473 case 0:
474 depth0_heartbeat_interval = $2;
475 break;
476 case 2:
477 if (!mynode)
478 break;
479 /* FALLTHROUGH */
480 case 1:
481 if (curres != NULL)
482 curres->hr_heartbeat_interval = $2;
483 break;
484 default:
485 PJDLOG_ABORT("heartbeat_interval at wrong depth level");
486 }
487 }
488 ;
489
490 complaint_count_statement: COMPLAINT_COUNT NUM
491 {
492 switch (depth) {
493 case 0:
494 depth0_complaint_count = $2;
495 break;
496 case 2:
497 if (!mynode)
498 break;
499 /* FALLTHROUGH */
500 case 1:
501 if (curres != NULL)
502 curres->hr_complaint_critical_cnt = $2;
503 break;
504 default:
505 PJDLOG_ABORT("complaint_count at wrong depth level");
506 }
507 }
508 ;
509
510 complaint_interval_statement: COMPLAINT_INTERVAL NUM
511 {
512 switch (depth) {
513 case 0:
514 depth0_complaint_interval = $2;
515 break;
516 case 2:
517 if (!mynode)
518 break;
519 /* FALLTHROUGH */
520 case 1:
521 if (curres != NULL)
522 curres->hr_complaint_interval = $2;
523 break;
524 default:
525 PJDLOG_ABORT("complaint_interval at wrong depth level");
526 }
527 }
528 ;
529
530 role_on_start_statement: ROLE_ON_START role
531 {
532 switch (depth) {
533 case 0:
534 depth0_role_on_start = $2;
535 break;
536 case 2:
537 if (!mynode)
538 break;
539 /* FALLTHROUGH */
540 case 1:
541 if (curres != NULL)
542 curres->hr_role_on_start = $2;
543 break;
544 default:
545 PJDLOG_ABORT("role_on_start at wrong depth level");
546 }
547 }
548 ;
549
550 role:
551 INIT { $$ = HAST_ROLE_INIT; }
552 |
553 PRIMARY { $$ = HAST_ROLE_PRIMARY; }
554 |
555 SECONDARY { $$ = HAST_ROLE_SECONDARY; }
556 |
557 WATCHDOG { $$ = HAST_ROLE_WATCHDOG; }
558 ;
559
560 exec_statement: EXEC STR
561 {
562 switch (depth) {
563 case 0:
564 if (strlcpy(depth0_exec, $2, sizeof(depth0_exec)) >=
565 sizeof(depth0_exec)) {
566 pjdlog_error("Exec path is too long.");
567 free($2);
568 return (1);
569 }
570 break;
571 case 2:
572 if (!mynode)
573 break;
574 /* FALLTHROUGH */
575 case 1:
576 if (curres == NULL)
577 break;
578 if (strlcpy(curres->hr_exec, $2,
579 sizeof(curres->hr_exec)) >=
580 sizeof(curres->hr_exec)) {
581 pjdlog_error("Exec path is too long.");
582 free($2);
583 return (1);
584 }
585 break;
586 default:
587 PJDLOG_ABORT("exec at wrong depth level");
588 }
589 free($2);
590 }
591 ;
592
593 node_statement: ON node_start OB node_entries CB
594 {
595 mynode = false;
596 }
597 ;
598
599 node_start: STR
600 {
601 switch (isitme($1)) {
602 case -1:
603 free($1);
604 return (1);
605 case 0:
606 break;
607 case 1:
608 mynode = true;
609 break;
610 default:
611 PJDLOG_ABORT("invalid isitme() return value");
612 }
613 free($1);
614 }
615 ;
616
617 node_entries:
618 |
619 node_entries node_entry
620 ;
621
622 node_entry:
623 control_statement
624 |
625 listen_statement
626 |
627 attempts_statement
628 |
629 friends_statement
630 |
631 priority_statement
632 |
633 heartbeat_interval_statement
634 |
635 complaint_count_statement
636 |
637 complaint_interval_statement
638 |
639 role_on_start_statement
640 ;
641
642 key_statement: KEY OB key_entries CB
643 ;
644
645 key_entries:
646 |
647 key_entries key_entry
648 ;
649
650 key_entry:
651 algorithm_statement
652 |
653 secret_statement
654 ;
655
656 algorithm_statement: ALGORITHM STR
657 {
658 switch (depth) {
659 case 1:
660 if ((depth0_key.au_algo = str2algo($2)) == HAST_AUTH_UNDEF) {
661 pjdlog_error("Unknown algorithm: %s.", $2);
662 free($2);
663 return (1);
664 }
665 break;
666 case 2:
667 if (curres == NULL)
668 break;
669 if ((curres->hr_key.au_algo = str2algo($2)) == HAST_AUTH_UNDEF) {
670 pjdlog_error("Unknown algorithm: %s.", $2);
671 free($2);
672 return (1);
673 }
674 break;
675 default:
676 PJDLOG_ABORT("key at wrong depth level");
677 }
678 free($2);
679 }
680 ;
681
682 secret_statement: SECRET STR
683 {
684 switch (depth) {
685 case 1:
686 if (strlcpy(depth0_key.au_secret, $2,
687 sizeof(depth0_key.au_secret)) >=
688 sizeof(depth0_key.au_secret)) {
689 pjdlog_error("Secret is too long.");
690 free($2);
691 return (1);
692 }
693 break;
694 case 2:
695 if (curres == NULL)
696 break;
697 if (strlcpy(curres->hr_key.au_secret, $2,
698 sizeof(depth0_key.au_secret)) >=
699 sizeof(depth0_key.au_secret)) {
700 pjdlog_error("Secret is too long.");
701 free($2);
702 return (1);
703 }
704 break;
705 default:
706 PJDLOG_ABORT("key at wrong depth level");
707 }
708 free($2);
709 }
710 ;
711
712 resource_statement: RESOURCE resource_start OB resource_entries CB
713 {
714 if (curres != NULL) {
715 /*
716 * There must be section for this node, at least with
717 * remote address configuration.
718 */
719 if (!hadmynode) {
720 char *names;
721
722 if (node_names(&names) != 0)
723 return (1);
724 pjdlog_error("No resource %s configuration for this node (acceptable node names: %s).",
725 curres->hr_name, names);
726 return (1);
727 }
728
729 /*
730 * Let's see there are some resource-level settings
731 * that we can use for node-level settings.
732 */
733
734 /*
735 * Remote address has to be configured at this point.
736 */
737 if (TAILQ_FIRST(&curres->hr_remote) == NULL) {
738 pjdlog_error("Remote address not configured for resource %s.",
739 curres->hr_name);
740 return (1);
741 }
742
743 /*
744 * Exec has to be configured at this point.
745 */
746 if (curres->hr_exec[0] == '\0') {
747 pjdlog_error("Exec not configured for resource %s.",
748 curres->hr_name);
749 return (1);
750 }
751
752 /* Put it onto resource list. */
753 TAILQ_INSERT_TAIL(&lconfig->hc_resources, curres, hr_next);
754 curres = NULL;
755 }
756 }
757 ;
758
759 resource_start: STR
760 {
761 /* Check if there is no duplicate entry. */
762 TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) {
763 if (strcmp(curres->hr_name, $1) == 0) {
764 pjdlog_error("Resource %s configured more than once.",
765 curres->hr_name);
766 free($1);
767 return (1);
768 }
769 }
770
771 /*
772 * Clear those, so we can tell if they were set at
773 * resource-level or not.
774 */
775 hadmynode = false;
776
777 curres = calloc(1, sizeof(*curres));
778 if (curres == NULL) {
779 pjdlog_error("Unable to allocate memory for resource.");
780 free($1);
781 return (1);
782 }
783 if (strlcpy(curres->hr_name, $1,
784 sizeof(curres->hr_name)) >=
785 sizeof(curres->hr_name)) {
786 pjdlog_error("Resource name is too long.");
787 free($1);
788 return (1);
789 }
790 free($1);
791 curres->hr_role = HAST_ROLE_INIT;
792 curres->hr_previous_role = HAST_ROLE_INIT;
793 curres->hr_role_on_start = -1;
794 curres->hr_timeout = -1;
795 curres->hr_priority = 100;
796 curres->hr_heartbeat_interval = -1;
797 curres->hr_exec[0] = '\0';
798 curres->hr_local_attempts_max = HAST_ATTEMPTS;
799 TAILQ_INIT(&curres->hr_friends);
800 curres->hr_remote_cnt = 0;
801 TAILQ_INIT(&curres->hr_remote);
802 curres->hr_key.au_algo = HAST_AUTH_UNDEF;
803 curres->hr_key.au_secret[0] = '\0';
804 curres->hr_complaint_critical_cnt = -1;
805 curres->hr_complaint_interval = -1;
806 TAILQ_INIT(&curres->hr_complaints);
807 }
808 ;
809
810 resource_entries:
811 |
812 resource_entries resource_entry
813 ;
814
815 resource_entry:
816 timeout_statement
817 |
818 attempts_statement
819 |
820 friends_statement
821 |
822 heartbeat_interval_statement
823 |
824 key_statement
825 |
826 complaint_count_statement
827 |
828 complaint_interval_statement
829 |
830 role_on_start_statement
831 |
832 exec_statement
833 |
834 resource_node_statement
835 ;
836
837 resource_node_statement:ON resource_node_start OB resource_node_entries CB
838 {
839 mynode = false;
840 }
841 ;
842
843 resource_node_start: STR
844 {
845 if (curres != NULL) {
846 switch (isitme($1)) {
847 case -1:
848 free($1);
849 return (1);
850 case 0:
851 break;
852 case 1:
853 mynode = hadmynode = true;
854 break;
855 default:
856 PJDLOG_ABORT("invalid isitme() return value");
857 }
858 free($1);
859 }
860 }
861 ;
862
863 resource_node_entries:
864 |
865 resource_node_entries resource_node_entry
866 ;
867
868 resource_node_entry:
869 attempts_statement
870 |
871 friends_statement
872 |
873 remote_statement
874 |
875 priority_statement
876 |
877 heartbeat_interval_statement
878 |
879 complaint_count_statement
880 |
881 complaint_interval_statement
882 |
883 exec_statement
884 |
885 role_on_start_statement
886 ;
887
888 remote_statement: REMOTE remote_addresses
889 ;
890
891 remote_addresses:
892 |
893 remote_addresses remote_address
894 ;
895
896 remote_address: STR
897 {
898 struct hast_remote *remote;
899
900 PJDLOG_ASSERT(depth == 2);
901 if (mynode) {
902 PJDLOG_ASSERT(curres != NULL);
903 remote = calloc(1, sizeof(*remote));
904 if (remote == NULL) {
905 errx(EX_TEMPFAIL,
906 "cannot allocate memory for resource");
907 }
908 if (strlcpy(remote->r_addr, $1,
909 sizeof(remote->r_addr)) >=
910 sizeof(remote->r_addr)) {
911 pjdlog_error("remote argument too long");
912 free($1);
913 return (1);
914 }
915 free($1);
916 remote->r_res = curres;
917 remote->r_ncomp = curres->hr_remote_cnt;
918 TAILQ_INSERT_TAIL(&curres->hr_remote, remote, r_next);
919 curres->hr_remote_cnt++;
920 }
921 }
922 ;
923
924 friends_statement: FRIENDS friend_addresses
925 ;
926
927 friend_addresses:
928 |
929 friend_addresses friend_address
930 ;
931
932 friend_address: STR
933 {
934 struct hast_address *addr;
935
936 switch (depth) {
937 case 0:
938 case 1:
939 addr = calloc(1, sizeof(*addr));
940 if (addr == NULL) {
941 errx(EX_TEMPFAIL,
942 "cannot allocate memory for resource");
943 }
944 if (strlcpy(addr->a_addr, $1,
945 sizeof(addr->a_addr)) >=
946 sizeof(addr->a_addr)) {
947 pjdlog_error("address argument too long");
948 free($1);
949 return (1);
950 }
951 free($1);
952 TAILQ_INSERT_TAIL(&lconfig->hc_friends, addr, a_next);
953 break;
954 case 2:
955 if (mynode) {
956 PJDLOG_ASSERT(curres != NULL);
957 addr = calloc(1, sizeof(*addr));
958 if (addr == NULL) {
959 errx(EX_TEMPFAIL,
960 "cannot allocate memory for resource");
961 }
962 if (strlcpy(addr->a_addr, $1,
963 sizeof(addr->a_addr)) >=
964 sizeof(addr->a_addr)) {
965 pjdlog_error("address argument too long");
966 free($1);
967 return (1);
968 }
969 free($1);
970 TAILQ_INSERT_TAIL(&curres->hr_friends, addr, a_next);
971 }
972 break;
973 default:
974 PJDLOG_ABORT("friends at wrong depth level");
975 }
976 }
977 ;
978
979 priority_statement: PRIORITY NUM
980 {
981 PJDLOG_ASSERT(depth == 2);
982 if (mynode) {
983 curres->hr_priority = $2;
984 if (curres->hr_priority < 0) {
985 pjdlog_error("priority should be greater or equal zero");
986 return (1);
987 }
988 }
989 }
990 ;
991