parse.y revision 225784
1153758Swollman%{ 2192886Sedwin/*- 3192886Sedwin * Copyright (c) 2009-2010 The FreeBSD Foundation 42744Swollman * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net> 558782Sru * All rights reserved. 658782Sru * 758782Sru * This software was developed by Pawel Jakub Dawidek under sponsorship from 858782Sru * the FreeBSD Foundation. 943009Swollman * 1043009Swollman * Redistribution and use in source and binary forms, with or without 1143009Swollman * modification, are permitted provided that the following conditions 1258782Sru * are met: 1343009Swollman * 1. Redistributions of source code must retain the above copyright 1443009Swollman * notice, this list of conditions and the following disclaimer. 1519876Swollman * 2. Redistributions in binary form must reproduce the above copyright 1619876Swollman * notice, this list of conditions and the following disclaimer in the 1730708Swollman * documentation and/or other materials provided with the distribution. 1819876Swollman * 1975264Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 202744Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2120091Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2220091Swollman * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 2320091Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2420091Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25169808Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26158417Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27158417Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2820091Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2920091Swollman * SUCH DAMAGE. 30169808Swollman * 31169808Swollman * $FreeBSD: head/sbin/hastd/parse.y 225784 2011-09-27 08:04:01Z pjd $ 32169808Swollman */ 33169808Swollman 34169808Swollman#include <sys/param.h> /* MAXHOSTNAMELEN */ 35169808Swollman#include <sys/queue.h> 36169808Swollman#include <sys/socket.h> 37169808Swollman#include <sys/sysctl.h> 38169808Swollman 39169808Swollman#include <arpa/inet.h> 40169808Swollman 41169808Swollman#include <err.h> 42169808Swollman#include <errno.h> 43169808Swollman#include <stdio.h> 44233445Sedwin#include <string.h> 45233445Sedwin#include <sysexits.h> 46233445Sedwin#include <unistd.h> 47233445Sedwin 48233445Sedwin#include <pjdlog.h> 49233445Sedwin 50233445Sedwin#include "hast.h" 51233445Sedwin 52233445Sedwinextern int depth; 53248307Sedwinextern int lineno; 54248307Sedwin 552744Swollmanextern FILE *yyin; 5658782Sruextern char *yytext; 5758782Sru 5858782Srustatic struct hastd_config *lconfig; 5958782Srustatic struct hast_resource *curres; 6058782Srustatic bool mynode, hadmynode; 6158782Sru 6258782Srustatic char depth0_control[HAST_ADDRSIZE]; 6358782Srustatic char depth0_listen_tcp4[HAST_ADDRSIZE]; 642744Swollmanstatic char depth0_listen_tcp6[HAST_ADDRSIZE]; 6519876Swollmanstatic TAILQ_HEAD(, hastd_listen) depth0_listen; 6630708Swollmanstatic int depth0_replication; 6758782Srustatic int depth0_checksum; 68153667Swollmanstatic int depth0_compression; 6958782Srustatic int depth0_timeout; 7058782Srustatic char depth0_exec[PATH_MAX]; 7158782Sru 7219876Swollmanstatic char depth1_provname[PATH_MAX]; 7319876Swollmanstatic char depth1_localpath[PATH_MAX]; 7458782Sru 7558782Sruextern void yyrestart(FILE *); 7658782Sru 7758782Srustatic int 78199107Sedwinisitme(const char *name) 79199107Sedwin{ 80199107Sedwin char buf[MAXHOSTNAMELEN]; 81199107Sedwin char *pos; 82199107Sedwin size_t bufsize; 83199107Sedwin 84199107Sedwin /* 85199107Sedwin * First check if the give name matches our full hostname. 86199107Sedwin */ 87199107Sedwin if (gethostname(buf, sizeof(buf)) < 0) { 88199107Sedwin pjdlog_errno(LOG_ERR, "gethostname() failed"); 89199107Sedwin return (-1); 90199107Sedwin } 91199107Sedwin if (strcmp(buf, name) == 0) 92199107Sedwin return (1); 93199107Sedwin 94199107Sedwin /* 95199107Sedwin * Now check if it matches first part of the host name. 96205475Sedwin */ 97249692Sedwin pos = strchr(buf, '.'); 98205475Sedwin if (pos != NULL && (size_t)(pos - buf) == strlen(name) && 99205475Sedwin strncmp(buf, name, pos - buf) == 0) { 100205475Sedwin return (1); 101205475Sedwin } 102205475Sedwin 103205475Sedwin /* 104205475Sedwin * At the end check if name is equal to our host's UUID. 105205475Sedwin */ 106205475Sedwin bufsize = sizeof(buf); 107205475Sedwin if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) { 108205475Sedwin pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed"); 109205475Sedwin return (-1); 110205475Sedwin } 111205475Sedwin if (strcasecmp(buf, name) == 0) 112205475Sedwin return (1); 11319876Swollman 11475264Swollman /* 115199107Sedwin * Looks like this isn't about us. 116199107Sedwin */ 117205475Sedwin return (0); 118205475Sedwin} 119233445Sedwin 120233445Sedwinstatic bool 121205475Sedwinfamily_supported(int family) 12275264Swollman{ 12343009Swollman int sock; 12475264Swollman 125199336Sedwin sock = socket(family, SOCK_STREAM, 0); 126205475Sedwin if (sock == -1 && errno == EPROTONOSUPPORT) 127233445Sedwin return (false); 128233445Sedwin if (sock >= 0) 129205475Sedwin (void)close(sock); 13075264Swollman return (true); 131199107Sedwin} 132199107Sedwin 133199107Sedwinstatic int 13419876Swollmannode_names(char **namesp) 13543009Swollman{ 13643009Swollman static char names[MAXHOSTNAMELEN * 3]; 13743009Swollman char buf[MAXHOSTNAMELEN]; 13843009Swollman char *pos; 13943009Swollman size_t bufsize; 14043009Swollman 14143009Swollman if (gethostname(buf, sizeof(buf)) < 0) { 14243009Swollman pjdlog_errno(LOG_ERR, "gethostname() failed"); 14343009Swollman return (-1); 14414338Swollman } 14519876Swollman 146149511Swollman /* First component of the host name. */ 14714338Swollman pos = strchr(buf, '.'); 14886218Swollman if (pos != NULL && pos != buf) { 14958782Sru (void)strlcpy(names, buf, MIN((size_t)(pos - buf + 1), 150149511Swollman sizeof(names))); 151149511Swollman (void)strlcat(names, ", ", sizeof(names)); 152149511Swollman } 153149511Swollman 15486218Swollman /* Full host name. */ 15514338Swollman (void)strlcat(names, buf, sizeof(names)); 15619876Swollman (void)strlcat(names, ", ", sizeof(names)); 157149511Swollman 158149511Swollman /* Host UUID. */ 15919876Swollman bufsize = sizeof(buf); 16030708Swollman if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) { 16119876Swollman pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed"); 162153667Swollman return (-1); 16330708Swollman } 16430708Swollman (void)strlcat(names, buf, sizeof(names)); 16530708Swollman 16630708Swollman *namesp = names; 16730708Swollman 16830708Swollman return (0); 16919876Swollman} 17019876Swollman 17130708Swollmanvoid 17230708Swollmanyyerror(const char *str) 17330708Swollman{ 17458782Sru 17530708Swollman pjdlog_error("Unable to parse configuration file at line %d near '%s': %s", 17658782Sru lineno, yytext, str); 17758782Sru} 17830708Swollman 17930708Swollmanstruct hastd_config * 18075264Swollmanyy_config_parse(const char *config, bool exitonerror) 18130708Swollman{ 18230708Swollman int ret; 18330708Swollman 18458782Sru curres = NULL; 18530708Swollman mynode = false; 18630708Swollman depth = 0; 18730708Swollman lineno = 0; 18830708Swollman 18930708Swollman depth0_timeout = HAST_TIMEOUT; 19075264Swollman depth0_replication = HAST_REPLICATION_FULLSYNC; 19130708Swollman depth0_checksum = HAST_CHECKSUM_NONE; 19275264Swollman depth0_compression = HAST_COMPRESSION_HOLE; 19330708Swollman strlcpy(depth0_control, HAST_CONTROL, sizeof(depth0_control)); 19430708Swollman TAILQ_INIT(&depth0_listen); 195153667Swollman strlcpy(depth0_listen_tcp4, HASTD_LISTEN_TCP4, 196153667Swollman sizeof(depth0_listen_tcp4)); 19743009Swollman strlcpy(depth0_listen_tcp6, HASTD_LISTEN_TCP6, 19819876Swollman sizeof(depth0_listen_tcp6)); 19919876Swollman depth0_exec[0] = '\0'; 200149511Swollman 20119876Swollman lconfig = calloc(1, sizeof(*lconfig)); 20219876Swollman if (lconfig == NULL) { 203149511Swollman pjdlog_error("Unable to allocate memory for configuration."); 20419876Swollman if (exitonerror) 20519876Swollman exit(EX_TEMPFAIL); 206149511Swollman return (NULL); 207149511Swollman } 20858782Sru 20958782Sru TAILQ_INIT(&lconfig->hc_listen); 210153667Swollman TAILQ_INIT(&lconfig->hc_resources); 21158782Sru 21258782Sru yyin = fopen(config, "r"); 21358782Sru if (yyin == NULL) { 21458782Sru pjdlog_errno(LOG_ERR, "Unable to open configuration file %s", 21558782Sru config); 21675264Swollman yy_config_free(lconfig); 21758782Sru if (exitonerror) 21858782Sru exit(EX_OSFILE); 21958782Sru return (NULL); 22058782Sru } 22158782Sru yyrestart(yyin); 22219876Swollman ret = yyparse(); 22319876Swollman fclose(yyin); 224149511Swollman if (ret != 0) { 22519876Swollman yy_config_free(lconfig); 22619876Swollman if (exitonerror) 22730708Swollman exit(EX_CONFIG); 22830708Swollman return (NULL); 22919876Swollman } 23019876Swollman 23119876Swollman /* 23219876Swollman * Let's see if everything is set up. 23319876Swollman */ 23419876Swollman if (lconfig->hc_controladdr[0] == '\0') { 23519876Swollman strlcpy(lconfig->hc_controladdr, depth0_control, 23619876Swollman sizeof(lconfig->hc_controladdr)); 23719876Swollman } 238171945Sedwin if (!TAILQ_EMPTY(&depth0_listen)) 23919876Swollman TAILQ_CONCAT(&lconfig->hc_listen, &depth0_listen, hl_next); 24019876Swollman if (TAILQ_EMPTY(&lconfig->hc_listen)) { 241171945Sedwin struct hastd_listen *lst; 242171945Sedwin 243171945Sedwin if (family_supported(AF_INET)) { 24419876Swollman lst = calloc(1, sizeof(*lst)); 24519876Swollman if (lst == NULL) { 24630708Swollman pjdlog_error("Unable to allocate memory for listen address."); 24719876Swollman yy_config_free(lconfig); 24819876Swollman if (exitonerror) 24930708Swollman exit(EX_TEMPFAIL); 25019876Swollman return (NULL); 25119876Swollman } 25258782Sru (void)strlcpy(lst->hl_addr, depth0_listen_tcp4, 25319876Swollman sizeof(lst->hl_addr)); 25419876Swollman TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next); 25558782Sru } else { 25658782Sru pjdlog_debug(1, 257149511Swollman "No IPv4 support in the kernel, not listening on IPv4 address."); 258149511Swollman } 25975264Swollman if (family_supported(AF_INET6)) { 26075264Swollman lst = calloc(1, sizeof(*lst)); 26119876Swollman if (lst == NULL) { 26275264Swollman pjdlog_error("Unable to allocate memory for listen address."); 26375264Swollman yy_config_free(lconfig); 26475264Swollman if (exitonerror) 26575264Swollman exit(EX_TEMPFAIL); 26675264Swollman return (NULL); 26775264Swollman } 26875264Swollman (void)strlcpy(lst->hl_addr, depth0_listen_tcp6, 26975264Swollman sizeof(lst->hl_addr)); 27075264Swollman TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next); 27175264Swollman } else { 27275264Swollman pjdlog_debug(1, 27375264Swollman "No IPv6 support in the kernel, not listening on IPv6 address."); 27475264Swollman } 27575264Swollman if (TAILQ_EMPTY(&lconfig->hc_listen)) { 27675264Swollman pjdlog_error("No address to listen on."); 27786218Swollman yy_config_free(lconfig); 27886218Swollman if (exitonerror) 27986218Swollman exit(EX_TEMPFAIL); 28086218Swollman return (NULL); 28186218Swollman } 28286218Swollman } 28386218Swollman TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) { 28486218Swollman PJDLOG_ASSERT(curres->hr_provname[0] != '\0'); 28586218Swollman PJDLOG_ASSERT(curres->hr_localpath[0] != '\0'); 28675264Swollman PJDLOG_ASSERT(curres->hr_remoteaddr[0] != '\0'); 28775264Swollman 28875264Swollman if (curres->hr_replication == -1) { 28919876Swollman /* 290149511Swollman * Replication is not set at resource-level. 291149511Swollman * Use global or default setting. 29219876Swollman */ 29319876Swollman curres->hr_replication = depth0_replication; 29419876Swollman } 29519876Swollman if (curres->hr_replication == HAST_REPLICATION_MEMSYNC || 29619876Swollman curres->hr_replication == HAST_REPLICATION_ASYNC) { 29730708Swollman pjdlog_warning("Replication mode \"%s\" is not implemented, falling back to \"%s\".", 29858782Sru curres->hr_replication == HAST_REPLICATION_MEMSYNC ? 29919876Swollman "memsync" : "async", "fullsync"); 30019876Swollman curres->hr_replication = HAST_REPLICATION_FULLSYNC; 30119876Swollman } 30258782Sru if (curres->hr_checksum == -1) { 30375264Swollman /* 30475264Swollman * Checksum is not set at resource-level. 30575264Swollman * Use global or default setting. 30675264Swollman */ 30775264Swollman curres->hr_checksum = depth0_checksum; 30875264Swollman } 30975264Swollman if (curres->hr_compression == -1) { 31019876Swollman /* 311114170Swollman * Compression is not set at resource-level. 312114170Swollman * Use global or default setting. 313114170Swollman */ 314114170Swollman curres->hr_compression = depth0_compression; 315114170Swollman } 316114170Swollman if (curres->hr_timeout == -1) { 317114170Swollman /* 31819876Swollman * Timeout is not set at resource-level. 31919876Swollman * Use global or default setting. 32058782Sru */ 32119876Swollman curres->hr_timeout = depth0_timeout; 32219876Swollman } 32319876Swollman if (curres->hr_exec[0] == '\0') { 32420091Swollman /* 32519876Swollman * Exec is not set at resource-level. 326149511Swollman * Use global or default setting. 32720091Swollman */ 32820091Swollman strlcpy(curres->hr_exec, depth0_exec, 32920091Swollman sizeof(curres->hr_exec)); 33020091Swollman } 33120091Swollman } 33220091Swollman 33320091Swollman return (lconfig); 33475264Swollman} 33520091Swollman 33620091Swollmanvoid 33720091Swollmanyy_config_free(struct hastd_config *config) 33820091Swollman{ 33920091Swollman struct hastd_listen *lst; 34075264Swollman struct hast_resource *res; 34119876Swollman 34275264Swollman while ((lst = TAILQ_FIRST(&depth0_listen)) != NULL) { 34319876Swollman TAILQ_REMOVE(&depth0_listen, lst, hl_next); 34419876Swollman free(lst); 34575264Swollman } 34675264Swollman while ((lst = TAILQ_FIRST(&config->hc_listen)) != NULL) { 34719876Swollman TAILQ_REMOVE(&config->hc_listen, lst, hl_next); 34819876Swollman free(lst); 34919876Swollman } 35019876Swollman while ((res = TAILQ_FIRST(&config->hc_resources)) != NULL) { 351153667Swollman TAILQ_REMOVE(&config->hc_resources, res, hr_next); 35219876Swollman free(res); 35319876Swollman } 35419876Swollman free(config); 35519876Swollman} 35619876Swollman%} 35719876Swollman 35819876Swollman%token CONTROL LISTEN PORT REPLICATION CHECKSUM COMPRESSION 35943009Swollman%token TIMEOUT EXEC EXTENTSIZE RESOURCE NAME LOCAL REMOTE SOURCE ON 36043009Swollman%token FULLSYNC MEMSYNC ASYNC NONE CRC32 SHA256 HOLE LZF 36143009Swollman%token NUM STR OB CB 36243009Swollman 36319876Swollman%type <str> remote_str 36419876Swollman%type <num> replication_type 36519876Swollman%type <num> checksum_type 36619876Swollman%type <num> compression_type 36719876Swollman 36819876Swollman%union 36919876Swollman{ 37019876Swollman int num; 37119876Swollman 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 PJDLOG_ASSERT(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 PJDLOG_ASSERT(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 PJDLOG_ASSERT(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 PJDLOG_ASSERT(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 PJDLOG_ASSERT(curres != NULL); 573 if (strlcpy(curres->hr_exec, $2, 574 sizeof(curres->hr_exec)) >= 575 sizeof(curres->hr_exec)) { 576 pjdlog_error("Exec path is too long."); 577 free($2); 578 return (1); 579 } 580 break; 581 default: 582 PJDLOG_ABORT("exec at wrong depth level"); 583 } 584 free($2); 585 } 586 ; 587 588node_statement: ON node_start OB node_entries CB 589 { 590 mynode = false; 591 } 592 ; 593 594node_start: STR 595 { 596 switch (isitme($1)) { 597 case -1: 598 free($1); 599 return (1); 600 case 0: 601 break; 602 case 1: 603 mynode = true; 604 break; 605 default: 606 PJDLOG_ABORT("invalid isitme() return value"); 607 } 608 free($1); 609 } 610 ; 611 612node_entries: 613 | 614 node_entries node_entry 615 ; 616 617node_entry: 618 control_statement 619 | 620 listen_statement 621 ; 622 623resource_statement: RESOURCE resource_start OB resource_entries CB 624 { 625 if (curres != NULL) { 626 /* 627 * There must be section for this node, at least with 628 * remote address configuration. 629 */ 630 if (!hadmynode) { 631 char *names; 632 633 if (node_names(&names) != 0) 634 return (1); 635 pjdlog_error("No resource %s configuration for this node (acceptable node names: %s).", 636 curres->hr_name, names); 637 return (1); 638 } 639 640 /* 641 * Let's see if there are some resource-level settings 642 * that we can use for node-level settings. 643 */ 644 if (curres->hr_provname[0] == '\0' && 645 depth1_provname[0] != '\0') { 646 /* 647 * Provider name is not set at node-level, 648 * but is set at resource-level, use it. 649 */ 650 strlcpy(curres->hr_provname, depth1_provname, 651 sizeof(curres->hr_provname)); 652 } 653 if (curres->hr_localpath[0] == '\0' && 654 depth1_localpath[0] != '\0') { 655 /* 656 * Path to local provider is not set at 657 * node-level, but is set at resource-level, 658 * use it. 659 */ 660 strlcpy(curres->hr_localpath, depth1_localpath, 661 sizeof(curres->hr_localpath)); 662 } 663 664 /* 665 * If provider name is not given, use resource name 666 * as provider name. 667 */ 668 if (curres->hr_provname[0] == '\0') { 669 strlcpy(curres->hr_provname, curres->hr_name, 670 sizeof(curres->hr_provname)); 671 } 672 673 /* 674 * Remote address has to be configured at this point. 675 */ 676 if (curres->hr_remoteaddr[0] == '\0') { 677 pjdlog_error("Remote address not configured for resource %s.", 678 curres->hr_name); 679 return (1); 680 } 681 /* 682 * Path to local provider has to be configured at this 683 * point. 684 */ 685 if (curres->hr_localpath[0] == '\0') { 686 pjdlog_error("Path to local component not configured for resource %s.", 687 curres->hr_name); 688 return (1); 689 } 690 691 /* Put it onto resource list. */ 692 TAILQ_INSERT_TAIL(&lconfig->hc_resources, curres, hr_next); 693 curres = NULL; 694 } 695 } 696 ; 697 698resource_start: STR 699 { 700 /* Check if there is no duplicate entry. */ 701 TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) { 702 if (strcmp(curres->hr_name, $1) == 0) { 703 pjdlog_error("Resource %s configured more than once.", 704 curres->hr_name); 705 free($1); 706 return (1); 707 } 708 } 709 710 /* 711 * Clear those, so we can tell if they were set at 712 * resource-level or not. 713 */ 714 depth1_provname[0] = '\0'; 715 depth1_localpath[0] = '\0'; 716 hadmynode = false; 717 718 curres = calloc(1, sizeof(*curres)); 719 if (curres == NULL) { 720 pjdlog_error("Unable to allocate memory for resource."); 721 free($1); 722 return (1); 723 } 724 if (strlcpy(curres->hr_name, $1, 725 sizeof(curres->hr_name)) >= 726 sizeof(curres->hr_name)) { 727 pjdlog_error("Resource name is too long."); 728 free($1); 729 return (1); 730 } 731 free($1); 732 curres->hr_role = HAST_ROLE_INIT; 733 curres->hr_previous_role = HAST_ROLE_INIT; 734 curres->hr_replication = -1; 735 curres->hr_checksum = -1; 736 curres->hr_compression = -1; 737 curres->hr_timeout = -1; 738 curres->hr_exec[0] = '\0'; 739 curres->hr_provname[0] = '\0'; 740 curres->hr_localpath[0] = '\0'; 741 curres->hr_localfd = -1; 742 curres->hr_remoteaddr[0] = '\0'; 743 curres->hr_sourceaddr[0] = '\0'; 744 curres->hr_ggateunit = -1; 745 } 746 ; 747 748resource_entries: 749 | 750 resource_entries resource_entry 751 ; 752 753resource_entry: 754 replication_statement 755 | 756 checksum_statement 757 | 758 compression_statement 759 | 760 timeout_statement 761 | 762 exec_statement 763 | 764 name_statement 765 | 766 local_statement 767 | 768 resource_node_statement 769 ; 770 771name_statement: NAME STR 772 { 773 switch (depth) { 774 case 1: 775 if (strlcpy(depth1_provname, $2, 776 sizeof(depth1_provname)) >= 777 sizeof(depth1_provname)) { 778 pjdlog_error("name argument is too long."); 779 free($2); 780 return (1); 781 } 782 break; 783 case 2: 784 if (!mynode) 785 break; 786 PJDLOG_ASSERT(curres != NULL); 787 if (strlcpy(curres->hr_provname, $2, 788 sizeof(curres->hr_provname)) >= 789 sizeof(curres->hr_provname)) { 790 pjdlog_error("name argument is too long."); 791 free($2); 792 return (1); 793 } 794 break; 795 default: 796 PJDLOG_ABORT("name at wrong depth level"); 797 } 798 free($2); 799 } 800 ; 801 802local_statement: LOCAL STR 803 { 804 switch (depth) { 805 case 1: 806 if (strlcpy(depth1_localpath, $2, 807 sizeof(depth1_localpath)) >= 808 sizeof(depth1_localpath)) { 809 pjdlog_error("local argument is too long."); 810 free($2); 811 return (1); 812 } 813 break; 814 case 2: 815 if (!mynode) 816 break; 817 PJDLOG_ASSERT(curres != NULL); 818 if (strlcpy(curres->hr_localpath, $2, 819 sizeof(curres->hr_localpath)) >= 820 sizeof(curres->hr_localpath)) { 821 pjdlog_error("local argument is too long."); 822 free($2); 823 return (1); 824 } 825 break; 826 default: 827 PJDLOG_ABORT("local at wrong depth level"); 828 } 829 free($2); 830 } 831 ; 832 833resource_node_statement:ON resource_node_start OB resource_node_entries CB 834 { 835 mynode = false; 836 } 837 ; 838 839resource_node_start: STR 840 { 841 if (curres != NULL) { 842 switch (isitme($1)) { 843 case -1: 844 free($1); 845 return (1); 846 case 0: 847 break; 848 case 1: 849 mynode = hadmynode = true; 850 break; 851 default: 852 PJDLOG_ABORT("invalid isitme() return value"); 853 } 854 } 855 free($1); 856 } 857 ; 858 859resource_node_entries: 860 | 861 resource_node_entries resource_node_entry 862 ; 863 864resource_node_entry: 865 name_statement 866 | 867 local_statement 868 | 869 remote_statement 870 | 871 source_statement 872 ; 873 874remote_statement: REMOTE remote_str 875 { 876 PJDLOG_ASSERT(depth == 2); 877 if (mynode) { 878 PJDLOG_ASSERT(curres != NULL); 879 if (strlcpy(curres->hr_remoteaddr, $2, 880 sizeof(curres->hr_remoteaddr)) >= 881 sizeof(curres->hr_remoteaddr)) { 882 pjdlog_error("remote argument is too long."); 883 free($2); 884 return (1); 885 } 886 } 887 free($2); 888 } 889 ; 890 891remote_str: 892 NONE { $$ = strdup("none"); } 893 | 894 STR { } 895 ; 896 897source_statement: SOURCE STR 898 { 899 PJDLOG_ASSERT(depth == 2); 900 if (mynode) { 901 PJDLOG_ASSERT(curres != NULL); 902 if (strlcpy(curres->hr_sourceaddr, $2, 903 sizeof(curres->hr_sourceaddr)) >= 904 sizeof(curres->hr_sourceaddr)) { 905 pjdlog_error("source argument is too long."); 906 free($2); 907 return (1); 908 } 909 } 910 free($2); 911 } 912 ; 913