3 * Copyright (c) 2009-2010 The FreeBSD Foundation
6 * This software was developed by Pawel Jakub Dawidek under sponsorship from
7 * the FreeBSD Foundation.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
33 #include <sys/param.h> /* MAXHOSTNAMELEN */
34 #include <sys/queue.h>
35 #include <sys/sysctl.h>
37 #include <arpa/inet.h>
54 static struct hastd_config lconfig;
55 static struct hast_resource *curres;
58 static char depth0_control[HAST_ADDRSIZE];
59 static char depth0_listen[HAST_ADDRSIZE];
60 static int depth0_replication;
62 static char depth1_provname[PATH_MAX];
63 static char depth1_localpath[PATH_MAX];
66 isitme(const char *name)
68 char buf[MAXHOSTNAMELEN];
73 * First check if the give name matches our full hostname.
75 if (gethostname(buf, sizeof(buf)) < 0)
76 err(EX_OSERR, "gethostname() failed");
77 if (strcmp(buf, name) == 0)
81 * Now check if it matches first part of the host name.
83 pos = strchr(buf, '.');
84 if (pos != NULL && pos != buf && strncmp(buf, name, pos - buf) == 0)
88 * At the end check if name is equal to our host's UUID.
90 bufsize = sizeof(buf);
91 if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0)
92 err(EX_OSERR, "sysctlbyname(kern.hostuuid) failed");
93 if (strcasecmp(buf, name) == 0)
97 * Looks like this isn't about us.
103 yyerror(const char *str)
106 fprintf(stderr, "error at line %d near '%s': %s\n",
107 lineno, yytext, str);
110 struct hastd_config *
111 yy_config_parse(const char *config)
118 depth0_replication = HAST_REPLICATION_MEMSYNC;
119 strlcpy(depth0_control, HAST_CONTROL, sizeof(depth0_control));
120 strlcpy(depth0_listen, HASTD_LISTEN, sizeof(depth0_listen));
122 TAILQ_INIT(&lconfig.hc_resources);
124 yyin = fopen(config, "r");
126 err(EX_OSFILE, "cannot open configuration file %s", config);
130 yy_config_free(&lconfig);
135 * Let's see if everything is set up.
137 if (lconfig.hc_controladdr[0] == '\0') {
138 strlcpy(lconfig.hc_controladdr, depth0_control,
139 sizeof(lconfig.hc_controladdr));
141 if (lconfig.hc_listenaddr[0] == '\0') {
142 strlcpy(lconfig.hc_listenaddr, depth0_listen,
143 sizeof(lconfig.hc_listenaddr));
145 TAILQ_FOREACH(curres, &lconfig.hc_resources, hr_next) {
146 assert(curres->hr_provname[0] != '\0');
147 assert(curres->hr_localpath[0] != '\0');
148 assert(curres->hr_remoteaddr[0] != '\0');
150 if (curres->hr_replication == -1) {
152 * Replication is not set at resource-level.
153 * Use global or default setting.
155 curres->hr_replication = depth0_replication;
163 yy_config_free(struct hastd_config *config)
165 struct hast_resource *res;
167 while ((res = TAILQ_FIRST(&config->hc_resources)) != NULL) {
168 TAILQ_REMOVE(&config->hc_resources, res, hr_next);
174 %token CONTROL LISTEN PORT REPLICATION EXTENTSIZE RESOURCE NAME LOCAL REMOTE ON
175 %token FULLSYNC MEMSYNC ASYNC
178 %type <num> replication_type
201 replication_statement
208 control_statement: CONTROL STR
212 if (strlcpy(depth0_control, $2,
213 sizeof(depth0_control)) >=
214 sizeof(depth0_control)) {
215 errx(EX_CONFIG, "control argument too long");
220 if (strlcpy(lconfig.hc_controladdr, $2,
221 sizeof(lconfig.hc_controladdr)) >=
222 sizeof(lconfig.hc_controladdr)) {
224 "control argument too long");
229 assert(!"control at wrong depth level");
234 listen_statement: LISTEN STR
238 if (strlcpy(depth0_listen, $2,
239 sizeof(depth0_listen)) >=
240 sizeof(depth0_listen)) {
241 errx(EX_CONFIG, "listen argument too long");
246 if (strlcpy(lconfig.hc_listenaddr, $2,
247 sizeof(lconfig.hc_listenaddr)) >=
248 sizeof(lconfig.hc_listenaddr)) {
250 "listen argument too long");
255 assert(!"listen at wrong depth level");
260 replication_statement: REPLICATION replication_type
264 depth0_replication = $2;
268 curres->hr_replication = $2;
271 assert(!"replication at wrong depth level");
277 FULLSYNC { $$ = HAST_REPLICATION_FULLSYNC; }
279 MEMSYNC { $$ = HAST_REPLICATION_MEMSYNC; }
281 ASYNC { $$ = HAST_REPLICATION_ASYNC; }
284 node_statement: ON node_start OB node_entries CB
299 node_entries node_entry
308 resource_statement: RESOURCE resource_start OB resource_entries CB
310 if (curres != NULL) {
312 * Let's see there are some resource-level settings
313 * that we can use for node-level settings.
315 if (curres->hr_provname[0] == '\0' &&
316 depth1_provname[0] != '\0') {
318 * Provider name is not set at node-level,
319 * but is set at resource-level, use it.
321 strlcpy(curres->hr_provname, depth1_provname,
322 sizeof(curres->hr_provname));
324 if (curres->hr_localpath[0] == '\0' &&
325 depth1_localpath[0] != '\0') {
327 * Path to local provider is not set at
328 * node-level, but is set at resource-level,
331 strlcpy(curres->hr_localpath, depth1_localpath,
332 sizeof(curres->hr_localpath));
336 * If provider name is not given, use resource name
339 if (curres->hr_provname[0] == '\0') {
340 strlcpy(curres->hr_provname, curres->hr_name,
341 sizeof(curres->hr_provname));
345 * Remote address has to be configured at this point.
347 if (curres->hr_remoteaddr[0] == '\0') {
349 "remote address not configured for resource %s",
353 * Path to local provider has to be configured at this
356 if (curres->hr_localpath[0] == '\0') {
358 "path local component not configured for resource %s",
362 /* Put it onto resource list. */
363 TAILQ_INSERT_TAIL(&lconfig.hc_resources, curres, hr_next);
372 * Clear those, so we can tell if they were set at
373 * resource-level or not.
375 depth1_provname[0] = '\0';
376 depth1_localpath[0] = '\0';
378 curres = calloc(1, sizeof(*curres));
379 if (curres == NULL) {
381 "cannot allocate memory for resource");
383 if (strlcpy(curres->hr_name, $1,
384 sizeof(curres->hr_name)) >=
385 sizeof(curres->hr_name)) {
387 "resource name (%s) too long", $1);
389 curres->hr_role = HAST_ROLE_INIT;
390 curres->hr_previous_role = HAST_ROLE_INIT;
391 curres->hr_replication = -1;
392 curres->hr_provname[0] = '\0';
393 curres->hr_localpath[0] = '\0';
394 curres->hr_localfd = -1;
395 curres->hr_remoteaddr[0] = '\0';
396 curres->hr_ggateunit = -1;
402 resource_entries resource_entry
406 replication_statement
412 resource_node_statement
415 name_statement: NAME STR
419 if (strlcpy(depth1_provname, $2,
420 sizeof(depth1_provname)) >=
421 sizeof(depth1_provname)) {
422 errx(EX_CONFIG, "name argument too long");
427 assert(curres != NULL);
428 if (strlcpy(curres->hr_provname, $2,
429 sizeof(curres->hr_provname)) >=
430 sizeof(curres->hr_provname)) {
432 "name argument too long");
437 assert(!"name at wrong depth level");
442 local_statement: LOCAL STR
446 if (strlcpy(depth1_localpath, $2,
447 sizeof(depth1_localpath)) >=
448 sizeof(depth1_localpath)) {
449 errx(EX_CONFIG, "local argument too long");
454 assert(curres != NULL);
455 if (strlcpy(curres->hr_localpath, $2,
456 sizeof(curres->hr_localpath)) >=
457 sizeof(curres->hr_localpath)) {
459 "local argument too long");
464 assert(!"local at wrong depth level");
469 resource_node_statement:ON resource_node_start OB resource_node_entries CB
475 resource_node_start: STR
477 if (curres != NULL && isitme($1))
482 resource_node_entries:
484 resource_node_entries resource_node_entry
495 remote_statement: REMOTE STR
499 assert(curres != NULL);
500 if (strlcpy(curres->hr_remoteaddr, $2,
501 sizeof(curres->hr_remoteaddr)) >=
502 sizeof(curres->hr_remoteaddr)) {
503 errx(EX_CONFIG, "remote argument too long");