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