1204076Spjd%{ 2204076Spjd/*- 3204076Spjd * Copyright (c) 2009-2010 The FreeBSD Foundation 4219351Spjd * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net> 5204076Spjd * All rights reserved. 6204076Spjd * 7204076Spjd * This software was developed by Pawel Jakub Dawidek under sponsorship from 8204076Spjd * the FreeBSD Foundation. 9204076Spjd * 10204076Spjd * Redistribution and use in source and binary forms, with or without 11204076Spjd * modification, are permitted provided that the following conditions 12204076Spjd * are met: 13204076Spjd * 1. Redistributions of source code must retain the above copyright 14204076Spjd * notice, this list of conditions and the following disclaimer. 15204076Spjd * 2. Redistributions in binary form must reproduce the above copyright 16204076Spjd * notice, this list of conditions and the following disclaimer in the 17204076Spjd * documentation and/or other materials provided with the distribution. 18204076Spjd * 19204076Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 20204076Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21204076Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22204076Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 23204076Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24204076Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25204076Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26204076Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27204076Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28204076Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29204076Spjd * SUCH DAMAGE. 30204076Spjd * 31204076Spjd * $FreeBSD$ 32204076Spjd */ 33204076Spjd 34204076Spjd#include <sys/param.h> /* MAXHOSTNAMELEN */ 35204076Spjd#include <sys/queue.h> 36222108Spjd#include <sys/socket.h> 37204076Spjd#include <sys/sysctl.h> 38204076Spjd 39204076Spjd#include <arpa/inet.h> 40204076Spjd 41204076Spjd#include <err.h> 42222108Spjd#include <errno.h> 43204076Spjd#include <stdio.h> 44204076Spjd#include <string.h> 45204076Spjd#include <sysexits.h> 46204076Spjd#include <unistd.h> 47204076Spjd 48210883Spjd#include <pjdlog.h> 49210883Spjd 50204076Spjd#include "hast.h" 51204076Spjd 52204076Spjdextern int depth; 53204076Spjdextern int lineno; 54204076Spjd 55204076Spjdextern FILE *yyin; 56204076Spjdextern char *yytext; 57204076Spjd 58210883Spjdstatic struct hastd_config *lconfig; 59204076Spjdstatic struct hast_resource *curres; 60216721Spjdstatic bool mynode, hadmynode; 61204076Spjd 62204076Spjdstatic char depth0_control[HAST_ADDRSIZE]; 63226463Spjdstatic char depth0_pidfile[PATH_MAX]; 64222119Spjdstatic char depth0_listen_tcp4[HAST_ADDRSIZE]; 65222119Spjdstatic char depth0_listen_tcp6[HAST_ADDRSIZE]; 66222108Spjdstatic TAILQ_HEAD(, hastd_listen) depth0_listen; 67204076Spjdstatic int depth0_replication; 68219351Spjdstatic int depth0_checksum; 69219354Spjdstatic int depth0_compression; 70207371Spjdstatic int depth0_timeout; 71211886Spjdstatic char depth0_exec[PATH_MAX]; 72225830Spjdstatic int depth0_metaflush; 73204076Spjd 74204076Spjdstatic char depth1_provname[PATH_MAX]; 75204076Spjdstatic char depth1_localpath[PATH_MAX]; 76225830Spjdstatic int depth1_metaflush; 77204076Spjd 78250914Sjkimextern void yyerror(const char *); 79250914Sjkimextern int yylex(void); 80210883Spjdextern void yyrestart(FILE *); 81210883Spjd 82235789Sbaptstatic int isitme(const char *name); 83235789Sbaptstatic bool family_supported(int family); 84235789Sbaptstatic int node_names(char **namesp); 85204076Spjd%} 86204076Spjd 87230395Spjd%token CONTROL PIDFILE LISTEN REPLICATION CHECKSUM COMPRESSION METAFLUSH 88230396Spjd%token TIMEOUT EXEC RESOURCE NAME LOCAL REMOTE SOURCE ON OFF 89219354Spjd%token FULLSYNC MEMSYNC ASYNC NONE CRC32 SHA256 HOLE LZF 90204076Spjd%token NUM STR OB CB 91204076Spjd 92221643Spjd%type <str> remote_str 93204076Spjd%type <num> replication_type 94219351Spjd%type <num> checksum_type 95219354Spjd%type <num> compression_type 96225830Spjd%type <num> boolean 97204076Spjd 98204076Spjd%union 99204076Spjd{ 100204076Spjd int num; 101204076Spjd char *str; 102204076Spjd} 103204076Spjd 104204076Spjd%token <num> NUM 105204076Spjd%token <str> STR 106204076Spjd 107204076Spjd%% 108204076Spjd 109204076Spjdstatements: 110204076Spjd | 111204076Spjd statements statement 112204076Spjd ; 113204076Spjd 114204076Spjdstatement: 115204076Spjd control_statement 116204076Spjd | 117226463Spjd pidfile_statement 118226463Spjd | 119204076Spjd listen_statement 120204076Spjd | 121204076Spjd replication_statement 122204076Spjd | 123219351Spjd checksum_statement 124219351Spjd | 125219354Spjd compression_statement 126219354Spjd | 127207371Spjd timeout_statement 128207371Spjd | 129211886Spjd exec_statement 130211886Spjd | 131225830Spjd metaflush_statement 132225830Spjd | 133204076Spjd node_statement 134204076Spjd | 135204076Spjd resource_statement 136204076Spjd ; 137204076Spjd 138204076Spjdcontrol_statement: CONTROL STR 139204076Spjd { 140204076Spjd switch (depth) { 141204076Spjd case 0: 142204076Spjd if (strlcpy(depth0_control, $2, 143204076Spjd sizeof(depth0_control)) >= 144204076Spjd sizeof(depth0_control)) { 145210883Spjd pjdlog_error("control argument is too long."); 146214274Spjd free($2); 147210883Spjd return (1); 148204076Spjd } 149204076Spjd break; 150204076Spjd case 1: 151211883Spjd if (!mynode) 152211883Spjd break; 153211883Spjd if (strlcpy(lconfig->hc_controladdr, $2, 154211883Spjd sizeof(lconfig->hc_controladdr)) >= 155211883Spjd sizeof(lconfig->hc_controladdr)) { 156211883Spjd pjdlog_error("control argument is too long."); 157214274Spjd free($2); 158211883Spjd return (1); 159204076Spjd } 160204076Spjd break; 161204076Spjd default: 162225782Spjd PJDLOG_ABORT("control at wrong depth level"); 163204076Spjd } 164214274Spjd free($2); 165204076Spjd } 166204076Spjd ; 167204076Spjd 168226463Spjdpidfile_statement: PIDFILE STR 169226463Spjd { 170226463Spjd switch (depth) { 171226463Spjd case 0: 172226463Spjd if (strlcpy(depth0_pidfile, $2, 173226463Spjd sizeof(depth0_pidfile)) >= 174226463Spjd sizeof(depth0_pidfile)) { 175226463Spjd pjdlog_error("pidfile argument is too long."); 176226463Spjd free($2); 177226463Spjd return (1); 178226463Spjd } 179226463Spjd break; 180226463Spjd case 1: 181226463Spjd if (!mynode) 182226463Spjd break; 183226463Spjd if (strlcpy(lconfig->hc_pidfile, $2, 184226463Spjd sizeof(lconfig->hc_pidfile)) >= 185226463Spjd sizeof(lconfig->hc_pidfile)) { 186226463Spjd pjdlog_error("pidfile argument is too long."); 187226463Spjd free($2); 188226463Spjd return (1); 189226463Spjd } 190226463Spjd break; 191226463Spjd default: 192226463Spjd PJDLOG_ABORT("pidfile at wrong depth level"); 193226463Spjd } 194226463Spjd free($2); 195226463Spjd } 196226463Spjd ; 197226463Spjd 198204076Spjdlisten_statement: LISTEN STR 199204076Spjd { 200222108Spjd struct hastd_listen *lst; 201222108Spjd 202222108Spjd lst = calloc(1, sizeof(*lst)); 203222108Spjd if (lst == NULL) { 204222108Spjd pjdlog_error("Unable to allocate memory for listen address."); 205222108Spjd free($2); 206222108Spjd return (1); 207222108Spjd } 208222108Spjd if (strlcpy(lst->hl_addr, $2, sizeof(lst->hl_addr)) >= 209222108Spjd sizeof(lst->hl_addr)) { 210222108Spjd pjdlog_error("listen argument is too long."); 211222108Spjd free($2); 212222108Spjd free(lst); 213222108Spjd return (1); 214222108Spjd } 215204076Spjd switch (depth) { 216204076Spjd case 0: 217222108Spjd TAILQ_INSERT_TAIL(&depth0_listen, lst, hl_next); 218204076Spjd break; 219204076Spjd case 1: 220222108Spjd if (mynode) 221222108Spjd TAILQ_INSERT_TAIL(&depth0_listen, lst, hl_next); 222222108Spjd else 223222108Spjd free(lst); 224204076Spjd break; 225204076Spjd default: 226225782Spjd PJDLOG_ABORT("listen at wrong depth level"); 227204076Spjd } 228214274Spjd free($2); 229204076Spjd } 230204076Spjd ; 231204076Spjd 232204076Spjdreplication_statement: REPLICATION replication_type 233204076Spjd { 234204076Spjd switch (depth) { 235204076Spjd case 0: 236204076Spjd depth0_replication = $2; 237204076Spjd break; 238204076Spjd case 1: 239225784Spjd PJDLOG_ASSERT(curres != NULL); 240225784Spjd curres->hr_replication = $2; 241246922Spjd curres->hr_original_replication = $2; 242204076Spjd break; 243204076Spjd default: 244225782Spjd PJDLOG_ABORT("replication at wrong depth level"); 245204076Spjd } 246204076Spjd } 247204076Spjd ; 248204076Spjd 249204076Spjdreplication_type: 250204076Spjd FULLSYNC { $$ = HAST_REPLICATION_FULLSYNC; } 251204076Spjd | 252204076Spjd MEMSYNC { $$ = HAST_REPLICATION_MEMSYNC; } 253204076Spjd | 254204076Spjd ASYNC { $$ = HAST_REPLICATION_ASYNC; } 255204076Spjd ; 256204076Spjd 257219351Spjdchecksum_statement: CHECKSUM checksum_type 258219351Spjd { 259219351Spjd switch (depth) { 260219351Spjd case 0: 261219351Spjd depth0_checksum = $2; 262219351Spjd break; 263219351Spjd case 1: 264225784Spjd PJDLOG_ASSERT(curres != NULL); 265225784Spjd curres->hr_checksum = $2; 266219351Spjd break; 267219351Spjd default: 268225782Spjd PJDLOG_ABORT("checksum at wrong depth level"); 269219351Spjd } 270219351Spjd } 271219351Spjd ; 272219351Spjd 273219351Spjdchecksum_type: 274219351Spjd NONE { $$ = HAST_CHECKSUM_NONE; } 275219351Spjd | 276219351Spjd CRC32 { $$ = HAST_CHECKSUM_CRC32; } 277219351Spjd | 278219351Spjd SHA256 { $$ = HAST_CHECKSUM_SHA256; } 279219351Spjd ; 280219351Spjd 281219354Spjdcompression_statement: COMPRESSION compression_type 282219354Spjd { 283219354Spjd switch (depth) { 284219354Spjd case 0: 285219354Spjd depth0_compression = $2; 286219354Spjd break; 287219354Spjd case 1: 288225784Spjd PJDLOG_ASSERT(curres != NULL); 289225784Spjd curres->hr_compression = $2; 290219354Spjd break; 291219354Spjd default: 292225782Spjd PJDLOG_ABORT("compression at wrong depth level"); 293219354Spjd } 294219354Spjd } 295219354Spjd ; 296219354Spjd 297219354Spjdcompression_type: 298219354Spjd NONE { $$ = HAST_COMPRESSION_NONE; } 299219354Spjd | 300219354Spjd HOLE { $$ = HAST_COMPRESSION_HOLE; } 301219354Spjd | 302219354Spjd LZF { $$ = HAST_COMPRESSION_LZF; } 303219354Spjd ; 304219354Spjd 305207371Spjdtimeout_statement: TIMEOUT NUM 306207371Spjd { 307220889Spjd if ($2 <= 0) { 308220889Spjd pjdlog_error("Negative or zero timeout."); 309220889Spjd return (1); 310220889Spjd } 311207371Spjd switch (depth) { 312207371Spjd case 0: 313207371Spjd depth0_timeout = $2; 314207371Spjd break; 315207371Spjd case 1: 316225784Spjd PJDLOG_ASSERT(curres != NULL); 317225784Spjd curres->hr_timeout = $2; 318207371Spjd break; 319207371Spjd default: 320225782Spjd PJDLOG_ABORT("timeout at wrong depth level"); 321207371Spjd } 322207371Spjd } 323207371Spjd ; 324207371Spjd 325211886Spjdexec_statement: EXEC STR 326211886Spjd { 327211886Spjd switch (depth) { 328211886Spjd case 0: 329211886Spjd if (strlcpy(depth0_exec, $2, sizeof(depth0_exec)) >= 330211886Spjd sizeof(depth0_exec)) { 331211886Spjd pjdlog_error("Exec path is too long."); 332214274Spjd free($2); 333211886Spjd return (1); 334211886Spjd } 335211886Spjd break; 336211886Spjd case 1: 337225784Spjd PJDLOG_ASSERT(curres != NULL); 338211886Spjd if (strlcpy(curres->hr_exec, $2, 339211886Spjd sizeof(curres->hr_exec)) >= 340211886Spjd sizeof(curres->hr_exec)) { 341211886Spjd pjdlog_error("Exec path is too long."); 342214274Spjd free($2); 343211886Spjd return (1); 344211886Spjd } 345211886Spjd break; 346211886Spjd default: 347225782Spjd PJDLOG_ABORT("exec at wrong depth level"); 348211886Spjd } 349214274Spjd free($2); 350211886Spjd } 351211886Spjd ; 352211886Spjd 353225830Spjdmetaflush_statement: METAFLUSH boolean 354225830Spjd { 355225830Spjd switch (depth) { 356225830Spjd case 0: 357225830Spjd depth0_metaflush = $2; 358225830Spjd break; 359225830Spjd case 1: 360225830Spjd PJDLOG_ASSERT(curres != NULL); 361225830Spjd depth1_metaflush = $2; 362225830Spjd break; 363225830Spjd case 2: 364225830Spjd if (!mynode) 365225830Spjd break; 366225830Spjd PJDLOG_ASSERT(curres != NULL); 367225830Spjd curres->hr_metaflush = $2; 368225830Spjd break; 369225830Spjd default: 370225830Spjd PJDLOG_ABORT("metaflush at wrong depth level"); 371225830Spjd } 372225830Spjd } 373225830Spjd ; 374225830Spjd 375225830Spjdboolean: 376225830Spjd ON { $$ = 1; } 377225830Spjd | 378225830Spjd OFF { $$ = 0; } 379225830Spjd ; 380225830Spjd 381204076Spjdnode_statement: ON node_start OB node_entries CB 382204076Spjd { 383204076Spjd mynode = false; 384204076Spjd } 385204076Spjd ; 386204076Spjd 387204076Spjdnode_start: STR 388204076Spjd { 389210883Spjd switch (isitme($1)) { 390210883Spjd case -1: 391214274Spjd free($1); 392210883Spjd return (1); 393210883Spjd case 0: 394210883Spjd break; 395210883Spjd case 1: 396204076Spjd mynode = true; 397210883Spjd break; 398210883Spjd default: 399225782Spjd PJDLOG_ABORT("invalid isitme() return value"); 400210883Spjd } 401214274Spjd free($1); 402204076Spjd } 403204076Spjd ; 404204076Spjd 405204076Spjdnode_entries: 406204076Spjd | 407204076Spjd node_entries node_entry 408204076Spjd ; 409204076Spjd 410204076Spjdnode_entry: 411204076Spjd control_statement 412204076Spjd | 413226463Spjd pidfile_statement 414226463Spjd | 415204076Spjd listen_statement 416204076Spjd ; 417204076Spjd 418204076Spjdresource_statement: RESOURCE resource_start OB resource_entries CB 419204076Spjd { 420204076Spjd if (curres != NULL) { 421204076Spjd /* 422216721Spjd * There must be section for this node, at least with 423216721Spjd * remote address configuration. 424216721Spjd */ 425216721Spjd if (!hadmynode) { 426216721Spjd char *names; 427216721Spjd 428216721Spjd if (node_names(&names) != 0) 429216721Spjd return (1); 430216721Spjd pjdlog_error("No resource %s configuration for this node (acceptable node names: %s).", 431216721Spjd curres->hr_name, names); 432216721Spjd return (1); 433216721Spjd } 434216721Spjd 435216721Spjd /* 436225784Spjd * Let's see if there are some resource-level settings 437204076Spjd * that we can use for node-level settings. 438204076Spjd */ 439204076Spjd if (curres->hr_provname[0] == '\0' && 440204076Spjd depth1_provname[0] != '\0') { 441204076Spjd /* 442204076Spjd * Provider name is not set at node-level, 443204076Spjd * but is set at resource-level, use it. 444204076Spjd */ 445204076Spjd strlcpy(curres->hr_provname, depth1_provname, 446204076Spjd sizeof(curres->hr_provname)); 447204076Spjd } 448204076Spjd if (curres->hr_localpath[0] == '\0' && 449204076Spjd depth1_localpath[0] != '\0') { 450204076Spjd /* 451204076Spjd * Path to local provider is not set at 452204076Spjd * node-level, but is set at resource-level, 453204076Spjd * use it. 454204076Spjd */ 455204076Spjd strlcpy(curres->hr_localpath, depth1_localpath, 456204076Spjd sizeof(curres->hr_localpath)); 457204076Spjd } 458225830Spjd if (curres->hr_metaflush == -1 && depth1_metaflush != -1) { 459225830Spjd /* 460225830Spjd * Metaflush is not set at node-level, 461225830Spjd * but is set at resource-level, use it. 462225830Spjd */ 463225830Spjd curres->hr_metaflush = depth1_metaflush; 464225830Spjd } 465204076Spjd 466204076Spjd /* 467204076Spjd * If provider name is not given, use resource name 468204076Spjd * as provider name. 469204076Spjd */ 470204076Spjd if (curres->hr_provname[0] == '\0') { 471204076Spjd strlcpy(curres->hr_provname, curres->hr_name, 472204076Spjd sizeof(curres->hr_provname)); 473204076Spjd } 474204076Spjd 475204076Spjd /* 476204076Spjd * Remote address has to be configured at this point. 477204076Spjd */ 478204076Spjd if (curres->hr_remoteaddr[0] == '\0') { 479210883Spjd pjdlog_error("Remote address not configured for resource %s.", 480204076Spjd curres->hr_name); 481210883Spjd return (1); 482204076Spjd } 483204076Spjd /* 484204076Spjd * Path to local provider has to be configured at this 485204076Spjd * point. 486204076Spjd */ 487204076Spjd if (curres->hr_localpath[0] == '\0') { 488210883Spjd pjdlog_error("Path to local component not configured for resource %s.", 489204076Spjd curres->hr_name); 490210883Spjd return (1); 491204076Spjd } 492204076Spjd 493204076Spjd /* Put it onto resource list. */ 494210883Spjd TAILQ_INSERT_TAIL(&lconfig->hc_resources, curres, hr_next); 495204076Spjd curres = NULL; 496204076Spjd } 497204076Spjd } 498204076Spjd ; 499204076Spjd 500204076Spjdresource_start: STR 501204076Spjd { 502216722Spjd /* Check if there is no duplicate entry. */ 503216722Spjd TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) { 504216722Spjd if (strcmp(curres->hr_name, $1) == 0) { 505216722Spjd pjdlog_error("Resource %s configured more than once.", 506216722Spjd curres->hr_name); 507216722Spjd free($1); 508216722Spjd return (1); 509216722Spjd } 510216722Spjd } 511216722Spjd 512204076Spjd /* 513204076Spjd * Clear those, so we can tell if they were set at 514204076Spjd * resource-level or not. 515204076Spjd */ 516204076Spjd depth1_provname[0] = '\0'; 517204076Spjd depth1_localpath[0] = '\0'; 518225830Spjd depth1_metaflush = -1; 519216721Spjd hadmynode = false; 520204076Spjd 521204076Spjd curres = calloc(1, sizeof(*curres)); 522204076Spjd if (curres == NULL) { 523210883Spjd pjdlog_error("Unable to allocate memory for resource."); 524214274Spjd free($1); 525210883Spjd return (1); 526204076Spjd } 527204076Spjd if (strlcpy(curres->hr_name, $1, 528204076Spjd sizeof(curres->hr_name)) >= 529204076Spjd sizeof(curres->hr_name)) { 530210883Spjd pjdlog_error("Resource name is too long."); 531230436Spjd free(curres); 532214274Spjd free($1); 533210883Spjd return (1); 534204076Spjd } 535214274Spjd free($1); 536204076Spjd curres->hr_role = HAST_ROLE_INIT; 537204076Spjd curres->hr_previous_role = HAST_ROLE_INIT; 538204076Spjd curres->hr_replication = -1; 539246922Spjd curres->hr_original_replication = -1; 540219351Spjd curres->hr_checksum = -1; 541219354Spjd curres->hr_compression = -1; 542246922Spjd curres->hr_version = 1; 543207371Spjd curres->hr_timeout = -1; 544211886Spjd curres->hr_exec[0] = '\0'; 545204076Spjd curres->hr_provname[0] = '\0'; 546204076Spjd curres->hr_localpath[0] = '\0'; 547204076Spjd curres->hr_localfd = -1; 548225832Spjd curres->hr_localflush = true; 549225830Spjd curres->hr_metaflush = -1; 550204076Spjd curres->hr_remoteaddr[0] = '\0'; 551219818Spjd curres->hr_sourceaddr[0] = '\0'; 552204076Spjd curres->hr_ggateunit = -1; 553204076Spjd } 554204076Spjd ; 555204076Spjd 556204076Spjdresource_entries: 557204076Spjd | 558204076Spjd resource_entries resource_entry 559204076Spjd ; 560204076Spjd 561204076Spjdresource_entry: 562204076Spjd replication_statement 563204076Spjd | 564219351Spjd checksum_statement 565219351Spjd | 566219354Spjd compression_statement 567219354Spjd | 568207371Spjd timeout_statement 569207371Spjd | 570211886Spjd exec_statement 571211886Spjd | 572225830Spjd metaflush_statement 573225830Spjd | 574204076Spjd name_statement 575204076Spjd | 576204076Spjd local_statement 577204076Spjd | 578204076Spjd resource_node_statement 579204076Spjd ; 580204076Spjd 581204076Spjdname_statement: NAME STR 582204076Spjd { 583204076Spjd switch (depth) { 584204076Spjd case 1: 585204076Spjd if (strlcpy(depth1_provname, $2, 586204076Spjd sizeof(depth1_provname)) >= 587204076Spjd sizeof(depth1_provname)) { 588210883Spjd pjdlog_error("name argument is too long."); 589214274Spjd free($2); 590210883Spjd return (1); 591204076Spjd } 592204076Spjd break; 593204076Spjd case 2: 594211883Spjd if (!mynode) 595211883Spjd break; 596225782Spjd PJDLOG_ASSERT(curres != NULL); 597211883Spjd if (strlcpy(curres->hr_provname, $2, 598211883Spjd sizeof(curres->hr_provname)) >= 599211883Spjd sizeof(curres->hr_provname)) { 600211883Spjd pjdlog_error("name argument is too long."); 601214274Spjd free($2); 602211883Spjd return (1); 603204076Spjd } 604204076Spjd break; 605204076Spjd default: 606225782Spjd PJDLOG_ABORT("name at wrong depth level"); 607204076Spjd } 608214274Spjd free($2); 609204076Spjd } 610204076Spjd ; 611204076Spjd 612204076Spjdlocal_statement: LOCAL STR 613204076Spjd { 614204076Spjd switch (depth) { 615204076Spjd case 1: 616204076Spjd if (strlcpy(depth1_localpath, $2, 617204076Spjd sizeof(depth1_localpath)) >= 618204076Spjd sizeof(depth1_localpath)) { 619210883Spjd pjdlog_error("local argument is too long."); 620214274Spjd free($2); 621210883Spjd return (1); 622204076Spjd } 623204076Spjd break; 624204076Spjd case 2: 625211883Spjd if (!mynode) 626211883Spjd break; 627225782Spjd PJDLOG_ASSERT(curres != NULL); 628211883Spjd if (strlcpy(curres->hr_localpath, $2, 629211883Spjd sizeof(curres->hr_localpath)) >= 630211883Spjd sizeof(curres->hr_localpath)) { 631211883Spjd pjdlog_error("local argument is too long."); 632214274Spjd free($2); 633211883Spjd return (1); 634204076Spjd } 635204076Spjd break; 636204076Spjd default: 637225782Spjd PJDLOG_ABORT("local at wrong depth level"); 638204076Spjd } 639214274Spjd free($2); 640204076Spjd } 641204076Spjd ; 642204076Spjd 643204076Spjdresource_node_statement:ON resource_node_start OB resource_node_entries CB 644204076Spjd { 645204076Spjd mynode = false; 646204076Spjd } 647204076Spjd ; 648204076Spjd 649204076Spjdresource_node_start: STR 650204076Spjd { 651210883Spjd if (curres != NULL) { 652210883Spjd switch (isitme($1)) { 653210883Spjd case -1: 654214274Spjd free($1); 655210883Spjd return (1); 656210883Spjd case 0: 657210883Spjd break; 658210883Spjd case 1: 659216721Spjd mynode = hadmynode = true; 660210883Spjd break; 661210883Spjd default: 662225782Spjd PJDLOG_ABORT("invalid isitme() return value"); 663210883Spjd } 664210883Spjd } 665214274Spjd free($1); 666204076Spjd } 667204076Spjd ; 668204076Spjd 669204076Spjdresource_node_entries: 670204076Spjd | 671204076Spjd resource_node_entries resource_node_entry 672204076Spjd ; 673204076Spjd 674204076Spjdresource_node_entry: 675204076Spjd name_statement 676204076Spjd | 677204076Spjd local_statement 678204076Spjd | 679204076Spjd remote_statement 680219818Spjd | 681219818Spjd source_statement 682225830Spjd | 683225830Spjd metaflush_statement 684204076Spjd ; 685204076Spjd 686221643Spjdremote_statement: REMOTE remote_str 687204076Spjd { 688225782Spjd PJDLOG_ASSERT(depth == 2); 689204076Spjd if (mynode) { 690225782Spjd PJDLOG_ASSERT(curres != NULL); 691204076Spjd if (strlcpy(curres->hr_remoteaddr, $2, 692204076Spjd sizeof(curres->hr_remoteaddr)) >= 693204076Spjd sizeof(curres->hr_remoteaddr)) { 694210883Spjd pjdlog_error("remote argument is too long."); 695214274Spjd free($2); 696210883Spjd return (1); 697204076Spjd } 698204076Spjd } 699214274Spjd free($2); 700204076Spjd } 701204076Spjd ; 702219818Spjd 703221643Spjdremote_str: 704221643Spjd NONE { $$ = strdup("none"); } 705221643Spjd | 706221643Spjd STR { } 707221643Spjd ; 708221643Spjd 709219818Spjdsource_statement: SOURCE STR 710219818Spjd { 711225782Spjd PJDLOG_ASSERT(depth == 2); 712219818Spjd if (mynode) { 713225782Spjd PJDLOG_ASSERT(curres != NULL); 714219818Spjd if (strlcpy(curres->hr_sourceaddr, $2, 715219818Spjd sizeof(curres->hr_sourceaddr)) >= 716219818Spjd sizeof(curres->hr_sourceaddr)) { 717219818Spjd pjdlog_error("source argument is too long."); 718219818Spjd free($2); 719219818Spjd return (1); 720219818Spjd } 721219818Spjd } 722219818Spjd free($2); 723219818Spjd } 724219818Spjd ; 725235789Sbapt 726235789Sbapt%% 727235789Sbapt 728235789Sbaptstatic int 729235789Sbaptisitme(const char *name) 730235789Sbapt{ 731235789Sbapt char buf[MAXHOSTNAMELEN]; 732246922Spjd unsigned long hostid; 733235789Sbapt char *pos; 734235789Sbapt size_t bufsize; 735235789Sbapt 736235789Sbapt /* 737235789Sbapt * First check if the given name matches our full hostname. 738235789Sbapt */ 739235789Sbapt if (gethostname(buf, sizeof(buf)) < 0) { 740235789Sbapt pjdlog_errno(LOG_ERR, "gethostname() failed"); 741235789Sbapt return (-1); 742235789Sbapt } 743235789Sbapt if (strcmp(buf, name) == 0) 744235789Sbapt return (1); 745235789Sbapt 746235789Sbapt /* 747246922Spjd * Check if it matches first part of the host name. 748235789Sbapt */ 749235789Sbapt pos = strchr(buf, '.'); 750235789Sbapt if (pos != NULL && (size_t)(pos - buf) == strlen(name) && 751235789Sbapt strncmp(buf, name, pos - buf) == 0) { 752235789Sbapt return (1); 753235789Sbapt } 754235789Sbapt 755235789Sbapt /* 756246922Spjd * Check if it matches host UUID. 757235789Sbapt */ 758235789Sbapt bufsize = sizeof(buf); 759235789Sbapt if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) { 760235789Sbapt pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed"); 761235789Sbapt return (-1); 762235789Sbapt } 763235789Sbapt if (strcasecmp(buf, name) == 0) 764235789Sbapt return (1); 765235789Sbapt 766235789Sbapt /* 767246922Spjd * Check if it matches hostid. 768246922Spjd */ 769246922Spjd bufsize = sizeof(hostid); 770246922Spjd if (sysctlbyname("kern.hostid", &hostid, &bufsize, NULL, 0) < 0) { 771246922Spjd pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostid) failed"); 772246922Spjd return (-1); 773246922Spjd } 774246922Spjd (void)snprintf(buf, sizeof(buf), "hostid%lu", hostid); 775246922Spjd if (strcmp(buf, name) == 0) 776246922Spjd return (1); 777246922Spjd 778246922Spjd /* 779235789Sbapt * Looks like this isn't about us. 780235789Sbapt */ 781235789Sbapt return (0); 782235789Sbapt} 783235789Sbapt 784235789Sbaptstatic bool 785235789Sbaptfamily_supported(int family) 786235789Sbapt{ 787235789Sbapt int sock; 788235789Sbapt 789235789Sbapt sock = socket(family, SOCK_STREAM, 0); 790246922Spjd if (sock == -1 && errno == EPROTONOSUPPORT) 791235789Sbapt return (false); 792235789Sbapt if (sock >= 0) 793235789Sbapt (void)close(sock); 794235789Sbapt return (true); 795235789Sbapt} 796235789Sbapt 797235789Sbaptstatic int 798235789Sbaptnode_names(char **namesp) 799235789Sbapt{ 800235789Sbapt static char names[MAXHOSTNAMELEN * 3]; 801235789Sbapt char buf[MAXHOSTNAMELEN]; 802246922Spjd unsigned long hostid; 803235789Sbapt char *pos; 804235789Sbapt size_t bufsize; 805235789Sbapt 806235789Sbapt if (gethostname(buf, sizeof(buf)) < 0) { 807235789Sbapt pjdlog_errno(LOG_ERR, "gethostname() failed"); 808235789Sbapt return (-1); 809235789Sbapt } 810235789Sbapt 811235789Sbapt /* First component of the host name. */ 812235789Sbapt pos = strchr(buf, '.'); 813235789Sbapt if (pos != NULL && pos != buf) { 814235789Sbapt (void)strlcpy(names, buf, MIN((size_t)(pos - buf + 1), 815235789Sbapt sizeof(names))); 816235789Sbapt (void)strlcat(names, ", ", sizeof(names)); 817235789Sbapt } 818235789Sbapt 819235789Sbapt /* Full host name. */ 820235789Sbapt (void)strlcat(names, buf, sizeof(names)); 821235789Sbapt (void)strlcat(names, ", ", sizeof(names)); 822235789Sbapt 823235789Sbapt /* Host UUID. */ 824235789Sbapt bufsize = sizeof(buf); 825235789Sbapt if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) { 826235789Sbapt pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed"); 827235789Sbapt return (-1); 828235789Sbapt } 829235789Sbapt (void)strlcat(names, buf, sizeof(names)); 830246922Spjd (void)strlcat(names, ", ", sizeof(names)); 831235789Sbapt 832246922Spjd /* Host ID. */ 833246922Spjd bufsize = sizeof(hostid); 834246922Spjd if (sysctlbyname("kern.hostid", &hostid, &bufsize, NULL, 0) < 0) { 835246922Spjd pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostid) failed"); 836246922Spjd return (-1); 837246922Spjd } 838246922Spjd (void)snprintf(buf, sizeof(buf), "hostid%lu", hostid); 839246922Spjd (void)strlcat(names, buf, sizeof(names)); 840246922Spjd 841235789Sbapt *namesp = names; 842235789Sbapt 843235789Sbapt return (0); 844235789Sbapt} 845235789Sbapt 846235789Sbaptvoid 847235789Sbaptyyerror(const char *str) 848235789Sbapt{ 849235789Sbapt 850235789Sbapt pjdlog_error("Unable to parse configuration file at line %d near '%s': %s", 851235789Sbapt lineno, yytext, str); 852235789Sbapt} 853235789Sbapt 854235789Sbaptstruct hastd_config * 855235789Sbaptyy_config_parse(const char *config, bool exitonerror) 856235789Sbapt{ 857235789Sbapt int ret; 858235789Sbapt 859235789Sbapt curres = NULL; 860235789Sbapt mynode = false; 861235789Sbapt depth = 0; 862235789Sbapt lineno = 0; 863235789Sbapt 864235789Sbapt depth0_timeout = HAST_TIMEOUT; 865246922Spjd depth0_replication = HAST_REPLICATION_MEMSYNC; 866235789Sbapt depth0_checksum = HAST_CHECKSUM_NONE; 867235789Sbapt depth0_compression = HAST_COMPRESSION_HOLE; 868235789Sbapt strlcpy(depth0_control, HAST_CONTROL, sizeof(depth0_control)); 869235789Sbapt strlcpy(depth0_pidfile, HASTD_PIDFILE, sizeof(depth0_pidfile)); 870235789Sbapt TAILQ_INIT(&depth0_listen); 871235789Sbapt strlcpy(depth0_listen_tcp4, HASTD_LISTEN_TCP4, 872235789Sbapt sizeof(depth0_listen_tcp4)); 873235789Sbapt strlcpy(depth0_listen_tcp6, HASTD_LISTEN_TCP6, 874235789Sbapt sizeof(depth0_listen_tcp6)); 875235789Sbapt depth0_exec[0] = '\0'; 876235789Sbapt depth0_metaflush = 1; 877235789Sbapt 878235789Sbapt lconfig = calloc(1, sizeof(*lconfig)); 879235789Sbapt if (lconfig == NULL) { 880235789Sbapt pjdlog_error("Unable to allocate memory for configuration."); 881235789Sbapt if (exitonerror) 882235789Sbapt exit(EX_TEMPFAIL); 883235789Sbapt return (NULL); 884235789Sbapt } 885235789Sbapt 886235789Sbapt TAILQ_INIT(&lconfig->hc_listen); 887235789Sbapt TAILQ_INIT(&lconfig->hc_resources); 888235789Sbapt 889235789Sbapt yyin = fopen(config, "r"); 890235789Sbapt if (yyin == NULL) { 891235789Sbapt pjdlog_errno(LOG_ERR, "Unable to open configuration file %s", 892235789Sbapt config); 893235789Sbapt yy_config_free(lconfig); 894235789Sbapt if (exitonerror) 895235789Sbapt exit(EX_OSFILE); 896235789Sbapt return (NULL); 897235789Sbapt } 898235789Sbapt yyrestart(yyin); 899235789Sbapt ret = yyparse(); 900235789Sbapt fclose(yyin); 901235789Sbapt if (ret != 0) { 902235789Sbapt yy_config_free(lconfig); 903235789Sbapt if (exitonerror) 904235789Sbapt exit(EX_CONFIG); 905235789Sbapt return (NULL); 906235789Sbapt } 907235789Sbapt 908235789Sbapt /* 909235789Sbapt * Let's see if everything is set up. 910235789Sbapt */ 911235789Sbapt if (lconfig->hc_controladdr[0] == '\0') { 912235789Sbapt strlcpy(lconfig->hc_controladdr, depth0_control, 913235789Sbapt sizeof(lconfig->hc_controladdr)); 914235789Sbapt } 915235789Sbapt if (lconfig->hc_pidfile[0] == '\0') { 916235789Sbapt strlcpy(lconfig->hc_pidfile, depth0_pidfile, 917235789Sbapt sizeof(lconfig->hc_pidfile)); 918235789Sbapt } 919235789Sbapt if (!TAILQ_EMPTY(&depth0_listen)) 920235789Sbapt TAILQ_CONCAT(&lconfig->hc_listen, &depth0_listen, hl_next); 921235789Sbapt if (TAILQ_EMPTY(&lconfig->hc_listen)) { 922235789Sbapt struct hastd_listen *lst; 923235789Sbapt 924235789Sbapt if (family_supported(AF_INET)) { 925235789Sbapt lst = calloc(1, sizeof(*lst)); 926235789Sbapt if (lst == NULL) { 927235789Sbapt pjdlog_error("Unable to allocate memory for listen address."); 928235789Sbapt yy_config_free(lconfig); 929235789Sbapt if (exitonerror) 930235789Sbapt exit(EX_TEMPFAIL); 931235789Sbapt return (NULL); 932235789Sbapt } 933235789Sbapt (void)strlcpy(lst->hl_addr, depth0_listen_tcp4, 934235789Sbapt sizeof(lst->hl_addr)); 935235789Sbapt TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next); 936235789Sbapt } else { 937235789Sbapt pjdlog_debug(1, 938235789Sbapt "No IPv4 support in the kernel, not listening on IPv4 address."); 939235789Sbapt } 940235789Sbapt if (family_supported(AF_INET6)) { 941235789Sbapt lst = calloc(1, sizeof(*lst)); 942235789Sbapt if (lst == NULL) { 943235789Sbapt pjdlog_error("Unable to allocate memory for listen address."); 944235789Sbapt yy_config_free(lconfig); 945235789Sbapt if (exitonerror) 946235789Sbapt exit(EX_TEMPFAIL); 947235789Sbapt return (NULL); 948235789Sbapt } 949235789Sbapt (void)strlcpy(lst->hl_addr, depth0_listen_tcp6, 950235789Sbapt sizeof(lst->hl_addr)); 951235789Sbapt TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next); 952235789Sbapt } else { 953235789Sbapt pjdlog_debug(1, 954235789Sbapt "No IPv6 support in the kernel, not listening on IPv6 address."); 955235789Sbapt } 956235789Sbapt if (TAILQ_EMPTY(&lconfig->hc_listen)) { 957235789Sbapt pjdlog_error("No address to listen on."); 958235789Sbapt yy_config_free(lconfig); 959235789Sbapt if (exitonerror) 960235789Sbapt exit(EX_TEMPFAIL); 961235789Sbapt return (NULL); 962235789Sbapt } 963235789Sbapt } 964235789Sbapt TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) { 965235789Sbapt PJDLOG_ASSERT(curres->hr_provname[0] != '\0'); 966235789Sbapt PJDLOG_ASSERT(curres->hr_localpath[0] != '\0'); 967235789Sbapt PJDLOG_ASSERT(curres->hr_remoteaddr[0] != '\0'); 968235789Sbapt 969235789Sbapt if (curres->hr_replication == -1) { 970235789Sbapt /* 971235789Sbapt * Replication is not set at resource-level. 972235789Sbapt * Use global or default setting. 973235789Sbapt */ 974235789Sbapt curres->hr_replication = depth0_replication; 975246922Spjd curres->hr_original_replication = depth0_replication; 976235789Sbapt } 977235789Sbapt if (curres->hr_checksum == -1) { 978235789Sbapt /* 979235789Sbapt * Checksum is not set at resource-level. 980235789Sbapt * Use global or default setting. 981235789Sbapt */ 982235789Sbapt curres->hr_checksum = depth0_checksum; 983235789Sbapt } 984235789Sbapt if (curres->hr_compression == -1) { 985235789Sbapt /* 986235789Sbapt * Compression is not set at resource-level. 987235789Sbapt * Use global or default setting. 988235789Sbapt */ 989235789Sbapt curres->hr_compression = depth0_compression; 990235789Sbapt } 991235789Sbapt if (curres->hr_timeout == -1) { 992235789Sbapt /* 993235789Sbapt * Timeout is not set at resource-level. 994235789Sbapt * Use global or default setting. 995235789Sbapt */ 996235789Sbapt curres->hr_timeout = depth0_timeout; 997235789Sbapt } 998235789Sbapt if (curres->hr_exec[0] == '\0') { 999235789Sbapt /* 1000235789Sbapt * Exec is not set at resource-level. 1001235789Sbapt * Use global or default setting. 1002235789Sbapt */ 1003235789Sbapt strlcpy(curres->hr_exec, depth0_exec, 1004235789Sbapt sizeof(curres->hr_exec)); 1005235789Sbapt } 1006235789Sbapt if (curres->hr_metaflush == -1) { 1007235789Sbapt /* 1008235789Sbapt * Metaflush is not set at resource-level. 1009235789Sbapt * Use global or default setting. 1010235789Sbapt */ 1011235789Sbapt curres->hr_metaflush = depth0_metaflush; 1012235789Sbapt } 1013235789Sbapt } 1014235789Sbapt 1015235789Sbapt return (lconfig); 1016235789Sbapt} 1017235789Sbapt 1018235789Sbaptvoid 1019235789Sbaptyy_config_free(struct hastd_config *config) 1020235789Sbapt{ 1021235789Sbapt struct hastd_listen *lst; 1022235789Sbapt struct hast_resource *res; 1023235789Sbapt 1024235789Sbapt while ((lst = TAILQ_FIRST(&depth0_listen)) != NULL) { 1025235789Sbapt TAILQ_REMOVE(&depth0_listen, lst, hl_next); 1026235789Sbapt free(lst); 1027235789Sbapt } 1028235789Sbapt while ((lst = TAILQ_FIRST(&config->hc_listen)) != NULL) { 1029235789Sbapt TAILQ_REMOVE(&config->hc_listen, lst, hl_next); 1030235789Sbapt free(lst); 1031235789Sbapt } 1032235789Sbapt while ((res = TAILQ_FIRST(&config->hc_resources)) != NULL) { 1033235789Sbapt TAILQ_REMOVE(&config->hc_resources, res, hr_next); 1034235789Sbapt free(res); 1035235789Sbapt } 1036235789Sbapt free(config); 1037235789Sbapt} 1038