parse.y revision 230395
1193323Sed%{ 2193323Sed/*- 3193323Sed * Copyright (c) 2009-2010 The FreeBSD Foundation 4193323Sed * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net> 5193323Sed * All rights reserved. 6193323Sed * 7193323Sed * This software was developed by Pawel Jakub Dawidek under sponsorship from 8193323Sed * the FreeBSD Foundation. 9193323Sed * 10193323Sed * Redistribution and use in source and binary forms, with or without 11193323Sed * modification, are permitted provided that the following conditions 12193323Sed * are met: 13193323Sed * 1. Redistributions of source code must retain the above copyright 14193323Sed * notice, this list of conditions and the following disclaimer. 15193323Sed * 2. Redistributions in binary form must reproduce the above copyright 16193323Sed * notice, this list of conditions and the following disclaimer in the 17193323Sed * documentation and/or other materials provided with the distribution. 18249423Sdim * 19249423Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 20249423Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21239462Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22239462Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 23193323Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24193323Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25193323Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26193323Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27221345Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28195340Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29193323Sed * SUCH DAMAGE. 30221345Sdim * 31221345Sdim * $FreeBSD: head/sbin/hastd/parse.y 230395 2012-01-20 21:45:24Z pjd $ 32221345Sdim */ 33193323Sed 34193323Sed#include <sys/param.h> /* MAXHOSTNAMELEN */ 35193323Sed#include <sys/queue.h> 36193323Sed#include <sys/socket.h> 37193323Sed#include <sys/sysctl.h> 38243830Sdim 39243830Sdim#include <arpa/inet.h> 40243830Sdim 41221345Sdim#include <err.h> 42263508Sdim#include <errno.h> 43193323Sed#include <stdio.h> 44193323Sed#include <string.h> 45263508Sdim#include <sysexits.h> 46193323Sed#include <unistd.h> 47193323Sed 48193323Sed#include <pjdlog.h> 49193323Sed 50193323Sed#include "hast.h" 51193323Sed 52193323Sedextern int depth; 53193323Sedextern int lineno; 54223017Sdim 55223017Sdimextern FILE *yyin; 56223017Sdimextern char *yytext; 57243830Sdim 58243830Sdimstatic struct hastd_config *lconfig; 59193323Sedstatic struct hast_resource *curres; 60193323Sedstatic bool mynode, hadmynode; 61193323Sed 62193323Sedstatic char depth0_control[HAST_ADDRSIZE]; 63193323Sedstatic char depth0_pidfile[PATH_MAX]; 64193323Sedstatic char depth0_listen_tcp4[HAST_ADDRSIZE]; 65193323Sedstatic char depth0_listen_tcp6[HAST_ADDRSIZE]; 66193323Sedstatic TAILQ_HEAD(, hastd_listen) depth0_listen; 67243830Sdimstatic int depth0_replication; 68193323Sedstatic int depth0_checksum; 69193323Sedstatic int depth0_compression; 70193323Sedstatic int depth0_timeout; 71202375Srdivackystatic char depth0_exec[PATH_MAX]; 72202375Srdivackystatic int depth0_metaflush; 73243830Sdim 74243830Sdimstatic char depth1_provname[PATH_MAX]; 75193323Sedstatic char depth1_localpath[PATH_MAX]; 76193323Sedstatic int depth1_metaflush; 77193323Sed 78193323Sedextern void yyrestart(FILE *); 79193323Sed 80219077Sdimstatic int 81243830Sdimisitme(const char *name) 82193323Sed{ 83263508Sdim char buf[MAXHOSTNAMELEN]; 84202375Srdivacky char *pos; 85202375Srdivacky size_t bufsize; 86202375Srdivacky 87202375Srdivacky /* 88202375Srdivacky * First check if the give name matches our full hostname. 89243830Sdim */ 90243830Sdim if (gethostname(buf, sizeof(buf)) < 0) { 91263508Sdim pjdlog_errno(LOG_ERR, "gethostname() failed"); 92193323Sed return (-1); 93193323Sed } 94193323Sed if (strcmp(buf, name) == 0) 95193323Sed return (1); 96199481Srdivacky 97199481Srdivacky /* 98199481Srdivacky * Now check if it matches first part of the host name. 99199481Srdivacky */ 100199481Srdivacky pos = strchr(buf, '.'); 101199481Srdivacky if (pos != NULL && (size_t)(pos - buf) == strlen(name) && 102199481Srdivacky strncmp(buf, name, pos - buf) == 0) { 103199481Srdivacky return (1); 104199481Srdivacky } 105199481Srdivacky 106199481Srdivacky /* 107199481Srdivacky * At the end check if name is equal to our host's UUID. 108243830Sdim */ 109263508Sdim bufsize = sizeof(buf); 110263508Sdim if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) { 111193323Sed pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed"); 112193323Sed return (-1); 113193323Sed } 114193323Sed if (strcasecmp(buf, name) == 0) 115193323Sed return (1); 116198090Srdivacky 117199481Srdivacky /* 118263508Sdim * Looks like this isn't about us. 119199481Srdivacky */ 120199481Srdivacky return (0); 121199481Srdivacky} 122199481Srdivacky 123199481Srdivackystatic bool 124199481Srdivackyfamily_supported(int family) 125199511Srdivacky{ 126199511Srdivacky int sock; 127199511Srdivacky 128199511Srdivacky sock = socket(family, SOCK_STREAM, 0); 129199511Srdivacky if (sock == -1 && errno == EPROTONOSUPPORT) 130199511Srdivacky return (false); 131199511Srdivacky if (sock >= 0) 132199511Srdivacky (void)close(sock); 133193323Sed return (true); 134193323Sed} 135193323Sed 136193323Sedstatic int 137193323Sednode_names(char **namesp) 138193323Sed{ 139249423Sdim static char names[MAXHOSTNAMELEN * 3]; 140249423Sdim char buf[MAXHOSTNAMELEN]; 141193323Sed char *pos; 142263508Sdim size_t bufsize; 143263508Sdim 144263508Sdim if (gethostname(buf, sizeof(buf)) < 0) { 145263508Sdim pjdlog_errno(LOG_ERR, "gethostname() failed"); 146263508Sdim return (-1); 147263508Sdim } 148195340Sed 149195340Sed /* First component of the host name. */ 150195340Sed pos = strchr(buf, '.'); 151195340Sed if (pos != NULL && pos != buf) { 152195340Sed (void)strlcpy(names, buf, MIN((size_t)(pos - buf + 1), 153195340Sed sizeof(names))); 154193323Sed (void)strlcat(names, ", ", sizeof(names)); 155193323Sed } 156193323Sed 157193323Sed /* Full host name. */ 158193323Sed (void)strlcat(names, buf, sizeof(names)); 159193323Sed (void)strlcat(names, ", ", sizeof(names)); 160198090Srdivacky 161198090Srdivacky /* Host UUID. */ 162193323Sed bufsize = sizeof(buf); 163193323Sed if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) { 164193323Sed pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed"); 165193323Sed return (-1); 166263508Sdim } 167193323Sed (void)strlcat(names, buf, sizeof(names)); 168193323Sed 169218893Sdim *namesp = names; 170218893Sdim 171218893Sdim return (0); 172218893Sdim} 173218893Sdim 174243830Sdimvoid 175218893Sdimyyerror(const char *str) 176218893Sdim{ 177243830Sdim 178218893Sdim pjdlog_error("Unable to parse configuration file at line %d near '%s': %s", 179218893Sdim lineno, yytext, str); 180218893Sdim} 181239462Sdim 182239462Sdimstruct hastd_config * 183239462Sdimyy_config_parse(const char *config, bool exitonerror) 184239462Sdim{ 185239462Sdim int ret; 186239462Sdim 187243830Sdim curres = NULL; 188239462Sdim mynode = false; 189263508Sdim depth = 0; 190263508Sdim lineno = 0; 191239462Sdim 192239462Sdim depth0_timeout = HAST_TIMEOUT; 193239462Sdim depth0_replication = HAST_REPLICATION_FULLSYNC; 194239462Sdim depth0_checksum = HAST_CHECKSUM_NONE; 195263508Sdim depth0_compression = HAST_COMPRESSION_HOLE; 196239462Sdim strlcpy(depth0_control, HAST_CONTROL, sizeof(depth0_control)); 197239462Sdim strlcpy(depth0_pidfile, HASTD_PIDFILE, sizeof(depth0_pidfile)); 198263508Sdim TAILQ_INIT(&depth0_listen); 199263508Sdim strlcpy(depth0_listen_tcp4, HASTD_LISTEN_TCP4, 200239462Sdim sizeof(depth0_listen_tcp4)); 201263508Sdim strlcpy(depth0_listen_tcp6, HASTD_LISTEN_TCP6, 202239462Sdim sizeof(depth0_listen_tcp6)); 203239462Sdim depth0_exec[0] = '\0'; 204239462Sdim depth0_metaflush = 1; 205239462Sdim 206263508Sdim lconfig = calloc(1, sizeof(*lconfig)); 207263508Sdim if (lconfig == NULL) { 208263508Sdim pjdlog_error("Unable to allocate memory for configuration."); 209239462Sdim if (exitonerror) 210239462Sdim exit(EX_TEMPFAIL); 211239462Sdim return (NULL); 212263508Sdim } 213263508Sdim 214239462Sdim TAILQ_INIT(&lconfig->hc_listen); 215263508Sdim TAILQ_INIT(&lconfig->hc_resources); 216263508Sdim 217263508Sdim yyin = fopen(config, "r"); 218239462Sdim if (yyin == NULL) { 219239462Sdim pjdlog_errno(LOG_ERR, "Unable to open configuration file %s", 220239462Sdim config); 221239462Sdim yy_config_free(lconfig); 222239462Sdim if (exitonerror) 223239462Sdim exit(EX_OSFILE); 224239462Sdim return (NULL); 225239462Sdim } 226239462Sdim yyrestart(yyin); 227239462Sdim ret = yyparse(); 228239462Sdim fclose(yyin); 229239462Sdim if (ret != 0) { 230239462Sdim yy_config_free(lconfig); 231239462Sdim if (exitonerror) 232239462Sdim exit(EX_CONFIG); 233239462Sdim return (NULL); 234239462Sdim } 235239462Sdim 236239462Sdim /* 237239462Sdim * Let's see if everything is set up. 238239462Sdim */ 239239462Sdim if (lconfig->hc_controladdr[0] == '\0') { 240239462Sdim strlcpy(lconfig->hc_controladdr, depth0_control, 241239462Sdim sizeof(lconfig->hc_controladdr)); 242239462Sdim } 243239462Sdim if (lconfig->hc_pidfile[0] == '\0') { 244239462Sdim strlcpy(lconfig->hc_pidfile, depth0_pidfile, 245239462Sdim sizeof(lconfig->hc_pidfile)); 246221345Sdim } 247221345Sdim if (!TAILQ_EMPTY(&depth0_listen)) 248221345Sdim TAILQ_CONCAT(&lconfig->hc_listen, &depth0_listen, hl_next); 249221345Sdim if (TAILQ_EMPTY(&lconfig->hc_listen)) { 250251662Sdim struct hastd_listen *lst; 251221345Sdim 252221345Sdim if (family_supported(AF_INET)) { 253221345Sdim lst = calloc(1, sizeof(*lst)); 254221345Sdim if (lst == NULL) { 255251662Sdim pjdlog_error("Unable to allocate memory for listen address."); 256221345Sdim yy_config_free(lconfig); 257221345Sdim if (exitonerror) 258221345Sdim exit(EX_TEMPFAIL); 259221345Sdim return (NULL); 260221345Sdim } 261221345Sdim (void)strlcpy(lst->hl_addr, depth0_listen_tcp4, 262221345Sdim sizeof(lst->hl_addr)); 263221345Sdim TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next); 264223017Sdim } else { 265223017Sdim pjdlog_debug(1, 266223017Sdim "No IPv4 support in the kernel, not listening on IPv4 address."); 267223017Sdim } 268249423Sdim if (family_supported(AF_INET6)) { 269249423Sdim lst = calloc(1, sizeof(*lst)); 270249423Sdim if (lst == NULL) { 271249423Sdim pjdlog_error("Unable to allocate memory for listen address."); 272249423Sdim yy_config_free(lconfig); 273249423Sdim if (exitonerror) 274249423Sdim exit(EX_TEMPFAIL); 275249423Sdim return (NULL); 276249423Sdim } 277249423Sdim (void)strlcpy(lst->hl_addr, depth0_listen_tcp6, 278193323Sed sizeof(lst->hl_addr)); 279193323Sed TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next); 280193323Sed } 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 350void 351yy_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 EXTENTSIZE 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 394statements: 395 | 396 statements statement 397 ; 398 399statement: 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 423control_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 453pidfile_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 483listen_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 517replication_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 533replication_type: 534 FULLSYNC { $$ = HAST_REPLICATION_FULLSYNC; } 535 | 536 MEMSYNC { $$ = HAST_REPLICATION_MEMSYNC; } 537 | 538 ASYNC { $$ = HAST_REPLICATION_ASYNC; } 539 ; 540 541checksum_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 557checksum_type: 558 NONE { $$ = HAST_CHECKSUM_NONE; } 559 | 560 CRC32 { $$ = HAST_CHECKSUM_CRC32; } 561 | 562 SHA256 { $$ = HAST_CHECKSUM_SHA256; } 563 ; 564 565compression_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 581compression_type: 582 NONE { $$ = HAST_COMPRESSION_NONE; } 583 | 584 HOLE { $$ = HAST_COMPRESSION_HOLE; } 585 | 586 LZF { $$ = HAST_COMPRESSION_LZF; } 587 ; 588 589timeout_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 609exec_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 637metaflush_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 659boolean: 660 ON { $$ = 1; } 661 | 662 OFF { $$ = 0; } 663 ; 664 665node_statement: ON node_start OB node_entries CB 666 { 667 mynode = false; 668 } 669 ; 670 671node_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 689node_entries: 690 | 691 node_entries node_entry 692 ; 693 694node_entry: 695 control_statement 696 | 697 pidfile_statement 698 | 699 listen_statement 700 ; 701 702resource_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 784resource_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($1); 816 return (1); 817 } 818 free($1); 819 curres->hr_role = HAST_ROLE_INIT; 820 curres->hr_previous_role = HAST_ROLE_INIT; 821 curres->hr_replication = -1; 822 curres->hr_checksum = -1; 823 curres->hr_compression = -1; 824 curres->hr_timeout = -1; 825 curres->hr_exec[0] = '\0'; 826 curres->hr_provname[0] = '\0'; 827 curres->hr_localpath[0] = '\0'; 828 curres->hr_localfd = -1; 829 curres->hr_localflush = true; 830 curres->hr_metaflush = -1; 831 curres->hr_remoteaddr[0] = '\0'; 832 curres->hr_sourceaddr[0] = '\0'; 833 curres->hr_ggateunit = -1; 834 } 835 ; 836 837resource_entries: 838 | 839 resource_entries resource_entry 840 ; 841 842resource_entry: 843 replication_statement 844 | 845 checksum_statement 846 | 847 compression_statement 848 | 849 timeout_statement 850 | 851 exec_statement 852 | 853 metaflush_statement 854 | 855 name_statement 856 | 857 local_statement 858 | 859 resource_node_statement 860 ; 861 862name_statement: NAME STR 863 { 864 switch (depth) { 865 case 1: 866 if (strlcpy(depth1_provname, $2, 867 sizeof(depth1_provname)) >= 868 sizeof(depth1_provname)) { 869 pjdlog_error("name argument is too long."); 870 free($2); 871 return (1); 872 } 873 break; 874 case 2: 875 if (!mynode) 876 break; 877 PJDLOG_ASSERT(curres != NULL); 878 if (strlcpy(curres->hr_provname, $2, 879 sizeof(curres->hr_provname)) >= 880 sizeof(curres->hr_provname)) { 881 pjdlog_error("name argument is too long."); 882 free($2); 883 return (1); 884 } 885 break; 886 default: 887 PJDLOG_ABORT("name at wrong depth level"); 888 } 889 free($2); 890 } 891 ; 892 893local_statement: LOCAL STR 894 { 895 switch (depth) { 896 case 1: 897 if (strlcpy(depth1_localpath, $2, 898 sizeof(depth1_localpath)) >= 899 sizeof(depth1_localpath)) { 900 pjdlog_error("local argument is too long."); 901 free($2); 902 return (1); 903 } 904 break; 905 case 2: 906 if (!mynode) 907 break; 908 PJDLOG_ASSERT(curres != NULL); 909 if (strlcpy(curres->hr_localpath, $2, 910 sizeof(curres->hr_localpath)) >= 911 sizeof(curres->hr_localpath)) { 912 pjdlog_error("local argument is too long."); 913 free($2); 914 return (1); 915 } 916 break; 917 default: 918 PJDLOG_ABORT("local at wrong depth level"); 919 } 920 free($2); 921 } 922 ; 923 924resource_node_statement:ON resource_node_start OB resource_node_entries CB 925 { 926 mynode = false; 927 } 928 ; 929 930resource_node_start: STR 931 { 932 if (curres != NULL) { 933 switch (isitme($1)) { 934 case -1: 935 free($1); 936 return (1); 937 case 0: 938 break; 939 case 1: 940 mynode = hadmynode = true; 941 break; 942 default: 943 PJDLOG_ABORT("invalid isitme() return value"); 944 } 945 } 946 free($1); 947 } 948 ; 949 950resource_node_entries: 951 | 952 resource_node_entries resource_node_entry 953 ; 954 955resource_node_entry: 956 name_statement 957 | 958 local_statement 959 | 960 remote_statement 961 | 962 source_statement 963 | 964 metaflush_statement 965 ; 966 967remote_statement: REMOTE remote_str 968 { 969 PJDLOG_ASSERT(depth == 2); 970 if (mynode) { 971 PJDLOG_ASSERT(curres != NULL); 972 if (strlcpy(curres->hr_remoteaddr, $2, 973 sizeof(curres->hr_remoteaddr)) >= 974 sizeof(curres->hr_remoteaddr)) { 975 pjdlog_error("remote argument is too long."); 976 free($2); 977 return (1); 978 } 979 } 980 free($2); 981 } 982 ; 983 984remote_str: 985 NONE { $$ = strdup("none"); } 986 | 987 STR { } 988 ; 989 990source_statement: SOURCE STR 991 { 992 PJDLOG_ASSERT(depth == 2); 993 if (mynode) { 994 PJDLOG_ASSERT(curres != NULL); 995 if (strlcpy(curres->hr_sourceaddr, $2, 996 sizeof(curres->hr_sourceaddr)) >= 997 sizeof(curres->hr_sourceaddr)) { 998 pjdlog_error("source argument is too long."); 999 free($2); 1000 return (1); 1001 } 1002 } 1003 free($2); 1004 } 1005 ; 1006