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