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