parse.y revision 225830
150397Sobrien%{ 2169689Skan/*- 390075Sobrien * Copyright (c) 2009-2010 The FreeBSD Foundation 4122180Skan * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net> 550397Sobrien * All rights reserved. 6132718Skan * 750397Sobrien * This software was developed by Pawel Jakub Dawidek under sponsorship from 8132718Skan * the FreeBSD Foundation. 950397Sobrien * 1050397Sobrien * Redistribution and use in source and binary forms, with or without 1150397Sobrien * modification, are permitted provided that the following conditions 1250397Sobrien * are met: 13132718Skan * 1. Redistributions of source code must retain the above copyright 1450397Sobrien * notice, this list of conditions and the following disclaimer. 1550397Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1650397Sobrien * notice, this list of conditions and the following disclaimer in the 1750397Sobrien * documentation and/or other materials provided with the distribution. 1850397Sobrien * 19132718Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 20169689Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21169689Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2250397Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 23122180Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2450397Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2550397Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2690075Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2750397Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2850397Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2990075Sobrien * SUCH DAMAGE. 3050397Sobrien * 3150397Sobrien * $FreeBSD: head/sbin/hastd/parse.y 225830 2011-09-28 13:08:51Z pjd $ 32122180Skan */ 33122180Skan 34122180Skan#include <sys/param.h> /* MAXHOSTNAMELEN */ 35122180Skan#include <sys/queue.h> 36122180Skan#include <sys/socket.h> 37122180Skan#include <sys/sysctl.h> 38122180Skan 39122180Skan#include <arpa/inet.h> 40122180Skan 41122180Skan#include <err.h> 42122180Skan#include <errno.h> 43122180Skan#include <stdio.h> 44122180Skan#include <string.h> 45122180Skan#include <sysexits.h> 4650397Sobrien#include <unistd.h> 47122180Skan 48122180Skan#include <pjdlog.h> 49122180Skan 5050397Sobrien#include "hast.h" 5150397Sobrien 5250397Sobrienextern int depth; 5350397Sobrienextern int lineno; 5450397Sobrien 5550397Sobrienextern FILE *yyin; 5650397Sobrienextern char *yytext; 57122180Skan 5850397Sobrienstatic struct hastd_config *lconfig; 5950397Sobrienstatic struct hast_resource *curres; 60122180Skanstatic bool mynode, hadmynode; 6150397Sobrien 62122180Skanstatic char depth0_control[HAST_ADDRSIZE]; 63122180Skanstatic char depth0_listen_tcp4[HAST_ADDRSIZE]; 64117395Skanstatic char depth0_listen_tcp6[HAST_ADDRSIZE]; 65117395Skanstatic TAILQ_HEAD(, hastd_listen) depth0_listen; 66122180Skanstatic int depth0_replication; 6750397Sobrienstatic int depth0_checksum; 68122180Skanstatic int depth0_compression; 69122180Skanstatic int depth0_timeout; 7050397Sobrienstatic char depth0_exec[PATH_MAX]; 7150397Sobrienstatic int depth0_metaflush; 72122180Skan 7350397Sobrienstatic char depth1_provname[PATH_MAX]; 7450397Sobrienstatic char depth1_localpath[PATH_MAX]; 7550397Sobrienstatic int depth1_metaflush; 7650397Sobrien 7750397Sobrienextern void yyrestart(FILE *); 7850397Sobrien 7950397Sobrienstatic int 8050397Sobrienisitme(const char *name) 8150397Sobrien{ 8250397Sobrien char buf[MAXHOSTNAMELEN]; 8350397Sobrien char *pos; 8450397Sobrien size_t bufsize; 8550397Sobrien 8650397Sobrien /* 8750397Sobrien * First check if the give name matches our full hostname. 8890075Sobrien */ 8990075Sobrien if (gethostname(buf, sizeof(buf)) < 0) { 9050397Sobrien pjdlog_errno(LOG_ERR, "gethostname() failed"); 9150397Sobrien return (-1); 9250397Sobrien } 9350397Sobrien if (strcmp(buf, name) == 0) 9450397Sobrien return (1); 9550397Sobrien 9650397Sobrien /* 9750397Sobrien * Now check if it matches first part of the host name. 98122180Skan */ 9950397Sobrien pos = strchr(buf, '.'); 10050397Sobrien if (pos != NULL && (size_t)(pos - buf) == strlen(name) && 10150397Sobrien strncmp(buf, name, pos - buf) == 0) { 10250397Sobrien return (1); 103122180Skan } 10450397Sobrien 10550397Sobrien /* 10650397Sobrien * At the end check if name is equal to our host's UUID. 10750397Sobrien */ 10850397Sobrien bufsize = sizeof(buf); 10950397Sobrien if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) { 11050397Sobrien pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed"); 11150397Sobrien return (-1); 11250397Sobrien } 11350397Sobrien if (strcasecmp(buf, name) == 0) 11450397Sobrien return (1); 11550397Sobrien 11650397Sobrien /* 117122180Skan * Looks like this isn't about us. 11850397Sobrien */ 11950397Sobrien return (0); 12050397Sobrien} 12150397Sobrien 12250397Sobrienstatic bool 12350397Sobrienfamily_supported(int family) 12450397Sobrien{ 12550397Sobrien int sock; 12650397Sobrien 12750397Sobrien sock = socket(family, SOCK_STREAM, 0); 12850397Sobrien if (sock == -1 && errno == EPROTONOSUPPORT) 12950397Sobrien return (false); 13050397Sobrien if (sock >= 0) 13150397Sobrien (void)close(sock); 13250397Sobrien return (true); 133122180Skan} 134122180Skan 135122180Skanstatic int 136122180Skannode_names(char **namesp) 137122180Skan{ 138122180Skan static char names[MAXHOSTNAMELEN * 3]; 139122180Skan char buf[MAXHOSTNAMELEN]; 140122180Skan char *pos; 141122180Skan size_t bufsize; 142122180Skan 143122180Skan if (gethostname(buf, sizeof(buf)) < 0) { 144122180Skan pjdlog_errno(LOG_ERR, "gethostname() failed"); 145122180Skan return (-1); 146132718Skan } 147122180Skan 148122180Skan /* First component of the host name. */ 149122180Skan pos = strchr(buf, '.'); 150122180Skan if (pos != NULL && pos != buf) { 151122180Skan (void)strlcpy(names, buf, MIN((size_t)(pos - buf + 1), 152122180Skan sizeof(names))); 153122180Skan (void)strlcat(names, ", ", sizeof(names)); 15450397Sobrien } 15550397Sobrien 156122180Skan /* Full host name. */ 157122180Skan (void)strlcat(names, buf, sizeof(names)); 158122180Skan (void)strlcat(names, ", ", sizeof(names)); 159122180Skan 160122180Skan /* Host UUID. */ 161122180Skan bufsize = sizeof(buf); 162122180Skan if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) { 163122180Skan pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed"); 164122180Skan return (-1); 165122180Skan } 166122180Skan (void)strlcat(names, buf, sizeof(names)); 167122180Skan 168122180Skan *namesp = names; 169122180Skan 17050397Sobrien return (0); 17150397Sobrien} 17250397Sobrien 17350397Sobrienvoid 174122180Skanyyerror(const char *str) 17550397Sobrien{ 17650397Sobrien 177122180Skan pjdlog_error("Unable to parse configuration file at line %d near '%s': %s", 178122180Skan lineno, yytext, str); 17950397Sobrien} 18050397Sobrien 181122180Skanstruct hastd_config * 182122180Skanyy_config_parse(const char *config, bool exitonerror) 183122180Skan{ 184122180Skan int ret; 185122180Skan 18650397Sobrien curres = NULL; 18750397Sobrien mynode = false; 18850397Sobrien depth = 0; 189122180Skan lineno = 0; 190122180Skan 191122180Skan depth0_timeout = HAST_TIMEOUT; 19250397Sobrien depth0_replication = HAST_REPLICATION_FULLSYNC; 193122180Skan depth0_checksum = HAST_CHECKSUM_NONE; 194122180Skan depth0_compression = HAST_COMPRESSION_HOLE; 195122180Skan strlcpy(depth0_control, HAST_CONTROL, sizeof(depth0_control)); 19650397Sobrien TAILQ_INIT(&depth0_listen); 19750397Sobrien strlcpy(depth0_listen_tcp4, HASTD_LISTEN_TCP4, 198122180Skan sizeof(depth0_listen_tcp4)); 199122180Skan strlcpy(depth0_listen_tcp6, HASTD_LISTEN_TCP6, 200122180Skan sizeof(depth0_listen_tcp6)); 201122180Skan depth0_exec[0] = '\0'; 202122180Skan depth0_metaflush = 1; 203122180Skan 204122180Skan lconfig = calloc(1, sizeof(*lconfig)); 205122180Skan if (lconfig == NULL) { 20650397Sobrien pjdlog_error("Unable to allocate memory for configuration."); 20750397Sobrien if (exitonerror) 20850397Sobrien exit(EX_TEMPFAIL); 209122180Skan return (NULL); 21050397Sobrien } 211122180Skan 212122180Skan TAILQ_INIT(&lconfig->hc_listen); 213122180Skan TAILQ_INIT(&lconfig->hc_resources); 214122180Skan 215122180Skan yyin = fopen(config, "r"); 216122180Skan if (yyin == NULL) { 217122180Skan pjdlog_errno(LOG_ERR, "Unable to open configuration file %s", 218122180Skan config); 219122180Skan yy_config_free(lconfig); 220122180Skan if (exitonerror) 221122180Skan exit(EX_OSFILE); 222122180Skan return (NULL); 223122180Skan } 224122180Skan yyrestart(yyin); 225117395Skan ret = yyparse(); 22650397Sobrien fclose(yyin); 22750397Sobrien if (ret != 0) { 228117395Skan yy_config_free(lconfig); 229122180Skan if (exitonerror) 23050397Sobrien exit(EX_CONFIG); 23150397Sobrien return (NULL); 232117395Skan } 23350397Sobrien 23450397Sobrien /* 23550397Sobrien * Let's see if everything is set up. 23650397Sobrien */ 23750397Sobrien if (lconfig->hc_controladdr[0] == '\0') { 23850397Sobrien strlcpy(lconfig->hc_controladdr, depth0_control, 23950397Sobrien sizeof(lconfig->hc_controladdr)); 24050397Sobrien } 24150397Sobrien if (!TAILQ_EMPTY(&depth0_listen)) 24250397Sobrien TAILQ_CONCAT(&lconfig->hc_listen, &depth0_listen, hl_next); 24350397Sobrien if (TAILQ_EMPTY(&lconfig->hc_listen)) { 24450397Sobrien struct hastd_listen *lst; 24550397Sobrien 24650397Sobrien if (family_supported(AF_INET)) { 24750397Sobrien lst = calloc(1, sizeof(*lst)); 24850397Sobrien if (lst == NULL) { 24950397Sobrien pjdlog_error("Unable to allocate memory for listen address."); 25050397Sobrien yy_config_free(lconfig); 251117395Skan if (exitonerror) 25250397Sobrien exit(EX_TEMPFAIL); 25350397Sobrien return (NULL); 25450397Sobrien } 255122180Skan (void)strlcpy(lst->hl_addr, depth0_listen_tcp4, 256169689Skan sizeof(lst->hl_addr)); 25750397Sobrien TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next); 25850397Sobrien } else { 259122180Skan pjdlog_debug(1, 260122180Skan "No IPv4 support in the kernel, not listening on IPv4 address."); 261122180Skan } 262122180Skan if (family_supported(AF_INET6)) { 26350397Sobrien lst = calloc(1, sizeof(*lst)); 26450397Sobrien if (lst == NULL) { 26550397Sobrien pjdlog_error("Unable to allocate memory for listen address."); 26650397Sobrien yy_config_free(lconfig); 26750397Sobrien if (exitonerror) 26850397Sobrien exit(EX_TEMPFAIL); 269122180Skan return (NULL); 270122180Skan } 271122180Skan (void)strlcpy(lst->hl_addr, depth0_listen_tcp6, 272122180Skan sizeof(lst->hl_addr)); 273132718Skan TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next); 27450397Sobrien } else { 27550397Sobrien pjdlog_debug(1, 27650397Sobrien "No IPv6 support in the kernel, not listening on IPv6 address."); 277122180Skan } 27850397Sobrien if (TAILQ_EMPTY(&lconfig->hc_listen)) { 27990075Sobrien pjdlog_error("No address to listen on."); 28090075Sobrien yy_config_free(lconfig); 28190075Sobrien if (exitonerror) 28290075Sobrien exit(EX_TEMPFAIL); 28390075Sobrien return (NULL); 28490075Sobrien } 28590075Sobrien } 28690075Sobrien TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) { 28790075Sobrien PJDLOG_ASSERT(curres->hr_provname[0] != '\0'); 28890075Sobrien PJDLOG_ASSERT(curres->hr_localpath[0] != '\0'); 28990075Sobrien PJDLOG_ASSERT(curres->hr_remoteaddr[0] != '\0'); 29090075Sobrien 29190075Sobrien if (curres->hr_replication == -1) { 29290075Sobrien /* 29390075Sobrien * Replication is not set at resource-level. 29490075Sobrien * Use global or default setting. 29590075Sobrien */ 29690075Sobrien curres->hr_replication = depth0_replication; 29790075Sobrien } 29890075Sobrien if (curres->hr_replication == HAST_REPLICATION_MEMSYNC || 29990075Sobrien curres->hr_replication == HAST_REPLICATION_ASYNC) { 30090075Sobrien pjdlog_warning("Replication mode \"%s\" is not implemented, falling back to \"%s\".", 30190075Sobrien curres->hr_replication == HAST_REPLICATION_MEMSYNC ? 30290075Sobrien "memsync" : "async", "fullsync"); 30390075Sobrien curres->hr_replication = HAST_REPLICATION_FULLSYNC; 30490075Sobrien } 30590075Sobrien if (curres->hr_checksum == -1) { 30690075Sobrien /* 30790075Sobrien * Checksum is not set at resource-level. 30890075Sobrien * Use global or default setting. 30990075Sobrien */ 31090075Sobrien curres->hr_checksum = depth0_checksum; 31190075Sobrien } 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 if (curres->hr_metaflush == -1) { 335 /* 336 * Metaflush is not set at resource-level. 337 * Use global or default setting. 338 */ 339 curres->hr_metaflush = depth0_metaflush; 340 } 341 } 342 343 return (lconfig); 344} 345 346void 347yy_config_free(struct hastd_config *config) 348{ 349 struct hastd_listen *lst; 350 struct hast_resource *res; 351 352 while ((lst = TAILQ_FIRST(&depth0_listen)) != NULL) { 353 TAILQ_REMOVE(&depth0_listen, lst, hl_next); 354 free(lst); 355 } 356 while ((lst = TAILQ_FIRST(&config->hc_listen)) != NULL) { 357 TAILQ_REMOVE(&config->hc_listen, lst, hl_next); 358 free(lst); 359 } 360 while ((res = TAILQ_FIRST(&config->hc_resources)) != NULL) { 361 TAILQ_REMOVE(&config->hc_resources, res, hr_next); 362 free(res); 363 } 364 free(config); 365} 366%} 367 368%token CONTROL LISTEN PORT REPLICATION CHECKSUM COMPRESSION METAFLUSH 369%token TIMEOUT EXEC EXTENTSIZE RESOURCE NAME LOCAL REMOTE SOURCE ON OFF 370%token FULLSYNC MEMSYNC ASYNC NONE CRC32 SHA256 HOLE LZF 371%token NUM STR OB CB 372 373%type <str> remote_str 374%type <num> replication_type 375%type <num> checksum_type 376%type <num> compression_type 377%type <num> boolean 378 379%union 380{ 381 int num; 382 char *str; 383} 384 385%token <num> NUM 386%token <str> STR 387 388%% 389 390statements: 391 | 392 statements statement 393 ; 394 395statement: 396 control_statement 397 | 398 listen_statement 399 | 400 replication_statement 401 | 402 checksum_statement 403 | 404 compression_statement 405 | 406 timeout_statement 407 | 408 exec_statement 409 | 410 metaflush_statement 411 | 412 node_statement 413 | 414 resource_statement 415 ; 416 417control_statement: CONTROL STR 418 { 419 switch (depth) { 420 case 0: 421 if (strlcpy(depth0_control, $2, 422 sizeof(depth0_control)) >= 423 sizeof(depth0_control)) { 424 pjdlog_error("control argument is too long."); 425 free($2); 426 return (1); 427 } 428 break; 429 case 1: 430 if (!mynode) 431 break; 432 if (strlcpy(lconfig->hc_controladdr, $2, 433 sizeof(lconfig->hc_controladdr)) >= 434 sizeof(lconfig->hc_controladdr)) { 435 pjdlog_error("control argument is too long."); 436 free($2); 437 return (1); 438 } 439 break; 440 default: 441 PJDLOG_ABORT("control at wrong depth level"); 442 } 443 free($2); 444 } 445 ; 446 447listen_statement: LISTEN STR 448 { 449 struct hastd_listen *lst; 450 451 lst = calloc(1, sizeof(*lst)); 452 if (lst == NULL) { 453 pjdlog_error("Unable to allocate memory for listen address."); 454 free($2); 455 return (1); 456 } 457 if (strlcpy(lst->hl_addr, $2, sizeof(lst->hl_addr)) >= 458 sizeof(lst->hl_addr)) { 459 pjdlog_error("listen argument is too long."); 460 free($2); 461 free(lst); 462 return (1); 463 } 464 switch (depth) { 465 case 0: 466 TAILQ_INSERT_TAIL(&depth0_listen, lst, hl_next); 467 break; 468 case 1: 469 if (mynode) 470 TAILQ_INSERT_TAIL(&depth0_listen, lst, hl_next); 471 else 472 free(lst); 473 break; 474 default: 475 PJDLOG_ABORT("listen at wrong depth level"); 476 } 477 free($2); 478 } 479 ; 480 481replication_statement: REPLICATION replication_type 482 { 483 switch (depth) { 484 case 0: 485 depth0_replication = $2; 486 break; 487 case 1: 488 PJDLOG_ASSERT(curres != NULL); 489 curres->hr_replication = $2; 490 break; 491 default: 492 PJDLOG_ABORT("replication at wrong depth level"); 493 } 494 } 495 ; 496 497replication_type: 498 FULLSYNC { $$ = HAST_REPLICATION_FULLSYNC; } 499 | 500 MEMSYNC { $$ = HAST_REPLICATION_MEMSYNC; } 501 | 502 ASYNC { $$ = HAST_REPLICATION_ASYNC; } 503 ; 504 505checksum_statement: CHECKSUM checksum_type 506 { 507 switch (depth) { 508 case 0: 509 depth0_checksum = $2; 510 break; 511 case 1: 512 PJDLOG_ASSERT(curres != NULL); 513 curres->hr_checksum = $2; 514 break; 515 default: 516 PJDLOG_ABORT("checksum at wrong depth level"); 517 } 518 } 519 ; 520 521checksum_type: 522 NONE { $$ = HAST_CHECKSUM_NONE; } 523 | 524 CRC32 { $$ = HAST_CHECKSUM_CRC32; } 525 | 526 SHA256 { $$ = HAST_CHECKSUM_SHA256; } 527 ; 528 529compression_statement: COMPRESSION compression_type 530 { 531 switch (depth) { 532 case 0: 533 depth0_compression = $2; 534 break; 535 case 1: 536 PJDLOG_ASSERT(curres != NULL); 537 curres->hr_compression = $2; 538 break; 539 default: 540 PJDLOG_ABORT("compression at wrong depth level"); 541 } 542 } 543 ; 544 545compression_type: 546 NONE { $$ = HAST_COMPRESSION_NONE; } 547 | 548 HOLE { $$ = HAST_COMPRESSION_HOLE; } 549 | 550 LZF { $$ = HAST_COMPRESSION_LZF; } 551 ; 552 553timeout_statement: TIMEOUT NUM 554 { 555 if ($2 <= 0) { 556 pjdlog_error("Negative or zero timeout."); 557 return (1); 558 } 559 switch (depth) { 560 case 0: 561 depth0_timeout = $2; 562 break; 563 case 1: 564 PJDLOG_ASSERT(curres != NULL); 565 curres->hr_timeout = $2; 566 break; 567 default: 568 PJDLOG_ABORT("timeout at wrong depth level"); 569 } 570 } 571 ; 572 573exec_statement: EXEC STR 574 { 575 switch (depth) { 576 case 0: 577 if (strlcpy(depth0_exec, $2, sizeof(depth0_exec)) >= 578 sizeof(depth0_exec)) { 579 pjdlog_error("Exec path is too long."); 580 free($2); 581 return (1); 582 } 583 break; 584 case 1: 585 PJDLOG_ASSERT(curres != NULL); 586 if (strlcpy(curres->hr_exec, $2, 587 sizeof(curres->hr_exec)) >= 588 sizeof(curres->hr_exec)) { 589 pjdlog_error("Exec path is too long."); 590 free($2); 591 return (1); 592 } 593 break; 594 default: 595 PJDLOG_ABORT("exec at wrong depth level"); 596 } 597 free($2); 598 } 599 ; 600 601metaflush_statement: METAFLUSH boolean 602 { 603 switch (depth) { 604 case 0: 605 depth0_metaflush = $2; 606 break; 607 case 1: 608 PJDLOG_ASSERT(curres != NULL); 609 depth1_metaflush = $2; 610 break; 611 case 2: 612 if (!mynode) 613 break; 614 PJDLOG_ASSERT(curres != NULL); 615 curres->hr_metaflush = $2; 616 break; 617 default: 618 PJDLOG_ABORT("metaflush at wrong depth level"); 619 } 620 } 621 ; 622 623boolean: 624 ON { $$ = 1; } 625 | 626 OFF { $$ = 0; } 627 ; 628 629node_statement: ON node_start OB node_entries CB 630 { 631 mynode = false; 632 } 633 ; 634 635node_start: STR 636 { 637 switch (isitme($1)) { 638 case -1: 639 free($1); 640 return (1); 641 case 0: 642 break; 643 case 1: 644 mynode = true; 645 break; 646 default: 647 PJDLOG_ABORT("invalid isitme() return value"); 648 } 649 free($1); 650 } 651 ; 652 653node_entries: 654 | 655 node_entries node_entry 656 ; 657 658node_entry: 659 control_statement 660 | 661 listen_statement 662 ; 663 664resource_statement: RESOURCE resource_start OB resource_entries CB 665 { 666 if (curres != NULL) { 667 /* 668 * There must be section for this node, at least with 669 * remote address configuration. 670 */ 671 if (!hadmynode) { 672 char *names; 673 674 if (node_names(&names) != 0) 675 return (1); 676 pjdlog_error("No resource %s configuration for this node (acceptable node names: %s).", 677 curres->hr_name, names); 678 return (1); 679 } 680 681 /* 682 * Let's see if there are some resource-level settings 683 * that we can use for node-level settings. 684 */ 685 if (curres->hr_provname[0] == '\0' && 686 depth1_provname[0] != '\0') { 687 /* 688 * Provider name is not set at node-level, 689 * but is set at resource-level, use it. 690 */ 691 strlcpy(curres->hr_provname, depth1_provname, 692 sizeof(curres->hr_provname)); 693 } 694 if (curres->hr_localpath[0] == '\0' && 695 depth1_localpath[0] != '\0') { 696 /* 697 * Path to local provider is not set at 698 * node-level, but is set at resource-level, 699 * use it. 700 */ 701 strlcpy(curres->hr_localpath, depth1_localpath, 702 sizeof(curres->hr_localpath)); 703 } 704 if (curres->hr_metaflush == -1 && depth1_metaflush != -1) { 705 /* 706 * Metaflush is not set at node-level, 707 * but is set at resource-level, use it. 708 */ 709 curres->hr_metaflush = depth1_metaflush; 710 } 711 712 /* 713 * If provider name is not given, use resource name 714 * as provider name. 715 */ 716 if (curres->hr_provname[0] == '\0') { 717 strlcpy(curres->hr_provname, curres->hr_name, 718 sizeof(curres->hr_provname)); 719 } 720 721 /* 722 * Remote address has to be configured at this point. 723 */ 724 if (curres->hr_remoteaddr[0] == '\0') { 725 pjdlog_error("Remote address not configured for resource %s.", 726 curres->hr_name); 727 return (1); 728 } 729 /* 730 * Path to local provider has to be configured at this 731 * point. 732 */ 733 if (curres->hr_localpath[0] == '\0') { 734 pjdlog_error("Path to local component not configured for resource %s.", 735 curres->hr_name); 736 return (1); 737 } 738 739 /* Put it onto resource list. */ 740 TAILQ_INSERT_TAIL(&lconfig->hc_resources, curres, hr_next); 741 curres = NULL; 742 } 743 } 744 ; 745 746resource_start: STR 747 { 748 /* Check if there is no duplicate entry. */ 749 TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) { 750 if (strcmp(curres->hr_name, $1) == 0) { 751 pjdlog_error("Resource %s configured more than once.", 752 curres->hr_name); 753 free($1); 754 return (1); 755 } 756 } 757 758 /* 759 * Clear those, so we can tell if they were set at 760 * resource-level or not. 761 */ 762 depth1_provname[0] = '\0'; 763 depth1_localpath[0] = '\0'; 764 depth1_metaflush = -1; 765 hadmynode = false; 766 767 curres = calloc(1, sizeof(*curres)); 768 if (curres == NULL) { 769 pjdlog_error("Unable to allocate memory for resource."); 770 free($1); 771 return (1); 772 } 773 if (strlcpy(curres->hr_name, $1, 774 sizeof(curres->hr_name)) >= 775 sizeof(curres->hr_name)) { 776 pjdlog_error("Resource name is too long."); 777 free($1); 778 return (1); 779 } 780 free($1); 781 curres->hr_role = HAST_ROLE_INIT; 782 curres->hr_previous_role = HAST_ROLE_INIT; 783 curres->hr_replication = -1; 784 curres->hr_checksum = -1; 785 curres->hr_compression = -1; 786 curres->hr_timeout = -1; 787 curres->hr_exec[0] = '\0'; 788 curres->hr_provname[0] = '\0'; 789 curres->hr_localpath[0] = '\0'; 790 curres->hr_localfd = -1; 791 curres->hr_metaflush = -1; 792 curres->hr_remoteaddr[0] = '\0'; 793 curres->hr_sourceaddr[0] = '\0'; 794 curres->hr_ggateunit = -1; 795 } 796 ; 797 798resource_entries: 799 | 800 resource_entries resource_entry 801 ; 802 803resource_entry: 804 replication_statement 805 | 806 checksum_statement 807 | 808 compression_statement 809 | 810 timeout_statement 811 | 812 exec_statement 813 | 814 metaflush_statement 815 | 816 name_statement 817 | 818 local_statement 819 | 820 resource_node_statement 821 ; 822 823name_statement: NAME STR 824 { 825 switch (depth) { 826 case 1: 827 if (strlcpy(depth1_provname, $2, 828 sizeof(depth1_provname)) >= 829 sizeof(depth1_provname)) { 830 pjdlog_error("name argument is too long."); 831 free($2); 832 return (1); 833 } 834 break; 835 case 2: 836 if (!mynode) 837 break; 838 PJDLOG_ASSERT(curres != NULL); 839 if (strlcpy(curres->hr_provname, $2, 840 sizeof(curres->hr_provname)) >= 841 sizeof(curres->hr_provname)) { 842 pjdlog_error("name argument is too long."); 843 free($2); 844 return (1); 845 } 846 break; 847 default: 848 PJDLOG_ABORT("name at wrong depth level"); 849 } 850 free($2); 851 } 852 ; 853 854local_statement: LOCAL STR 855 { 856 switch (depth) { 857 case 1: 858 if (strlcpy(depth1_localpath, $2, 859 sizeof(depth1_localpath)) >= 860 sizeof(depth1_localpath)) { 861 pjdlog_error("local argument is too long."); 862 free($2); 863 return (1); 864 } 865 break; 866 case 2: 867 if (!mynode) 868 break; 869 PJDLOG_ASSERT(curres != NULL); 870 if (strlcpy(curres->hr_localpath, $2, 871 sizeof(curres->hr_localpath)) >= 872 sizeof(curres->hr_localpath)) { 873 pjdlog_error("local argument is too long."); 874 free($2); 875 return (1); 876 } 877 break; 878 default: 879 PJDLOG_ABORT("local at wrong depth level"); 880 } 881 free($2); 882 } 883 ; 884 885resource_node_statement:ON resource_node_start OB resource_node_entries CB 886 { 887 mynode = false; 888 } 889 ; 890 891resource_node_start: STR 892 { 893 if (curres != NULL) { 894 switch (isitme($1)) { 895 case -1: 896 free($1); 897 return (1); 898 case 0: 899 break; 900 case 1: 901 mynode = hadmynode = true; 902 break; 903 default: 904 PJDLOG_ABORT("invalid isitme() return value"); 905 } 906 } 907 free($1); 908 } 909 ; 910 911resource_node_entries: 912 | 913 resource_node_entries resource_node_entry 914 ; 915 916resource_node_entry: 917 name_statement 918 | 919 local_statement 920 | 921 remote_statement 922 | 923 source_statement 924 | 925 metaflush_statement 926 ; 927 928remote_statement: REMOTE remote_str 929 { 930 PJDLOG_ASSERT(depth == 2); 931 if (mynode) { 932 PJDLOG_ASSERT(curres != NULL); 933 if (strlcpy(curres->hr_remoteaddr, $2, 934 sizeof(curres->hr_remoteaddr)) >= 935 sizeof(curres->hr_remoteaddr)) { 936 pjdlog_error("remote argument is too long."); 937 free($2); 938 return (1); 939 } 940 } 941 free($2); 942 } 943 ; 944 945remote_str: 946 NONE { $$ = strdup("none"); } 947 | 948 STR { } 949 ; 950 951source_statement: SOURCE STR 952 { 953 PJDLOG_ASSERT(depth == 2); 954 if (mynode) { 955 PJDLOG_ASSERT(curres != NULL); 956 if (strlcpy(curres->hr_sourceaddr, $2, 957 sizeof(curres->hr_sourceaddr)) >= 958 sizeof(curres->hr_sourceaddr)) { 959 pjdlog_error("source argument is too long."); 960 free($2); 961 return (1); 962 } 963 } 964 free($2); 965 } 966 ; 967