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_pidfile[PATH_MAX]; 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 static int depth0_metaflush; 73 74 static char depth1_provname[PATH_MAX]; 75 static char depth1_localpath[PATH_MAX]; 76 static int depth1_metaflush; 77 78 extern void yyrestart(FILE *); 79 80 static int 81 isitme(const char *name) 82 { 83 char buf[MAXHOSTNAMELEN]; 84 char *pos; 85 size_t bufsize; 86 87 /* 88 * First check if the given 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 123 static bool 124 family_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 136 static int 137 node_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 174 void 175 yyerror(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 182 struct hastd_config * 183 yy_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 pjdlog_warning("Replication mode \"%s\" is not implemented, falling back to \"%s\".", 306 "memsync", "fullsync"); 307 curres->hr_replication = HAST_REPLICATION_FULLSYNC; 308 } 309 if (curres->hr_checksum == -1) { 310 /* 311 * Checksum is not set at resource-level. 312 * Use global or default setting. 313 */ 314 curres->hr_checksum = depth0_checksum; 315 } 316 if (curres->hr_compression == -1) { 317 /* 318 * Compression is not set at resource-level. 319 * Use global or default setting. 320 */ 321 curres->hr_compression = depth0_compression; 322 } 323 if (curres->hr_timeout == -1) { 324 /* 325 * Timeout is not set at resource-level. 326 * Use global or default setting. 327 */ 328 curres->hr_timeout = depth0_timeout; 329 } 330 if (curres->hr_exec[0] == '\0') { 331 /* 332 * Exec is not set at resource-level. 333 * Use global or default setting. 334 */ 335 strlcpy(curres->hr_exec, depth0_exec, 336 sizeof(curres->hr_exec)); 337 } 338 if (curres->hr_metaflush == -1) { 339 /* 340 * Metaflush is not set at resource-level. 341 * Use global or default setting. 342 */ 343 curres->hr_metaflush = depth0_metaflush; 344 } 345 } 346 347 return (lconfig); 348 } 349 350 void 351 yy_config_free(struct hastd_config *config) 352 { 353 struct hastd_listen *lst; 354 struct hast_resource *res; 355 356 while ((lst = TAILQ_FIRST(&depth0_listen)) != NULL) { 357 TAILQ_REMOVE(&depth0_listen, lst, hl_next); 358 free(lst); 359 } 360 while ((lst = TAILQ_FIRST(&config->hc_listen)) != NULL) { 361 TAILQ_REMOVE(&config->hc_listen, lst, hl_next); 362 free(lst); 363 } 364 while ((res = TAILQ_FIRST(&config->hc_resources)) != NULL) { 365 TAILQ_REMOVE(&config->hc_resources, res, hr_next); 366 free(res); 367 } 368 free(config); 369 } 370 %} 371 372 %token CONTROL PIDFILE LISTEN REPLICATION CHECKSUM COMPRESSION METAFLUSH 373 %token TIMEOUT EXEC RESOURCE NAME LOCAL REMOTE SOURCE ON OFF 374 %token FULLSYNC MEMSYNC ASYNC NONE CRC32 SHA256 HOLE LZF 375 %token NUM STR OB CB 376 377 %type <str> remote_str 378 %type <num> replication_type 379 %type <num> checksum_type 380 %type <num> compression_type 381 %type <num> boolean 382 383 %union 384 { 385 int num; 386 char *str; 387 } 388 389 %token <num> NUM 390 %token <str> STR 391 392 %% 393 394 statements: 395 | 396 statements statement 397 ; 398 399 statement: 400 control_statement 401 | 402 pidfile_statement 403 | 404 listen_statement 405 | 406 replication_statement 407 | 408 checksum_statement 409 | 410 compression_statement 411 | 412 timeout_statement 413 | 414 exec_statement 415 | 416 metaflush_statement 417 | 418 node_statement 419 | 420 resource_statement 421 ; 422 423 control_statement: CONTROL STR 424 { 425 switch (depth) { 426 case 0: 427 if (strlcpy(depth0_control, $2, 428 sizeof(depth0_control)) >= 429 sizeof(depth0_control)) { 430 pjdlog_error("control argument is too long."); 431 free($2); 432 return (1); 433 } 434 break; 435 case 1: 436 if (!mynode) 437 break; 438 if (strlcpy(lconfig->hc_controladdr, $2, 439 sizeof(lconfig->hc_controladdr)) >= 440 sizeof(lconfig->hc_controladdr)) { 441 pjdlog_error("control argument is too long."); 442 free($2); 443 return (1); 444 } 445 break; 446 default: 447 PJDLOG_ABORT("control at wrong depth level"); 448 } 449 free($2); 450 } 451 ; 452 453 pidfile_statement: PIDFILE STR 454 { 455 switch (depth) { 456 case 0: 457 if (strlcpy(depth0_pidfile, $2, 458 sizeof(depth0_pidfile)) >= 459 sizeof(depth0_pidfile)) { 460 pjdlog_error("pidfile argument is too long."); 461 free($2); 462 return (1); 463 } 464 break; 465 case 1: 466 if (!mynode) 467 break; 468 if (strlcpy(lconfig->hc_pidfile, $2, 469 sizeof(lconfig->hc_pidfile)) >= 470 sizeof(lconfig->hc_pidfile)) { 471 pjdlog_error("pidfile argument is too long."); 472 free($2); 473 return (1); 474 } 475 break; 476 default: 477 PJDLOG_ABORT("pidfile at wrong depth level"); 478 } 479 free($2); 480 } 481 ; 482 483 listen_statement: LISTEN STR 484 { 485 struct hastd_listen *lst; 486 487 lst = calloc(1, sizeof(*lst)); 488 if (lst == NULL) { 489 pjdlog_error("Unable to allocate memory for listen address."); 490 free($2); 491 return (1); 492 } 493 if (strlcpy(lst->hl_addr, $2, sizeof(lst->hl_addr)) >= 494 sizeof(lst->hl_addr)) { 495 pjdlog_error("listen argument is too long."); 496 free($2); 497 free(lst); 498 return (1); 499 } 500 switch (depth) { 501 case 0: 502 TAILQ_INSERT_TAIL(&depth0_listen, lst, hl_next); 503 break; 504 case 1: 505 if (mynode) 506 TAILQ_INSERT_TAIL(&depth0_listen, lst, hl_next); 507 else 508 free(lst); 509 break; 510 default: 511 PJDLOG_ABORT("listen at wrong depth level"); 512 } 513 free($2); 514 } 515 ; 516 517 replication_statement: REPLICATION replication_type 518 { 519 switch (depth) { 520 case 0: 521 depth0_replication = $2; 522 break; 523 case 1: 524 PJDLOG_ASSERT(curres != NULL); 525 curres->hr_replication = $2; 526 break; 527 default: 528 PJDLOG_ABORT("replication at wrong depth level"); 529 } 530 } 531 ; 532 533 replication_type: 534 FULLSYNC { $$ = HAST_REPLICATION_FULLSYNC; } 535 | 536 MEMSYNC { $$ = HAST_REPLICATION_MEMSYNC; } 537 | 538 ASYNC { $$ = HAST_REPLICATION_ASYNC; } 539 ; 540 541 checksum_statement: CHECKSUM checksum_type 542 { 543 switch (depth) { 544 case 0: 545 depth0_checksum = $2; 546 break; 547 case 1: 548 PJDLOG_ASSERT(curres != NULL); 549 curres->hr_checksum = $2; 550 break; 551 default: 552 PJDLOG_ABORT("checksum at wrong depth level"); 553 } 554 } 555 ; 556 557 checksum_type: 558 NONE { $$ = HAST_CHECKSUM_NONE; } 559 | 560 CRC32 { $$ = HAST_CHECKSUM_CRC32; } 561 | 562 SHA256 { $$ = HAST_CHECKSUM_SHA256; } 563 ; 564 565 compression_statement: COMPRESSION compression_type 566 { 567 switch (depth) { 568 case 0: 569 depth0_compression = $2; 570 break; 571 case 1: 572 PJDLOG_ASSERT(curres != NULL); 573 curres->hr_compression = $2; 574 break; 575 default: 576 PJDLOG_ABORT("compression at wrong depth level"); 577 } 578 } 579 ; 580 581 compression_type: 582 NONE { $$ = HAST_COMPRESSION_NONE; } 583 | 584 HOLE { $$ = HAST_COMPRESSION_HOLE; } 585 | 586 LZF { $$ = HAST_COMPRESSION_LZF; } 587 ; 588 589 timeout_statement: TIMEOUT NUM 590 { 591 if ($2 <= 0) { 592 pjdlog_error("Negative or zero timeout."); 593 return (1); 594 } 595 switch (depth) { 596 case 0: 597 depth0_timeout = $2; 598 break; 599 case 1: 600 PJDLOG_ASSERT(curres != NULL); 601 curres->hr_timeout = $2; 602 break; 603 default: 604 PJDLOG_ABORT("timeout at wrong depth level"); 605 } 606 } 607 ; 608 609 exec_statement: EXEC STR 610 { 611 switch (depth) { 612 case 0: 613 if (strlcpy(depth0_exec, $2, sizeof(depth0_exec)) >= 614 sizeof(depth0_exec)) { 615 pjdlog_error("Exec path is too long."); 616 free($2); 617 return (1); 618 } 619 break; 620 case 1: 621 PJDLOG_ASSERT(curres != NULL); 622 if (strlcpy(curres->hr_exec, $2, 623 sizeof(curres->hr_exec)) >= 624 sizeof(curres->hr_exec)) { 625 pjdlog_error("Exec path is too long."); 626 free($2); 627 return (1); 628 } 629 break; 630 default: 631 PJDLOG_ABORT("exec at wrong depth level"); 632 } 633 free($2); 634 } 635 ; 636 637 metaflush_statement: METAFLUSH boolean 638 { 639 switch (depth) { 640 case 0: 641 depth0_metaflush = $2; 642 break; 643 case 1: 644 PJDLOG_ASSERT(curres != NULL); 645 depth1_metaflush = $2; 646 break; 647 case 2: 648 if (!mynode) 649 break; 650 PJDLOG_ASSERT(curres != NULL); 651 curres->hr_metaflush = $2; 652 break; 653 default: 654 PJDLOG_ABORT("metaflush at wrong depth level"); 655 } 656 } 657 ; 658 659 boolean: 660 ON { $$ = 1; } 661 | 662 OFF { $$ = 0; } 663 ; 664 665 node_statement: ON node_start OB node_entries CB 666 { 667 mynode = false; 668 } 669 ; 670 671 node_start: STR 672 { 673 switch (isitme($1)) { 674 case -1: 675 free($1); 676 return (1); 677 case 0: 678 break; 679 case 1: 680 mynode = true; 681 break; 682 default: 683 PJDLOG_ABORT("invalid isitme() return value"); 684 } 685 free($1); 686 } 687 ; 688 689 node_entries: 690 | 691 node_entries node_entry 692 ; 693 694 node_entry: 695 control_statement 696 | 697 pidfile_statement 698 | 699 listen_statement 700 ; 701 702 resource_statement: RESOURCE resource_start OB resource_entries CB 703 { 704 if (curres != NULL) { 705 /* 706 * There must be section for this node, at least with 707 * remote address configuration. 708 */ 709 if (!hadmynode) { 710 char *names; 711 712 if (node_names(&names) != 0) 713 return (1); 714 pjdlog_error("No resource %s configuration for this node (acceptable node names: %s).", 715 curres->hr_name, names); 716 return (1); 717 } 718 719 /* 720 * Let's see if there are some resource-level settings 721 * that we can use for node-level settings. 722 */ 723 if (curres->hr_provname[0] == '\0' && 724 depth1_provname[0] != '\0') { 725 /* 726 * Provider name is not set at node-level, 727 * but is set at resource-level, use it. 728 */ 729 strlcpy(curres->hr_provname, depth1_provname, 730 sizeof(curres->hr_provname)); 731 } 732 if (curres->hr_localpath[0] == '\0' && 733 depth1_localpath[0] != '\0') { 734 /* 735 * Path to local provider is not set at 736 * node-level, but is set at resource-level, 737 * use it. 738 */ 739 strlcpy(curres->hr_localpath, depth1_localpath, 740 sizeof(curres->hr_localpath)); 741 } 742 if (curres->hr_metaflush == -1 && depth1_metaflush != -1) { 743 /* 744 * Metaflush is not set at node-level, 745 * but is set at resource-level, use it. 746 */ 747 curres->hr_metaflush = depth1_metaflush; 748 } 749 750 /* 751 * If provider name is not given, use resource name 752 * as provider name. 753 */ 754 if (curres->hr_provname[0] == '\0') { 755 strlcpy(curres->hr_provname, curres->hr_name, 756 sizeof(curres->hr_provname)); 757 } 758 759 /* 760 * Remote address has to be configured at this point. 761 */ 762 if (curres->hr_remoteaddr[0] == '\0') { 763 pjdlog_error("Remote address not configured for resource %s.", 764 curres->hr_name); 765 return (1); 766 } 767 /* 768 * Path to local provider has to be configured at this 769 * point. 770 */ 771 if (curres->hr_localpath[0] == '\0') { 772 pjdlog_error("Path to local component not configured for resource %s.", 773 curres->hr_name); 774 return (1); 775 } 776 777 /* Put it onto resource list. */ 778 TAILQ_INSERT_TAIL(&lconfig->hc_resources, curres, hr_next); 779 curres = NULL; 780 } 781 } 782 ; 783 784 resource_start: STR 785 { 786 /* Check if there is no duplicate entry. */ 787 TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) { 788 if (strcmp(curres->hr_name, $1) == 0) { 789 pjdlog_error("Resource %s configured more than once.", 790 curres->hr_name); 791 free($1); 792 return (1); 793 } 794 } 795 796 /* 797 * Clear those, so we can tell if they were set at 798 * resource-level or not. 799 */ 800 depth1_provname[0] = '\0'; 801 depth1_localpath[0] = '\0'; 802 depth1_metaflush = -1; 803 hadmynode = false; 804 805 curres = calloc(1, sizeof(*curres)); 806 if (curres == NULL) { 807 pjdlog_error("Unable to allocate memory for resource."); 808 free($1); 809 return (1); 810 } 811 if (strlcpy(curres->hr_name, $1, 812 sizeof(curres->hr_name)) >= 813 sizeof(curres->hr_name)) { 814 pjdlog_error("Resource name is too long."); 815 free(curres); 816 free($1); 817 return (1); 818 } 819 free($1); 820 curres->hr_role = HAST_ROLE_INIT; 821 curres->hr_previous_role = HAST_ROLE_INIT; 822 curres->hr_replication = -1; 823 curres->hr_checksum = -1; 824 curres->hr_compression = -1; 825 curres->hr_timeout = -1; 826 curres->hr_exec[0] = '\0'; 827 curres->hr_provname[0] = '\0'; 828 curres->hr_localpath[0] = '\0'; 829 curres->hr_localfd = -1; 830 curres->hr_localflush = true; 831 curres->hr_metaflush = -1; 832 curres->hr_remoteaddr[0] = '\0'; 833 curres->hr_sourceaddr[0] = '\0'; 834 curres->hr_ggateunit = -1; 835 } 836 ; 837 838 resource_entries: 839 | 840 resource_entries resource_entry 841 ; 842 843 resource_entry: 844 replication_statement 845 | 846 checksum_statement 847 | 848 compression_statement 849 | 850 timeout_statement 851 | 852 exec_statement 853 | 854 metaflush_statement 855 | 856 name_statement 857 | 858 local_statement 859 | 860 resource_node_statement 861 ; 862 863 name_statement: NAME STR 864 { 865 switch (depth) { 866 case 1: 867 if (strlcpy(depth1_provname, $2, 868 sizeof(depth1_provname)) >= 869 sizeof(depth1_provname)) { 870 pjdlog_error("name argument is too long."); 871 free($2); 872 return (1); 873 } 874 break; 875 case 2: 876 if (!mynode) 877 break; 878 PJDLOG_ASSERT(curres != NULL); 879 if (strlcpy(curres->hr_provname, $2, 880 sizeof(curres->hr_provname)) >= 881 sizeof(curres->hr_provname)) { 882 pjdlog_error("name argument is too long."); 883 free($2); 884 return (1); 885 } 886 break; 887 default: 888 PJDLOG_ABORT("name at wrong depth level"); 889 } 890 free($2); 891 } 892 ; 893 894 local_statement: LOCAL STR 895 { 896 switch (depth) { 897 case 1: 898 if (strlcpy(depth1_localpath, $2, 899 sizeof(depth1_localpath)) >= 900 sizeof(depth1_localpath)) { 901 pjdlog_error("local argument is too long."); 902 free($2); 903 return (1); 904 } 905 break; 906 case 2: 907 if (!mynode) 908 break; 909 PJDLOG_ASSERT(curres != NULL); 910 if (strlcpy(curres->hr_localpath, $2, 911 sizeof(curres->hr_localpath)) >= 912 sizeof(curres->hr_localpath)) { 913 pjdlog_error("local argument is too long."); 914 free($2); 915 return (1); 916 } 917 break; 918 default: 919 PJDLOG_ABORT("local at wrong depth level"); 920 } 921 free($2); 922 } 923 ; 924 925 resource_node_statement:ON resource_node_start OB resource_node_entries CB 926 { 927 mynode = false; 928 } 929 ; 930 931 resource_node_start: STR 932 { 933 if (curres != NULL) { 934 switch (isitme($1)) { 935 case -1: 936 free($1); 937 return (1); 938 case 0: 939 break; 940 case 1: 941 mynode = hadmynode = true; 942 break; 943 default: 944 PJDLOG_ABORT("invalid isitme() return value"); 945 } 946 } 947 free($1); 948 } 949 ; 950 951 resource_node_entries: 952 | 953 resource_node_entries resource_node_entry 954 ; 955 956 resource_node_entry: 957 name_statement 958 | 959 local_statement 960 | 961 remote_statement 962 | 963 source_statement 964 | 965 metaflush_statement 966 ; 967 968 remote_statement: REMOTE remote_str 969 { 970 PJDLOG_ASSERT(depth == 2); 971 if (mynode) { 972 PJDLOG_ASSERT(curres != NULL); 973 if (strlcpy(curres->hr_remoteaddr, $2, 974 sizeof(curres->hr_remoteaddr)) >= 975 sizeof(curres->hr_remoteaddr)) { 976 pjdlog_error("remote argument is too long."); 977 free($2); 978 return (1); 979 } 980 } 981 free($2); 982 } 983 ; 984 985 remote_str: 986 NONE { $$ = strdup("none"); } 987 | 988 STR { } 989 ; 990 991 source_statement: SOURCE STR 992 { 993 PJDLOG_ASSERT(depth == 2); 994 if (mynode) { 995 PJDLOG_ASSERT(curres != NULL); 996 if (strlcpy(curres->hr_sourceaddr, $2, 997 sizeof(curres->hr_sourceaddr)) >= 998 sizeof(curres->hr_sourceaddr)) { 999 pjdlog_error("source argument is too long."); 1000 free($2); 1001 return (1); 1002 } 1003 } 1004 free($2); 1005 } 1006 ; 1007