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