parse.y revision 267654
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: releng/9.3/sbin/hastd/parse.y 252181 2013-06-24 21:33:19Z marius $ 32 */ 33 34#include <sys/param.h> /* MAXHOSTNAMELEN */ 35#include <sys/queue.h> 36#include <sys/socket.h> 37#include <sys/sysctl.h> 38 39#include <arpa/inet.h> 40 41#include <err.h> 42#include <errno.h> 43#include <stdio.h> 44#include <string.h> 45#include <sysexits.h> 46#include <unistd.h> 47 48#include <pjdlog.h> 49 50#include "hast.h" 51 52extern int depth; 53extern int lineno; 54 55extern FILE *yyin; 56extern char *yytext; 57 58static struct hastd_config *lconfig; 59static struct hast_resource *curres; 60static bool mynode, hadmynode; 61 62static char depth0_control[HAST_ADDRSIZE]; 63static char depth0_pidfile[PATH_MAX]; 64static char depth0_listen_tcp4[HAST_ADDRSIZE]; 65static char depth0_listen_tcp6[HAST_ADDRSIZE]; 66static TAILQ_HEAD(, hastd_listen) depth0_listen; 67static int depth0_replication; 68static int depth0_checksum; 69static int depth0_compression; 70static int depth0_timeout; 71static char depth0_exec[PATH_MAX]; 72static int depth0_metaflush; 73 74static char depth1_provname[PATH_MAX]; 75static char depth1_localpath[PATH_MAX]; 76static int depth1_metaflush; 77 78extern void yyerror(const char *); 79extern int yylex(void); 80extern void yyrestart(FILE *); 81 82static int 83isitme(const char *name) 84{ 85 char buf[MAXHOSTNAMELEN]; 86 unsigned long hostid; 87 char *pos; 88 size_t bufsize; 89 90 /* 91 * First check if the given name matches our full hostname. 92 */ 93 if (gethostname(buf, sizeof(buf)) < 0) { 94 pjdlog_errno(LOG_ERR, "gethostname() failed"); 95 return (-1); 96 } 97 if (strcmp(buf, name) == 0) 98 return (1); 99 100 /* 101 * Check if it matches first part of the host name. 102 */ 103 pos = strchr(buf, '.'); 104 if (pos != NULL && (size_t)(pos - buf) == strlen(name) && 105 strncmp(buf, name, pos - buf) == 0) { 106 return (1); 107 } 108 109 /* 110 * Check if it matches host UUID. 111 */ 112 bufsize = sizeof(buf); 113 if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) { 114 pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed"); 115 return (-1); 116 } 117 if (strcasecmp(buf, name) == 0) 118 return (1); 119 120 /* 121 * Check if it matches hostid. 122 */ 123 bufsize = sizeof(hostid); 124 if (sysctlbyname("kern.hostid", &hostid, &bufsize, NULL, 0) < 0) { 125 pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostid) failed"); 126 return (-1); 127 } 128 (void)snprintf(buf, sizeof(buf), "hostid%lu", hostid); 129 if (strcmp(buf, name) == 0) 130 return (1); 131 132 /* 133 * Looks like this isn't about us. 134 */ 135 return (0); 136} 137 138static bool 139family_supported(int family) 140{ 141 int sock; 142 143 sock = socket(family, SOCK_STREAM, 0); 144 if (sock == -1 && errno == EPROTONOSUPPORT) 145 return (false); 146 if (sock >= 0) 147 (void)close(sock); 148 return (true); 149} 150 151static int 152node_names(char **namesp) 153{ 154 static char names[MAXHOSTNAMELEN * 3]; 155 char buf[MAXHOSTNAMELEN]; 156 unsigned long hostid; 157 char *pos; 158 size_t bufsize; 159 160 if (gethostname(buf, sizeof(buf)) < 0) { 161 pjdlog_errno(LOG_ERR, "gethostname() failed"); 162 return (-1); 163 } 164 165 /* First component of the host name. */ 166 pos = strchr(buf, '.'); 167 if (pos != NULL && pos != buf) { 168 (void)strlcpy(names, buf, MIN((size_t)(pos - buf + 1), 169 sizeof(names))); 170 (void)strlcat(names, ", ", sizeof(names)); 171 } 172 173 /* Full host name. */ 174 (void)strlcat(names, buf, sizeof(names)); 175 (void)strlcat(names, ", ", sizeof(names)); 176 177 /* Host UUID. */ 178 bufsize = sizeof(buf); 179 if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) { 180 pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed"); 181 return (-1); 182 } 183 (void)strlcat(names, buf, sizeof(names)); 184 (void)strlcat(names, ", ", sizeof(names)); 185 186 /* Host ID. */ 187 bufsize = sizeof(hostid); 188 if (sysctlbyname("kern.hostid", &hostid, &bufsize, NULL, 0) < 0) { 189 pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostid) failed"); 190 return (-1); 191 } 192 (void)snprintf(buf, sizeof(buf), "hostid%lu", hostid); 193 (void)strlcat(names, buf, sizeof(names)); 194 195 *namesp = names; 196 197 return (0); 198} 199 200void 201yyerror(const char *str) 202{ 203 204 pjdlog_error("Unable to parse configuration file at line %d near '%s': %s", 205 lineno, yytext, str); 206} 207 208struct hastd_config * 209yy_config_parse(const char *config, bool exitonerror) 210{ 211 int ret; 212 213 curres = NULL; 214 mynode = false; 215 depth = 0; 216 lineno = 0; 217 218 depth0_timeout = HAST_TIMEOUT; 219 depth0_replication = HAST_REPLICATION_MEMSYNC; 220 depth0_checksum = HAST_CHECKSUM_NONE; 221 depth0_compression = HAST_COMPRESSION_HOLE; 222 strlcpy(depth0_control, HAST_CONTROL, sizeof(depth0_control)); 223 strlcpy(depth0_pidfile, HASTD_PIDFILE, sizeof(depth0_pidfile)); 224 TAILQ_INIT(&depth0_listen); 225 strlcpy(depth0_listen_tcp4, HASTD_LISTEN_TCP4, 226 sizeof(depth0_listen_tcp4)); 227 strlcpy(depth0_listen_tcp6, HASTD_LISTEN_TCP6, 228 sizeof(depth0_listen_tcp6)); 229 depth0_exec[0] = '\0'; 230 depth0_metaflush = 1; 231 232 lconfig = calloc(1, sizeof(*lconfig)); 233 if (lconfig == NULL) { 234 pjdlog_error("Unable to allocate memory for configuration."); 235 if (exitonerror) 236 exit(EX_TEMPFAIL); 237 return (NULL); 238 } 239 240 TAILQ_INIT(&lconfig->hc_listen); 241 TAILQ_INIT(&lconfig->hc_resources); 242 243 yyin = fopen(config, "r"); 244 if (yyin == NULL) { 245 pjdlog_errno(LOG_ERR, "Unable to open configuration file %s", 246 config); 247 yy_config_free(lconfig); 248 if (exitonerror) 249 exit(EX_OSFILE); 250 return (NULL); 251 } 252 yyrestart(yyin); 253 ret = yyparse(); 254 fclose(yyin); 255 if (ret != 0) { 256 yy_config_free(lconfig); 257 if (exitonerror) 258 exit(EX_CONFIG); 259 return (NULL); 260 } 261 262 /* 263 * Let's see if everything is set up. 264 */ 265 if (lconfig->hc_controladdr[0] == '\0') { 266 strlcpy(lconfig->hc_controladdr, depth0_control, 267 sizeof(lconfig->hc_controladdr)); 268 } 269 if (lconfig->hc_pidfile[0] == '\0') { 270 strlcpy(lconfig->hc_pidfile, depth0_pidfile, 271 sizeof(lconfig->hc_pidfile)); 272 } 273 if (!TAILQ_EMPTY(&depth0_listen)) 274 TAILQ_CONCAT(&lconfig->hc_listen, &depth0_listen, hl_next); 275 if (TAILQ_EMPTY(&lconfig->hc_listen)) { 276 struct hastd_listen *lst; 277 278 if (family_supported(AF_INET)) { 279 lst = calloc(1, sizeof(*lst)); 280 if (lst == NULL) { 281 pjdlog_error("Unable to allocate memory for listen address."); 282 yy_config_free(lconfig); 283 if (exitonerror) 284 exit(EX_TEMPFAIL); 285 return (NULL); 286 } 287 (void)strlcpy(lst->hl_addr, depth0_listen_tcp4, 288 sizeof(lst->hl_addr)); 289 TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next); 290 } else { 291 pjdlog_debug(1, 292 "No IPv4 support in the kernel, not listening on IPv4 address."); 293 } 294 if (family_supported(AF_INET6)) { 295 lst = calloc(1, sizeof(*lst)); 296 if (lst == NULL) { 297 pjdlog_error("Unable to allocate memory for listen address."); 298 yy_config_free(lconfig); 299 if (exitonerror) 300 exit(EX_TEMPFAIL); 301 return (NULL); 302 } 303 (void)strlcpy(lst->hl_addr, depth0_listen_tcp6, 304 sizeof(lst->hl_addr)); 305 TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next); 306 } else { 307 pjdlog_debug(1, 308 "No IPv6 support in the kernel, not listening on IPv6 address."); 309 } 310 if (TAILQ_EMPTY(&lconfig->hc_listen)) { 311 pjdlog_error("No address to listen on."); 312 yy_config_free(lconfig); 313 if (exitonerror) 314 exit(EX_TEMPFAIL); 315 return (NULL); 316 } 317 } 318 TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) { 319 PJDLOG_ASSERT(curres->hr_provname[0] != '\0'); 320 PJDLOG_ASSERT(curres->hr_localpath[0] != '\0'); 321 PJDLOG_ASSERT(curres->hr_remoteaddr[0] != '\0'); 322 323 if (curres->hr_replication == -1) { 324 /* 325 * Replication is not set at resource-level. 326 * Use global or default setting. 327 */ 328 curres->hr_replication = depth0_replication; 329 curres->hr_original_replication = depth0_replication; 330 } 331 if (curres->hr_checksum == -1) { 332 /* 333 * Checksum is not set at resource-level. 334 * Use global or default setting. 335 */ 336 curres->hr_checksum = depth0_checksum; 337 } 338 if (curres->hr_compression == -1) { 339 /* 340 * Compression is not set at resource-level. 341 * Use global or default setting. 342 */ 343 curres->hr_compression = depth0_compression; 344 } 345 if (curres->hr_timeout == -1) { 346 /* 347 * Timeout is not set at resource-level. 348 * Use global or default setting. 349 */ 350 curres->hr_timeout = depth0_timeout; 351 } 352 if (curres->hr_exec[0] == '\0') { 353 /* 354 * Exec is not set at resource-level. 355 * Use global or default setting. 356 */ 357 strlcpy(curres->hr_exec, depth0_exec, 358 sizeof(curres->hr_exec)); 359 } 360 if (curres->hr_metaflush == -1) { 361 /* 362 * Metaflush is not set at resource-level. 363 * Use global or default setting. 364 */ 365 curres->hr_metaflush = depth0_metaflush; 366 } 367 } 368 369 return (lconfig); 370} 371 372void 373yy_config_free(struct hastd_config *config) 374{ 375 struct hastd_listen *lst; 376 struct hast_resource *res; 377 378 while ((lst = TAILQ_FIRST(&depth0_listen)) != NULL) { 379 TAILQ_REMOVE(&depth0_listen, lst, hl_next); 380 free(lst); 381 } 382 while ((lst = TAILQ_FIRST(&config->hc_listen)) != NULL) { 383 TAILQ_REMOVE(&config->hc_listen, lst, hl_next); 384 free(lst); 385 } 386 while ((res = TAILQ_FIRST(&config->hc_resources)) != NULL) { 387 TAILQ_REMOVE(&config->hc_resources, res, hr_next); 388 free(res); 389 } 390 free(config); 391} 392%} 393 394%token CONTROL PIDFILE LISTEN REPLICATION CHECKSUM COMPRESSION METAFLUSH 395%token TIMEOUT EXEC RESOURCE NAME LOCAL REMOTE SOURCE ON OFF 396%token FULLSYNC MEMSYNC ASYNC NONE CRC32 SHA256 HOLE LZF 397%token NUM STR OB CB 398 399%type <str> remote_str 400%type <num> replication_type 401%type <num> checksum_type 402%type <num> compression_type 403%type <num> boolean 404 405%union 406{ 407 int num; 408 char *str; 409} 410 411%token <num> NUM 412%token <str> STR 413 414%% 415 416statements: 417 | 418 statements statement 419 ; 420 421statement: 422 control_statement 423 | 424 pidfile_statement 425 | 426 listen_statement 427 | 428 replication_statement 429 | 430 checksum_statement 431 | 432 compression_statement 433 | 434 timeout_statement 435 | 436 exec_statement 437 | 438 metaflush_statement 439 | 440 node_statement 441 | 442 resource_statement 443 ; 444 445control_statement: CONTROL STR 446 { 447 switch (depth) { 448 case 0: 449 if (strlcpy(depth0_control, $2, 450 sizeof(depth0_control)) >= 451 sizeof(depth0_control)) { 452 pjdlog_error("control argument is too long."); 453 free($2); 454 return (1); 455 } 456 break; 457 case 1: 458 if (!mynode) 459 break; 460 if (strlcpy(lconfig->hc_controladdr, $2, 461 sizeof(lconfig->hc_controladdr)) >= 462 sizeof(lconfig->hc_controladdr)) { 463 pjdlog_error("control argument is too long."); 464 free($2); 465 return (1); 466 } 467 break; 468 default: 469 PJDLOG_ABORT("control at wrong depth level"); 470 } 471 free($2); 472 } 473 ; 474 475pidfile_statement: PIDFILE STR 476 { 477 switch (depth) { 478 case 0: 479 if (strlcpy(depth0_pidfile, $2, 480 sizeof(depth0_pidfile)) >= 481 sizeof(depth0_pidfile)) { 482 pjdlog_error("pidfile argument is too long."); 483 free($2); 484 return (1); 485 } 486 break; 487 case 1: 488 if (!mynode) 489 break; 490 if (strlcpy(lconfig->hc_pidfile, $2, 491 sizeof(lconfig->hc_pidfile)) >= 492 sizeof(lconfig->hc_pidfile)) { 493 pjdlog_error("pidfile argument is too long."); 494 free($2); 495 return (1); 496 } 497 break; 498 default: 499 PJDLOG_ABORT("pidfile at wrong depth level"); 500 } 501 free($2); 502 } 503 ; 504 505listen_statement: LISTEN STR 506 { 507 struct hastd_listen *lst; 508 509 lst = calloc(1, sizeof(*lst)); 510 if (lst == NULL) { 511 pjdlog_error("Unable to allocate memory for listen address."); 512 free($2); 513 return (1); 514 } 515 if (strlcpy(lst->hl_addr, $2, sizeof(lst->hl_addr)) >= 516 sizeof(lst->hl_addr)) { 517 pjdlog_error("listen argument is too long."); 518 free($2); 519 free(lst); 520 return (1); 521 } 522 switch (depth) { 523 case 0: 524 TAILQ_INSERT_TAIL(&depth0_listen, lst, hl_next); 525 break; 526 case 1: 527 if (mynode) 528 TAILQ_INSERT_TAIL(&depth0_listen, lst, hl_next); 529 else 530 free(lst); 531 break; 532 default: 533 PJDLOG_ABORT("listen at wrong depth level"); 534 } 535 free($2); 536 } 537 ; 538 539replication_statement: REPLICATION replication_type 540 { 541 switch (depth) { 542 case 0: 543 depth0_replication = $2; 544 break; 545 case 1: 546 PJDLOG_ASSERT(curres != NULL); 547 curres->hr_replication = $2; 548 curres->hr_original_replication = $2; 549 break; 550 default: 551 PJDLOG_ABORT("replication at wrong depth level"); 552 } 553 } 554 ; 555 556replication_type: 557 FULLSYNC { $$ = HAST_REPLICATION_FULLSYNC; } 558 | 559 MEMSYNC { $$ = HAST_REPLICATION_MEMSYNC; } 560 | 561 ASYNC { $$ = HAST_REPLICATION_ASYNC; } 562 ; 563 564checksum_statement: CHECKSUM checksum_type 565 { 566 switch (depth) { 567 case 0: 568 depth0_checksum = $2; 569 break; 570 case 1: 571 PJDLOG_ASSERT(curres != NULL); 572 curres->hr_checksum = $2; 573 break; 574 default: 575 PJDLOG_ABORT("checksum at wrong depth level"); 576 } 577 } 578 ; 579 580checksum_type: 581 NONE { $$ = HAST_CHECKSUM_NONE; } 582 | 583 CRC32 { $$ = HAST_CHECKSUM_CRC32; } 584 | 585 SHA256 { $$ = HAST_CHECKSUM_SHA256; } 586 ; 587 588compression_statement: COMPRESSION compression_type 589 { 590 switch (depth) { 591 case 0: 592 depth0_compression = $2; 593 break; 594 case 1: 595 PJDLOG_ASSERT(curres != NULL); 596 curres->hr_compression = $2; 597 break; 598 default: 599 PJDLOG_ABORT("compression at wrong depth level"); 600 } 601 } 602 ; 603 604compression_type: 605 NONE { $$ = HAST_COMPRESSION_NONE; } 606 | 607 HOLE { $$ = HAST_COMPRESSION_HOLE; } 608 | 609 LZF { $$ = HAST_COMPRESSION_LZF; } 610 ; 611 612timeout_statement: TIMEOUT NUM 613 { 614 if ($2 <= 0) { 615 pjdlog_error("Negative or zero timeout."); 616 return (1); 617 } 618 switch (depth) { 619 case 0: 620 depth0_timeout = $2; 621 break; 622 case 1: 623 PJDLOG_ASSERT(curres != NULL); 624 curres->hr_timeout = $2; 625 break; 626 default: 627 PJDLOG_ABORT("timeout at wrong depth level"); 628 } 629 } 630 ; 631 632exec_statement: EXEC STR 633 { 634 switch (depth) { 635 case 0: 636 if (strlcpy(depth0_exec, $2, sizeof(depth0_exec)) >= 637 sizeof(depth0_exec)) { 638 pjdlog_error("Exec path is too long."); 639 free($2); 640 return (1); 641 } 642 break; 643 case 1: 644 PJDLOG_ASSERT(curres != NULL); 645 if (strlcpy(curres->hr_exec, $2, 646 sizeof(curres->hr_exec)) >= 647 sizeof(curres->hr_exec)) { 648 pjdlog_error("Exec path is too long."); 649 free($2); 650 return (1); 651 } 652 break; 653 default: 654 PJDLOG_ABORT("exec at wrong depth level"); 655 } 656 free($2); 657 } 658 ; 659 660metaflush_statement: METAFLUSH boolean 661 { 662 switch (depth) { 663 case 0: 664 depth0_metaflush = $2; 665 break; 666 case 1: 667 PJDLOG_ASSERT(curres != NULL); 668 depth1_metaflush = $2; 669 break; 670 case 2: 671 if (!mynode) 672 break; 673 PJDLOG_ASSERT(curres != NULL); 674 curres->hr_metaflush = $2; 675 break; 676 default: 677 PJDLOG_ABORT("metaflush at wrong depth level"); 678 } 679 } 680 ; 681 682boolean: 683 ON { $$ = 1; } 684 | 685 OFF { $$ = 0; } 686 ; 687 688node_statement: ON node_start OB node_entries CB 689 { 690 mynode = false; 691 } 692 ; 693 694node_start: STR 695 { 696 switch (isitme($1)) { 697 case -1: 698 free($1); 699 return (1); 700 case 0: 701 break; 702 case 1: 703 mynode = true; 704 break; 705 default: 706 PJDLOG_ABORT("invalid isitme() return value"); 707 } 708 free($1); 709 } 710 ; 711 712node_entries: 713 | 714 node_entries node_entry 715 ; 716 717node_entry: 718 control_statement 719 | 720 pidfile_statement 721 | 722 listen_statement 723 ; 724 725resource_statement: RESOURCE resource_start OB resource_entries CB 726 { 727 if (curres != NULL) { 728 /* 729 * There must be section for this node, at least with 730 * remote address configuration. 731 */ 732 if (!hadmynode) { 733 char *names; 734 735 if (node_names(&names) != 0) 736 return (1); 737 pjdlog_error("No resource %s configuration for this node (acceptable node names: %s).", 738 curres->hr_name, names); 739 return (1); 740 } 741 742 /* 743 * Let's see if there are some resource-level settings 744 * that we can use for node-level settings. 745 */ 746 if (curres->hr_provname[0] == '\0' && 747 depth1_provname[0] != '\0') { 748 /* 749 * Provider name is not set at node-level, 750 * but is set at resource-level, use it. 751 */ 752 strlcpy(curres->hr_provname, depth1_provname, 753 sizeof(curres->hr_provname)); 754 } 755 if (curres->hr_localpath[0] == '\0' && 756 depth1_localpath[0] != '\0') { 757 /* 758 * Path to local provider is not set at 759 * node-level, but is set at resource-level, 760 * use it. 761 */ 762 strlcpy(curres->hr_localpath, depth1_localpath, 763 sizeof(curres->hr_localpath)); 764 } 765 if (curres->hr_metaflush == -1 && depth1_metaflush != -1) { 766 /* 767 * Metaflush is not set at node-level, 768 * but is set at resource-level, use it. 769 */ 770 curres->hr_metaflush = depth1_metaflush; 771 } 772 773 /* 774 * If provider name is not given, use resource name 775 * as provider name. 776 */ 777 if (curres->hr_provname[0] == '\0') { 778 strlcpy(curres->hr_provname, curres->hr_name, 779 sizeof(curres->hr_provname)); 780 } 781 782 /* 783 * Remote address has to be configured at this point. 784 */ 785 if (curres->hr_remoteaddr[0] == '\0') { 786 pjdlog_error("Remote address not configured for resource %s.", 787 curres->hr_name); 788 return (1); 789 } 790 /* 791 * Path to local provider has to be configured at this 792 * point. 793 */ 794 if (curres->hr_localpath[0] == '\0') { 795 pjdlog_error("Path to local component not configured for resource %s.", 796 curres->hr_name); 797 return (1); 798 } 799 800 /* Put it onto resource list. */ 801 TAILQ_INSERT_TAIL(&lconfig->hc_resources, curres, hr_next); 802 curres = NULL; 803 } 804 } 805 ; 806 807resource_start: STR 808 { 809 /* Check if there is no duplicate entry. */ 810 TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) { 811 if (strcmp(curres->hr_name, $1) == 0) { 812 pjdlog_error("Resource %s configured more than once.", 813 curres->hr_name); 814 free($1); 815 return (1); 816 } 817 } 818 819 /* 820 * Clear those, so we can tell if they were set at 821 * resource-level or not. 822 */ 823 depth1_provname[0] = '\0'; 824 depth1_localpath[0] = '\0'; 825 depth1_metaflush = -1; 826 hadmynode = false; 827 828 curres = calloc(1, sizeof(*curres)); 829 if (curres == NULL) { 830 pjdlog_error("Unable to allocate memory for resource."); 831 free($1); 832 return (1); 833 } 834 if (strlcpy(curres->hr_name, $1, 835 sizeof(curres->hr_name)) >= 836 sizeof(curres->hr_name)) { 837 pjdlog_error("Resource name is too long."); 838 free(curres); 839 free($1); 840 return (1); 841 } 842 free($1); 843 curres->hr_role = HAST_ROLE_INIT; 844 curres->hr_previous_role = HAST_ROLE_INIT; 845 curres->hr_replication = -1; 846 curres->hr_original_replication = -1; 847 curres->hr_checksum = -1; 848 curres->hr_compression = -1; 849 curres->hr_version = 1; 850 curres->hr_timeout = -1; 851 curres->hr_exec[0] = '\0'; 852 curres->hr_provname[0] = '\0'; 853 curres->hr_localpath[0] = '\0'; 854 curres->hr_localfd = -1; 855 curres->hr_localflush = true; 856 curres->hr_metaflush = -1; 857 curres->hr_remoteaddr[0] = '\0'; 858 curres->hr_sourceaddr[0] = '\0'; 859 curres->hr_ggateunit = -1; 860 } 861 ; 862 863resource_entries: 864 | 865 resource_entries resource_entry 866 ; 867 868resource_entry: 869 replication_statement 870 | 871 checksum_statement 872 | 873 compression_statement 874 | 875 timeout_statement 876 | 877 exec_statement 878 | 879 metaflush_statement 880 | 881 name_statement 882 | 883 local_statement 884 | 885 resource_node_statement 886 ; 887 888name_statement: NAME STR 889 { 890 switch (depth) { 891 case 1: 892 if (strlcpy(depth1_provname, $2, 893 sizeof(depth1_provname)) >= 894 sizeof(depth1_provname)) { 895 pjdlog_error("name argument is too long."); 896 free($2); 897 return (1); 898 } 899 break; 900 case 2: 901 if (!mynode) 902 break; 903 PJDLOG_ASSERT(curres != NULL); 904 if (strlcpy(curres->hr_provname, $2, 905 sizeof(curres->hr_provname)) >= 906 sizeof(curres->hr_provname)) { 907 pjdlog_error("name argument is too long."); 908 free($2); 909 return (1); 910 } 911 break; 912 default: 913 PJDLOG_ABORT("name at wrong depth level"); 914 } 915 free($2); 916 } 917 ; 918 919local_statement: LOCAL STR 920 { 921 switch (depth) { 922 case 1: 923 if (strlcpy(depth1_localpath, $2, 924 sizeof(depth1_localpath)) >= 925 sizeof(depth1_localpath)) { 926 pjdlog_error("local argument is too long."); 927 free($2); 928 return (1); 929 } 930 break; 931 case 2: 932 if (!mynode) 933 break; 934 PJDLOG_ASSERT(curres != NULL); 935 if (strlcpy(curres->hr_localpath, $2, 936 sizeof(curres->hr_localpath)) >= 937 sizeof(curres->hr_localpath)) { 938 pjdlog_error("local argument is too long."); 939 free($2); 940 return (1); 941 } 942 break; 943 default: 944 PJDLOG_ABORT("local at wrong depth level"); 945 } 946 free($2); 947 } 948 ; 949 950resource_node_statement:ON resource_node_start OB resource_node_entries CB 951 { 952 mynode = false; 953 } 954 ; 955 956resource_node_start: STR 957 { 958 if (curres != NULL) { 959 switch (isitme($1)) { 960 case -1: 961 free($1); 962 return (1); 963 case 0: 964 break; 965 case 1: 966 mynode = hadmynode = true; 967 break; 968 default: 969 PJDLOG_ABORT("invalid isitme() return value"); 970 } 971 } 972 free($1); 973 } 974 ; 975 976resource_node_entries: 977 | 978 resource_node_entries resource_node_entry 979 ; 980 981resource_node_entry: 982 name_statement 983 | 984 local_statement 985 | 986 remote_statement 987 | 988 source_statement 989 | 990 metaflush_statement 991 ; 992 993remote_statement: REMOTE remote_str 994 { 995 PJDLOG_ASSERT(depth == 2); 996 if (mynode) { 997 PJDLOG_ASSERT(curres != NULL); 998 if (strlcpy(curres->hr_remoteaddr, $2, 999 sizeof(curres->hr_remoteaddr)) >= 1000 sizeof(curres->hr_remoteaddr)) { 1001 pjdlog_error("remote argument is too long."); 1002 free($2); 1003 return (1); 1004 } 1005 } 1006 free($2); 1007 } 1008 ; 1009 1010remote_str: 1011 NONE { $$ = strdup("none"); } 1012 | 1013 STR { } 1014 ; 1015 1016source_statement: SOURCE STR 1017 { 1018 PJDLOG_ASSERT(depth == 2); 1019 if (mynode) { 1020 PJDLOG_ASSERT(curres != NULL); 1021 if (strlcpy(curres->hr_sourceaddr, $2, 1022 sizeof(curres->hr_sourceaddr)) >= 1023 sizeof(curres->hr_sourceaddr)) { 1024 pjdlog_error("source argument is too long."); 1025 free($2); 1026 return (1); 1027 } 1028 } 1029 free($2); 1030 } 1031 ; 1032