parse.y revision 211886
1%{ 2/*- 3 * Copyright (c) 2009-2010 The FreeBSD Foundation 4 * All rights reserved. 5 * 6 * This software was developed by Pawel Jakub Dawidek under sponsorship from 7 * the FreeBSD Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * $FreeBSD: head/sbin/hastd/parse.y 211886 2010-08-27 15:16:52Z pjd $ 31 */ 32 33#include <sys/param.h> /* MAXHOSTNAMELEN */ 34#include <sys/queue.h> 35#include <sys/sysctl.h> 36 37#include <arpa/inet.h> 38 39#include <assert.h> 40#include <err.h> 41#include <stdio.h> 42#include <string.h> 43#include <sysexits.h> 44#include <unistd.h> 45 46#include <pjdlog.h> 47 48#include "hast.h" 49 50extern int depth; 51extern int lineno; 52 53extern FILE *yyin; 54extern char *yytext; 55 56static struct hastd_config *lconfig; 57static struct hast_resource *curres; 58static bool mynode; 59 60static char depth0_control[HAST_ADDRSIZE]; 61static char depth0_listen[HAST_ADDRSIZE]; 62static int depth0_replication; 63static int depth0_timeout; 64static char depth0_exec[PATH_MAX]; 65 66static char depth1_provname[PATH_MAX]; 67static char depth1_localpath[PATH_MAX]; 68 69extern void yyrestart(FILE *); 70 71static int 72isitme(const char *name) 73{ 74 char buf[MAXHOSTNAMELEN]; 75 char *pos; 76 size_t bufsize; 77 78 /* 79 * First check if the give name matches our full hostname. 80 */ 81 if (gethostname(buf, sizeof(buf)) < 0) { 82 pjdlog_errno(LOG_ERR, "gethostname() failed"); 83 return (-1); 84 } 85 if (strcmp(buf, name) == 0) 86 return (1); 87 88 /* 89 * Now check if it matches first part of the host name. 90 */ 91 pos = strchr(buf, '.'); 92 if (pos != NULL && pos != buf && strncmp(buf, name, pos - buf) == 0) 93 return (1); 94 95 /* 96 * At the end check if name is equal to our host's UUID. 97 */ 98 bufsize = sizeof(buf); 99 if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) { 100 pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed"); 101 return (-1); 102 } 103 if (strcasecmp(buf, name) == 0) 104 return (1); 105 106 /* 107 * Looks like this isn't about us. 108 */ 109 return (0); 110} 111 112void 113yyerror(const char *str) 114{ 115 116 pjdlog_error("Unable to parse configuration file at line %d near '%s': %s", 117 lineno, yytext, str); 118} 119 120struct hastd_config * 121yy_config_parse(const char *config, bool exitonerror) 122{ 123 int ret; 124 125 curres = NULL; 126 mynode = false; 127 depth = 0; 128 lineno = 0; 129 130 depth0_timeout = HAST_TIMEOUT; 131 depth0_replication = HAST_REPLICATION_MEMSYNC; 132 strlcpy(depth0_control, HAST_CONTROL, sizeof(depth0_control)); 133 strlcpy(depth0_listen, HASTD_LISTEN, sizeof(depth0_listen)); 134 depth0_exec[0] = '\0'; 135 136 lconfig = calloc(1, sizeof(*lconfig)); 137 if (lconfig == NULL) { 138 pjdlog_error("Unable to allocate memory for configuration."); 139 if (exitonerror) 140 exit(EX_TEMPFAIL); 141 return (NULL); 142 } 143 144 TAILQ_INIT(&lconfig->hc_resources); 145 146 yyin = fopen(config, "r"); 147 if (yyin == NULL) { 148 pjdlog_errno(LOG_ERR, "Unable to open configuration file %s", 149 config); 150 yy_config_free(lconfig); 151 if (exitonerror) 152 exit(EX_OSFILE); 153 return (NULL); 154 } 155 yyrestart(yyin); 156 ret = yyparse(); 157 fclose(yyin); 158 if (ret != 0) { 159 yy_config_free(lconfig); 160 if (exitonerror) 161 exit(EX_CONFIG); 162 return (NULL); 163 } 164 165 /* 166 * Let's see if everything is set up. 167 */ 168 if (lconfig->hc_controladdr[0] == '\0') { 169 strlcpy(lconfig->hc_controladdr, depth0_control, 170 sizeof(lconfig->hc_controladdr)); 171 } 172 if (lconfig->hc_listenaddr[0] == '\0') { 173 strlcpy(lconfig->hc_listenaddr, depth0_listen, 174 sizeof(lconfig->hc_listenaddr)); 175 } 176 TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) { 177 assert(curres->hr_provname[0] != '\0'); 178 assert(curres->hr_localpath[0] != '\0'); 179 assert(curres->hr_remoteaddr[0] != '\0'); 180 181 if (curres->hr_replication == -1) { 182 /* 183 * Replication is not set at resource-level. 184 * Use global or default setting. 185 */ 186 curres->hr_replication = depth0_replication; 187 } 188 if (curres->hr_timeout == -1) { 189 /* 190 * Timeout is not set at resource-level. 191 * Use global or default setting. 192 */ 193 curres->hr_timeout = depth0_timeout; 194 } 195 if (curres->hr_exec[0] == '\0') { 196 /* 197 * Exec is not set at resource-level. 198 * Use global or default setting. 199 */ 200 strlcpy(curres->hr_exec, depth0_exec, 201 sizeof(curres->hr_exec)); 202 } 203 } 204 205 return (lconfig); 206} 207 208void 209yy_config_free(struct hastd_config *config) 210{ 211 struct hast_resource *res; 212 213 while ((res = TAILQ_FIRST(&config->hc_resources)) != NULL) { 214 TAILQ_REMOVE(&config->hc_resources, res, hr_next); 215 free(res); 216 } 217 free(config); 218} 219%} 220 221%token CONTROL LISTEN PORT REPLICATION TIMEOUT EXEC EXTENTSIZE RESOURCE NAME LOCAL REMOTE ON 222%token FULLSYNC MEMSYNC ASYNC 223%token NUM STR OB CB 224 225%type <num> replication_type 226 227%union 228{ 229 int num; 230 char *str; 231} 232 233%token <num> NUM 234%token <str> STR 235 236%% 237 238statements: 239 | 240 statements statement 241 ; 242 243statement: 244 control_statement 245 | 246 listen_statement 247 | 248 replication_statement 249 | 250 timeout_statement 251 | 252 exec_statement 253 | 254 node_statement 255 | 256 resource_statement 257 ; 258 259control_statement: CONTROL STR 260 { 261 switch (depth) { 262 case 0: 263 if (strlcpy(depth0_control, $2, 264 sizeof(depth0_control)) >= 265 sizeof(depth0_control)) { 266 pjdlog_error("control argument is too long."); 267 return (1); 268 } 269 break; 270 case 1: 271 if (!mynode) 272 break; 273 if (strlcpy(lconfig->hc_controladdr, $2, 274 sizeof(lconfig->hc_controladdr)) >= 275 sizeof(lconfig->hc_controladdr)) { 276 pjdlog_error("control argument is too long."); 277 return (1); 278 } 279 break; 280 default: 281 assert(!"control at wrong depth level"); 282 } 283 } 284 ; 285 286listen_statement: LISTEN STR 287 { 288 switch (depth) { 289 case 0: 290 if (strlcpy(depth0_listen, $2, 291 sizeof(depth0_listen)) >= 292 sizeof(depth0_listen)) { 293 pjdlog_error("listen argument is too long."); 294 return (1); 295 } 296 break; 297 case 1: 298 if (!mynode) 299 break; 300 if (strlcpy(lconfig->hc_listenaddr, $2, 301 sizeof(lconfig->hc_listenaddr)) >= 302 sizeof(lconfig->hc_listenaddr)) { 303 pjdlog_error("listen argument is too long."); 304 return (1); 305 } 306 break; 307 default: 308 assert(!"listen at wrong depth level"); 309 } 310 } 311 ; 312 313replication_statement: REPLICATION replication_type 314 { 315 switch (depth) { 316 case 0: 317 depth0_replication = $2; 318 break; 319 case 1: 320 if (curres != NULL) 321 curres->hr_replication = $2; 322 break; 323 default: 324 assert(!"replication at wrong depth level"); 325 } 326 } 327 ; 328 329replication_type: 330 FULLSYNC { $$ = HAST_REPLICATION_FULLSYNC; } 331 | 332 MEMSYNC { $$ = HAST_REPLICATION_MEMSYNC; } 333 | 334 ASYNC { $$ = HAST_REPLICATION_ASYNC; } 335 ; 336 337timeout_statement: TIMEOUT NUM 338 { 339 switch (depth) { 340 case 0: 341 depth0_timeout = $2; 342 break; 343 case 1: 344 if (curres != NULL) 345 curres->hr_timeout = $2; 346 break; 347 default: 348 assert(!"timeout at wrong depth level"); 349 } 350 } 351 ; 352 353exec_statement: EXEC STR 354 { 355 switch (depth) { 356 case 0: 357 if (strlcpy(depth0_exec, $2, sizeof(depth0_exec)) >= 358 sizeof(depth0_exec)) { 359 pjdlog_error("Exec path is too long."); 360 return (1); 361 } 362 break; 363 case 1: 364 if (curres == NULL) 365 break; 366 if (strlcpy(curres->hr_exec, $2, 367 sizeof(curres->hr_exec)) >= 368 sizeof(curres->hr_exec)) { 369 pjdlog_error("Exec path is too long."); 370 return (1); 371 } 372 break; 373 default: 374 assert(!"exec at wrong depth level"); 375 } 376 } 377 ; 378 379node_statement: ON node_start OB node_entries CB 380 { 381 mynode = false; 382 } 383 ; 384 385node_start: STR 386 { 387 switch (isitme($1)) { 388 case -1: 389 return (1); 390 case 0: 391 break; 392 case 1: 393 mynode = true; 394 break; 395 default: 396 assert(!"invalid isitme() return value"); 397 } 398 } 399 ; 400 401node_entries: 402 | 403 node_entries node_entry 404 ; 405 406node_entry: 407 control_statement 408 | 409 listen_statement 410 ; 411 412resource_statement: RESOURCE resource_start OB resource_entries CB 413 { 414 if (curres != NULL) { 415 /* 416 * Let's see there are some resource-level settings 417 * that we can use for node-level settings. 418 */ 419 if (curres->hr_provname[0] == '\0' && 420 depth1_provname[0] != '\0') { 421 /* 422 * Provider name is not set at node-level, 423 * but is set at resource-level, use it. 424 */ 425 strlcpy(curres->hr_provname, depth1_provname, 426 sizeof(curres->hr_provname)); 427 } 428 if (curres->hr_localpath[0] == '\0' && 429 depth1_localpath[0] != '\0') { 430 /* 431 * Path to local provider is not set at 432 * node-level, but is set at resource-level, 433 * use it. 434 */ 435 strlcpy(curres->hr_localpath, depth1_localpath, 436 sizeof(curres->hr_localpath)); 437 } 438 439 /* 440 * If provider name is not given, use resource name 441 * as provider name. 442 */ 443 if (curres->hr_provname[0] == '\0') { 444 strlcpy(curres->hr_provname, curres->hr_name, 445 sizeof(curres->hr_provname)); 446 } 447 448 /* 449 * Remote address has to be configured at this point. 450 */ 451 if (curres->hr_remoteaddr[0] == '\0') { 452 pjdlog_error("Remote address not configured for resource %s.", 453 curres->hr_name); 454 return (1); 455 } 456 /* 457 * Path to local provider has to be configured at this 458 * point. 459 */ 460 if (curres->hr_localpath[0] == '\0') { 461 pjdlog_error("Path to local component not configured for resource %s.", 462 curres->hr_name); 463 return (1); 464 } 465 466 /* Put it onto resource list. */ 467 TAILQ_INSERT_TAIL(&lconfig->hc_resources, curres, hr_next); 468 curres = NULL; 469 } 470 } 471 ; 472 473resource_start: STR 474 { 475 /* 476 * Clear those, so we can tell if they were set at 477 * resource-level or not. 478 */ 479 depth1_provname[0] = '\0'; 480 depth1_localpath[0] = '\0'; 481 482 curres = calloc(1, sizeof(*curres)); 483 if (curres == NULL) { 484 pjdlog_error("Unable to allocate memory for resource."); 485 return (1); 486 } 487 if (strlcpy(curres->hr_name, $1, 488 sizeof(curres->hr_name)) >= 489 sizeof(curres->hr_name)) { 490 pjdlog_error("Resource name is too long."); 491 return (1); 492 } 493 curres->hr_role = HAST_ROLE_INIT; 494 curres->hr_previous_role = HAST_ROLE_INIT; 495 curres->hr_replication = -1; 496 curres->hr_timeout = -1; 497 curres->hr_exec[0] = '\0'; 498 curres->hr_provname[0] = '\0'; 499 curres->hr_localpath[0] = '\0'; 500 curres->hr_localfd = -1; 501 curres->hr_remoteaddr[0] = '\0'; 502 curres->hr_ggateunit = -1; 503 } 504 ; 505 506resource_entries: 507 | 508 resource_entries resource_entry 509 ; 510 511resource_entry: 512 replication_statement 513 | 514 timeout_statement 515 | 516 exec_statement 517 | 518 name_statement 519 | 520 local_statement 521 | 522 resource_node_statement 523 ; 524 525name_statement: NAME STR 526 { 527 switch (depth) { 528 case 1: 529 if (strlcpy(depth1_provname, $2, 530 sizeof(depth1_provname)) >= 531 sizeof(depth1_provname)) { 532 pjdlog_error("name argument is too long."); 533 return (1); 534 } 535 break; 536 case 2: 537 if (!mynode) 538 break; 539 assert(curres != NULL); 540 if (strlcpy(curres->hr_provname, $2, 541 sizeof(curres->hr_provname)) >= 542 sizeof(curres->hr_provname)) { 543 pjdlog_error("name argument is too long."); 544 return (1); 545 } 546 break; 547 default: 548 assert(!"name at wrong depth level"); 549 } 550 } 551 ; 552 553local_statement: LOCAL STR 554 { 555 switch (depth) { 556 case 1: 557 if (strlcpy(depth1_localpath, $2, 558 sizeof(depth1_localpath)) >= 559 sizeof(depth1_localpath)) { 560 pjdlog_error("local argument is too long."); 561 return (1); 562 } 563 break; 564 case 2: 565 if (!mynode) 566 break; 567 assert(curres != NULL); 568 if (strlcpy(curres->hr_localpath, $2, 569 sizeof(curres->hr_localpath)) >= 570 sizeof(curres->hr_localpath)) { 571 pjdlog_error("local argument is too long."); 572 return (1); 573 } 574 break; 575 default: 576 assert(!"local at wrong depth level"); 577 } 578 } 579 ; 580 581resource_node_statement:ON resource_node_start OB resource_node_entries CB 582 { 583 mynode = false; 584 } 585 ; 586 587resource_node_start: STR 588 { 589 if (curres != NULL) { 590 switch (isitme($1)) { 591 case -1: 592 return (1); 593 case 0: 594 break; 595 case 1: 596 mynode = true; 597 break; 598 default: 599 assert(!"invalid isitme() return value"); 600 } 601 } 602 } 603 ; 604 605resource_node_entries: 606 | 607 resource_node_entries resource_node_entry 608 ; 609 610resource_node_entry: 611 name_statement 612 | 613 local_statement 614 | 615 remote_statement 616 ; 617 618remote_statement: REMOTE STR 619 { 620 assert(depth == 2); 621 if (mynode) { 622 assert(curres != NULL); 623 if (strlcpy(curres->hr_remoteaddr, $2, 624 sizeof(curres->hr_remoteaddr)) >= 625 sizeof(curres->hr_remoteaddr)) { 626 pjdlog_error("remote argument is too long."); 627 return (1); 628 } 629 } 630 } 631 ; 632