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