1 %{ 2 /*- 3 * Copyright (c) 2009-2010 The FreeBSD Foundation 4 * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net> 5 * All rights reserved. 6 * 7 * This software was developed by Pawel Jakub Dawidek under sponsorship from 8 * the FreeBSD Foundation. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * $FreeBSD$ 32 */ 33 34 #include <sys/param.h> /* MAXHOSTNAMELEN */ 35 #include <sys/queue.h> 36 #include <sys/socket.h> 37 #include <sys/sysctl.h> 38 39 #include <arpa/inet.h> 40 41 #include <err.h> 42 #include <errno.h> 43 #include <stdio.h> 44 #include <string.h> 45 #include <sysexits.h> 46 #include <unistd.h> 47 48 #include <pjdlog.h> 49 50 #include "hast.h" 51 52 extern int depth; 53 extern int lineno; 54 55 extern FILE *yyin; 56 extern char *yytext; 57 58 static struct hastd_config *lconfig; 59 static struct hast_resource *curres; 60 static bool mynode, hadmynode; 61 62 static char depth0_control[HAST_ADDRSIZE]; 63 static char depth0_pidfile[PATH_MAX]; 64 static char depth0_listen_tcp4[HAST_ADDRSIZE]; 65 static char depth0_listen_tcp6[HAST_ADDRSIZE]; 66 static TAILQ_HEAD(, hastd_listen) depth0_listen; 67 static int depth0_replication; 68 static int depth0_checksum; 69 static int depth0_compression; 70 static int depth0_timeout; 71 static char depth0_exec[PATH_MAX]; 72 static int depth0_metaflush; 73 74 static char depth1_provname[PATH_MAX]; 75 static char depth1_localpath[PATH_MAX]; 76 static int depth1_metaflush; 77 78 extern void yyrestart(FILE *); 79 80 static int isitme(const char *name); 81 static bool family_supported(int family); 82 static int node_names(char **namesp); 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 107 statements: 108 | 109 statements statement 110 ; 111 112 statement: 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 136 control_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 166 pidfile_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 196 listen_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 230 replication_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 246 replication_type: 247 FULLSYNC { $$ = HAST_REPLICATION_FULLSYNC; } 248 | 249 MEMSYNC { $$ = HAST_REPLICATION_MEMSYNC; } 250 | 251 ASYNC { $$ = HAST_REPLICATION_ASYNC; } 252 ; 253 254 checksum_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 270 checksum_type: 271 NONE { $$ = HAST_CHECKSUM_NONE; } 272 | 273 CRC32 { $$ = HAST_CHECKSUM_CRC32; } 274 | 275 SHA256 { $$ = HAST_CHECKSUM_SHA256; } 276 ; 277 278 compression_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 294 compression_type: 295 NONE { $$ = HAST_COMPRESSION_NONE; } 296 | 297 HOLE { $$ = HAST_COMPRESSION_HOLE; } 298 | 299 LZF { $$ = HAST_COMPRESSION_LZF; } 300 ; 301 302 timeout_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 322 exec_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 350 metaflush_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 372 boolean: 373 ON { $$ = 1; } 374 | 375 OFF { $$ = 0; } 376 ; 377 378 node_statement: ON node_start OB node_entries CB 379 { 380 mynode = false; 381 } 382 ; 383 384 node_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 402 node_entries: 403 | 404 node_entries node_entry 405 ; 406 407 node_entry: 408 control_statement 409 | 410 pidfile_statement 411 | 412 listen_statement 413 ; 414 415 resource_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 497 resource_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 551 resource_entries: 552 | 553 resource_entries resource_entry 554 ; 555 556 resource_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 576 name_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 607 local_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 638 resource_node_statement:ON resource_node_start OB resource_node_entries CB 639 { 640 mynode = false; 641 } 642 ; 643 644 resource_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 664 resource_node_entries: 665 | 666 resource_node_entries resource_node_entry 667 ; 668 669 resource_node_entry: 670 name_statement 671 | 672 local_statement 673 | 674 remote_statement 675 | 676 source_statement 677 | 678 metaflush_statement 679 ; 680 681 remote_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 698 remote_str: 699 NONE { $$ = strdup("none"); } 700 | 701 STR { } 702 ; 703 704 source_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 723 static int 724 isitme(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 766 static bool 767 family_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 779 static int 780 node_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 817 void 818 yyerror(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 825 struct hastd_config * 826 yy_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 993 void 994 yy_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 } 1013