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