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