parse.y revision 222119
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: head/sbin/hastd/parse.y 222119 2011-05-20 11:15:27Z pjd $ 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 53extern int depth; 54extern int lineno; 55 56extern FILE *yyin; 57extern char *yytext; 58 59static struct hastd_config *lconfig; 60static struct hast_resource *curres; 61static bool mynode, hadmynode; 62 63static char depth0_control[HAST_ADDRSIZE]; 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]; 72 73static char depth1_provname[PATH_MAX]; 74static char depth1_localpath[PATH_MAX]; 75 76extern void yyrestart(FILE *); 77 78static int 79isitme(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 121static bool 122family_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 134static int 135node_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 172void 173yyerror(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 180struct hastd_config * 181yy_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#ifdef notyet 261 if (family_supported(AF_INET6)) { 262 lst = calloc(1, sizeof(*lst)); 263 if (lst == NULL) { 264 pjdlog_error("Unable to allocate memory for listen address."); 265 yy_config_free(lconfig); 266 if (exitonerror) 267 exit(EX_TEMPFAIL); 268 return (NULL); 269 } 270 (void)strlcpy(lst->hl_addr, depth0_listen_tcp6, 271 sizeof(lst->hl_addr)); 272 TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next); 273 } else { 274 pjdlog_debug(1, 275 "No IPv6 support in the kernel, not listening on IPv6 address."); 276 } 277#endif 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 assert(curres->hr_provname[0] != '\0'); 288 assert(curres->hr_localpath[0] != '\0'); 289 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 } 335 336 return (lconfig); 337} 338 339void 340yy_config_free(struct hastd_config *config) 341{ 342 struct hastd_listen *lst; 343 struct hast_resource *res; 344 345 while ((lst = TAILQ_FIRST(&depth0_listen)) != NULL) { 346 TAILQ_REMOVE(&depth0_listen, lst, hl_next); 347 free(lst); 348 } 349 while ((lst = TAILQ_FIRST(&config->hc_listen)) != NULL) { 350 TAILQ_REMOVE(&config->hc_listen, lst, hl_next); 351 free(lst); 352 } 353 while ((res = TAILQ_FIRST(&config->hc_resources)) != NULL) { 354 TAILQ_REMOVE(&config->hc_resources, res, hr_next); 355 free(res); 356 } 357 free(config); 358} 359%} 360 361%token CONTROL LISTEN PORT REPLICATION CHECKSUM COMPRESSION 362%token TIMEOUT EXEC EXTENTSIZE RESOURCE NAME LOCAL REMOTE SOURCE ON 363%token FULLSYNC MEMSYNC ASYNC NONE CRC32 SHA256 HOLE LZF 364%token NUM STR OB CB 365 366%type <str> remote_str 367%type <num> replication_type 368%type <num> checksum_type 369%type <num> compression_type 370 371%union 372{ 373 int num; 374 char *str; 375} 376 377%token <num> NUM 378%token <str> STR 379 380%% 381 382statements: 383 | 384 statements statement 385 ; 386 387statement: 388 control_statement 389 | 390 listen_statement 391 | 392 replication_statement 393 | 394 checksum_statement 395 | 396 compression_statement 397 | 398 timeout_statement 399 | 400 exec_statement 401 | 402 node_statement 403 | 404 resource_statement 405 ; 406 407control_statement: CONTROL STR 408 { 409 switch (depth) { 410 case 0: 411 if (strlcpy(depth0_control, $2, 412 sizeof(depth0_control)) >= 413 sizeof(depth0_control)) { 414 pjdlog_error("control argument is too long."); 415 free($2); 416 return (1); 417 } 418 break; 419 case 1: 420 if (!mynode) 421 break; 422 if (strlcpy(lconfig->hc_controladdr, $2, 423 sizeof(lconfig->hc_controladdr)) >= 424 sizeof(lconfig->hc_controladdr)) { 425 pjdlog_error("control argument is too long."); 426 free($2); 427 return (1); 428 } 429 break; 430 default: 431 assert(!"control at wrong depth level"); 432 } 433 free($2); 434 } 435 ; 436 437listen_statement: LISTEN STR 438 { 439 struct hastd_listen *lst; 440 441 lst = calloc(1, sizeof(*lst)); 442 if (lst == NULL) { 443 pjdlog_error("Unable to allocate memory for listen address."); 444 free($2); 445 return (1); 446 } 447 if (strlcpy(lst->hl_addr, $2, sizeof(lst->hl_addr)) >= 448 sizeof(lst->hl_addr)) { 449 pjdlog_error("listen argument is too long."); 450 free($2); 451 free(lst); 452 return (1); 453 } 454 switch (depth) { 455 case 0: 456 TAILQ_INSERT_TAIL(&depth0_listen, lst, hl_next); 457 break; 458 case 1: 459 if (mynode) 460 TAILQ_INSERT_TAIL(&depth0_listen, lst, hl_next); 461 else 462 free(lst); 463 break; 464 default: 465 assert(!"listen at wrong depth level"); 466 } 467 free($2); 468 } 469 ; 470 471replication_statement: REPLICATION replication_type 472 { 473 switch (depth) { 474 case 0: 475 depth0_replication = $2; 476 break; 477 case 1: 478 if (curres != NULL) 479 curres->hr_replication = $2; 480 break; 481 default: 482 assert(!"replication at wrong depth level"); 483 } 484 } 485 ; 486 487replication_type: 488 FULLSYNC { $$ = HAST_REPLICATION_FULLSYNC; } 489 | 490 MEMSYNC { $$ = HAST_REPLICATION_MEMSYNC; } 491 | 492 ASYNC { $$ = HAST_REPLICATION_ASYNC; } 493 ; 494 495checksum_statement: CHECKSUM checksum_type 496 { 497 switch (depth) { 498 case 0: 499 depth0_checksum = $2; 500 break; 501 case 1: 502 if (curres != NULL) 503 curres->hr_checksum = $2; 504 break; 505 default: 506 assert(!"checksum at wrong depth level"); 507 } 508 } 509 ; 510 511checksum_type: 512 NONE { $$ = HAST_CHECKSUM_NONE; } 513 | 514 CRC32 { $$ = HAST_CHECKSUM_CRC32; } 515 | 516 SHA256 { $$ = HAST_CHECKSUM_SHA256; } 517 ; 518 519compression_statement: COMPRESSION compression_type 520 { 521 switch (depth) { 522 case 0: 523 depth0_compression = $2; 524 break; 525 case 1: 526 if (curres != NULL) 527 curres->hr_compression = $2; 528 break; 529 default: 530 assert(!"compression at wrong depth level"); 531 } 532 } 533 ; 534 535compression_type: 536 NONE { $$ = HAST_COMPRESSION_NONE; } 537 | 538 HOLE { $$ = HAST_COMPRESSION_HOLE; } 539 | 540 LZF { $$ = HAST_COMPRESSION_LZF; } 541 ; 542 543timeout_statement: TIMEOUT NUM 544 { 545 if ($2 <= 0) { 546 pjdlog_error("Negative or zero timeout."); 547 return (1); 548 } 549 switch (depth) { 550 case 0: 551 depth0_timeout = $2; 552 break; 553 case 1: 554 if (curres != NULL) 555 curres->hr_timeout = $2; 556 break; 557 default: 558 assert(!"timeout at wrong depth level"); 559 } 560 } 561 ; 562 563exec_statement: EXEC STR 564 { 565 switch (depth) { 566 case 0: 567 if (strlcpy(depth0_exec, $2, sizeof(depth0_exec)) >= 568 sizeof(depth0_exec)) { 569 pjdlog_error("Exec path is too long."); 570 free($2); 571 return (1); 572 } 573 break; 574 case 1: 575 if (curres == NULL) 576 break; 577 if (strlcpy(curres->hr_exec, $2, 578 sizeof(curres->hr_exec)) >= 579 sizeof(curres->hr_exec)) { 580 pjdlog_error("Exec path is too long."); 581 free($2); 582 return (1); 583 } 584 break; 585 default: 586 assert(!"exec at wrong depth level"); 587 } 588 free($2); 589 } 590 ; 591 592node_statement: ON node_start OB node_entries CB 593 { 594 mynode = false; 595 } 596 ; 597 598node_start: STR 599 { 600 switch (isitme($1)) { 601 case -1: 602 free($1); 603 return (1); 604 case 0: 605 break; 606 case 1: 607 mynode = true; 608 break; 609 default: 610 assert(!"invalid isitme() return value"); 611 } 612 free($1); 613 } 614 ; 615 616node_entries: 617 | 618 node_entries node_entry 619 ; 620 621node_entry: 622 control_statement 623 | 624 listen_statement 625 ; 626 627resource_statement: RESOURCE resource_start OB resource_entries CB 628 { 629 if (curres != NULL) { 630 /* 631 * There must be section for this node, at least with 632 * remote address configuration. 633 */ 634 if (!hadmynode) { 635 char *names; 636 637 if (node_names(&names) != 0) 638 return (1); 639 pjdlog_error("No resource %s configuration for this node (acceptable node names: %s).", 640 curres->hr_name, names); 641 return (1); 642 } 643 644 /* 645 * Let's see there are some resource-level settings 646 * that we can use for node-level settings. 647 */ 648 if (curres->hr_provname[0] == '\0' && 649 depth1_provname[0] != '\0') { 650 /* 651 * Provider name is not set at node-level, 652 * but is set at resource-level, use it. 653 */ 654 strlcpy(curres->hr_provname, depth1_provname, 655 sizeof(curres->hr_provname)); 656 } 657 if (curres->hr_localpath[0] == '\0' && 658 depth1_localpath[0] != '\0') { 659 /* 660 * Path to local provider is not set at 661 * node-level, but is set at resource-level, 662 * use it. 663 */ 664 strlcpy(curres->hr_localpath, depth1_localpath, 665 sizeof(curres->hr_localpath)); 666 } 667 668 /* 669 * If provider name is not given, use resource name 670 * as provider name. 671 */ 672 if (curres->hr_provname[0] == '\0') { 673 strlcpy(curres->hr_provname, curres->hr_name, 674 sizeof(curres->hr_provname)); 675 } 676 677 /* 678 * Remote address has to be configured at this point. 679 */ 680 if (curres->hr_remoteaddr[0] == '\0') { 681 pjdlog_error("Remote address not configured for resource %s.", 682 curres->hr_name); 683 return (1); 684 } 685 /* 686 * Path to local provider has to be configured at this 687 * point. 688 */ 689 if (curres->hr_localpath[0] == '\0') { 690 pjdlog_error("Path to local component not configured for resource %s.", 691 curres->hr_name); 692 return (1); 693 } 694 695 /* Put it onto resource list. */ 696 TAILQ_INSERT_TAIL(&lconfig->hc_resources, curres, hr_next); 697 curres = NULL; 698 } 699 } 700 ; 701 702resource_start: STR 703 { 704 /* Check if there is no duplicate entry. */ 705 TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) { 706 if (strcmp(curres->hr_name, $1) == 0) { 707 pjdlog_error("Resource %s configured more than once.", 708 curres->hr_name); 709 free($1); 710 return (1); 711 } 712 } 713 714 /* 715 * Clear those, so we can tell if they were set at 716 * resource-level or not. 717 */ 718 depth1_provname[0] = '\0'; 719 depth1_localpath[0] = '\0'; 720 hadmynode = false; 721 722 curres = calloc(1, sizeof(*curres)); 723 if (curres == NULL) { 724 pjdlog_error("Unable to allocate memory for resource."); 725 free($1); 726 return (1); 727 } 728 if (strlcpy(curres->hr_name, $1, 729 sizeof(curres->hr_name)) >= 730 sizeof(curres->hr_name)) { 731 pjdlog_error("Resource name is too long."); 732 free($1); 733 return (1); 734 } 735 free($1); 736 curres->hr_role = HAST_ROLE_INIT; 737 curres->hr_previous_role = HAST_ROLE_INIT; 738 curres->hr_replication = -1; 739 curres->hr_checksum = -1; 740 curres->hr_compression = -1; 741 curres->hr_timeout = -1; 742 curres->hr_exec[0] = '\0'; 743 curres->hr_provname[0] = '\0'; 744 curres->hr_localpath[0] = '\0'; 745 curres->hr_localfd = -1; 746 curres->hr_remoteaddr[0] = '\0'; 747 curres->hr_sourceaddr[0] = '\0'; 748 curres->hr_ggateunit = -1; 749 } 750 ; 751 752resource_entries: 753 | 754 resource_entries resource_entry 755 ; 756 757resource_entry: 758 replication_statement 759 | 760 checksum_statement 761 | 762 compression_statement 763 | 764 timeout_statement 765 | 766 exec_statement 767 | 768 name_statement 769 | 770 local_statement 771 | 772 resource_node_statement 773 ; 774 775name_statement: NAME STR 776 { 777 switch (depth) { 778 case 1: 779 if (strlcpy(depth1_provname, $2, 780 sizeof(depth1_provname)) >= 781 sizeof(depth1_provname)) { 782 pjdlog_error("name argument is too long."); 783 free($2); 784 return (1); 785 } 786 break; 787 case 2: 788 if (!mynode) 789 break; 790 assert(curres != NULL); 791 if (strlcpy(curres->hr_provname, $2, 792 sizeof(curres->hr_provname)) >= 793 sizeof(curres->hr_provname)) { 794 pjdlog_error("name argument is too long."); 795 free($2); 796 return (1); 797 } 798 break; 799 default: 800 assert(!"name at wrong depth level"); 801 } 802 free($2); 803 } 804 ; 805 806local_statement: LOCAL STR 807 { 808 switch (depth) { 809 case 1: 810 if (strlcpy(depth1_localpath, $2, 811 sizeof(depth1_localpath)) >= 812 sizeof(depth1_localpath)) { 813 pjdlog_error("local argument is too long."); 814 free($2); 815 return (1); 816 } 817 break; 818 case 2: 819 if (!mynode) 820 break; 821 assert(curres != NULL); 822 if (strlcpy(curres->hr_localpath, $2, 823 sizeof(curres->hr_localpath)) >= 824 sizeof(curres->hr_localpath)) { 825 pjdlog_error("local argument is too long."); 826 free($2); 827 return (1); 828 } 829 break; 830 default: 831 assert(!"local at wrong depth level"); 832 } 833 free($2); 834 } 835 ; 836 837resource_node_statement:ON resource_node_start OB resource_node_entries CB 838 { 839 mynode = false; 840 } 841 ; 842 843resource_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 assert(!"invalid isitme() return value"); 857 } 858 } 859 free($1); 860 } 861 ; 862 863resource_node_entries: 864 | 865 resource_node_entries resource_node_entry 866 ; 867 868resource_node_entry: 869 name_statement 870 | 871 local_statement 872 | 873 remote_statement 874 | 875 source_statement 876 ; 877 878remote_statement: REMOTE remote_str 879 { 880 assert(depth == 2); 881 if (mynode) { 882 assert(curres != NULL); 883 if (strlcpy(curres->hr_remoteaddr, $2, 884 sizeof(curres->hr_remoteaddr)) >= 885 sizeof(curres->hr_remoteaddr)) { 886 pjdlog_error("remote argument is too long."); 887 free($2); 888 return (1); 889 } 890 } 891 free($2); 892 } 893 ; 894 895remote_str: 896 NONE { $$ = strdup("none"); } 897 | 898 STR { } 899 ; 900 901source_statement: SOURCE STR 902 { 903 assert(depth == 2); 904 if (mynode) { 905 assert(curres != NULL); 906 if (strlcpy(curres->hr_sourceaddr, $2, 907 sizeof(curres->hr_sourceaddr)) >= 908 sizeof(curres->hr_sourceaddr)) { 909 pjdlog_error("source argument is too long."); 910 free($2); 911 return (1); 912 } 913 } 914 free($2); 915 } 916 ; 917