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