]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/hastd/parse.y
Merge with latest head.
[FreeBSD/FreeBSD.git] / sbin / hastd / parse.y
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$
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 "hast.h"
47
48 extern int depth;
49 extern int lineno;
50
51 extern FILE *yyin;
52 extern char *yytext;
53
54 static struct hastd_config lconfig;
55 static struct hast_resource *curres;
56 static bool mynode;
57
58 static char depth0_control[HAST_ADDRSIZE];
59 static char depth0_listen[HAST_ADDRSIZE];
60 static int depth0_replication;
61
62 static char depth1_provname[PATH_MAX];
63 static char depth1_localpath[PATH_MAX];
64
65 static bool
66 isitme(const char *name)
67 {
68         char buf[MAXHOSTNAMELEN];
69         char *pos;
70         size_t bufsize;
71
72         /*
73          * First check if the give name matches our full hostname.
74          */
75         if (gethostname(buf, sizeof(buf)) < 0)
76                 err(EX_OSERR, "gethostname() failed");
77         if (strcmp(buf, name) == 0)
78                 return (true);
79
80         /*
81          * Now check if it matches first part of the host name.
82          */
83         pos = strchr(buf, '.');
84         if (pos != NULL && pos != buf && strncmp(buf, name, pos - buf) == 0)
85                 return (true);
86
87         /*
88          * At the end check if name is equal to our host's UUID.
89          */
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)
94                 return (true);
95
96         /*
97          * Looks like this isn't about us.
98          */
99         return (false);
100 }
101
102 void
103 yyerror(const char *str)
104 {
105
106         fprintf(stderr, "error at line %d near '%s': %s\n",
107             lineno, yytext, str);
108 }
109
110 struct hastd_config *
111 yy_config_parse(const char *config)
112 {
113         int ret;
114
115         curres = NULL;
116         mynode = false;
117
118         depth0_replication = HAST_REPLICATION_MEMSYNC;
119         strlcpy(depth0_control, HAST_CONTROL, sizeof(depth0_control));
120         strlcpy(depth0_listen, HASTD_LISTEN, sizeof(depth0_listen));
121
122         TAILQ_INIT(&lconfig.hc_resources);
123
124         yyin = fopen(config, "r");
125         if (yyin == NULL)
126                 err(EX_OSFILE, "cannot open configuration file %s", config);
127         ret = yyparse();
128         fclose(yyin);
129         if (ret != 0) {
130                 yy_config_free(&lconfig);
131                 exit(EX_CONFIG);
132         }
133
134         /*
135          * Let's see if everything is set up.
136          */
137         if (lconfig.hc_controladdr[0] == '\0') {
138                 strlcpy(lconfig.hc_controladdr, depth0_control,
139                     sizeof(lconfig.hc_controladdr));
140         }
141         if (lconfig.hc_listenaddr[0] == '\0') {
142                 strlcpy(lconfig.hc_listenaddr, depth0_listen,
143                     sizeof(lconfig.hc_listenaddr));
144         }
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');
149
150                 if (curres->hr_replication == -1) {
151                         /*
152                          * Replication is not set at resource-level.
153                          * Use global or default setting.
154                          */
155                         curres->hr_replication = depth0_replication;
156                 }
157         }
158
159         return (&lconfig);
160 }
161
162 void
163 yy_config_free(struct hastd_config *config)
164 {
165         struct hast_resource *res;
166
167         while ((res = TAILQ_FIRST(&config->hc_resources)) != NULL) {
168                 TAILQ_REMOVE(&config->hc_resources, res, hr_next);
169                 free(res);
170         }
171 }
172 %}
173
174 %token CONTROL LISTEN PORT REPLICATION EXTENTSIZE RESOURCE NAME LOCAL REMOTE ON
175 %token FULLSYNC MEMSYNC ASYNC
176 %token NUM STR OB CB
177
178 %type <num> replication_type
179
180 %union
181 {
182         int num;
183         char *str;
184 }
185
186 %token <num> NUM
187 %token <str> STR
188
189 %%
190
191 statements:
192         |
193         statements statement
194         ;
195
196 statement:
197         control_statement
198         |
199         listen_statement
200         |
201         replication_statement
202         |
203         node_statement
204         |
205         resource_statement
206         ;
207
208 control_statement:      CONTROL STR
209         {
210                 switch (depth) {
211                 case 0:
212                         if (strlcpy(depth0_control, $2,
213                             sizeof(depth0_control)) >=
214                             sizeof(depth0_control)) {
215                                 errx(EX_CONFIG, "control argument too long");
216                         }
217                         break;
218                 case 1:
219                         if (mynode) {
220                                 if (strlcpy(lconfig.hc_controladdr, $2,
221                                     sizeof(lconfig.hc_controladdr)) >=
222                                     sizeof(lconfig.hc_controladdr)) {
223                                         errx(EX_CONFIG,
224                                             "control argument too long");
225                                 }
226                         }
227                         break;
228                 default:
229                         assert(!"control at wrong depth level");
230                 }
231         }
232         ;
233
234 listen_statement:       LISTEN STR
235         {
236                 switch (depth) {
237                 case 0:
238                         if (strlcpy(depth0_listen, $2,
239                             sizeof(depth0_listen)) >=
240                             sizeof(depth0_listen)) {
241                                 errx(EX_CONFIG, "listen argument too long");
242                         }
243                         break;
244                 case 1:
245                         if (mynode) {
246                                 if (strlcpy(lconfig.hc_listenaddr, $2,
247                                     sizeof(lconfig.hc_listenaddr)) >=
248                                     sizeof(lconfig.hc_listenaddr)) {
249                                         errx(EX_CONFIG,
250                                             "listen argument too long");
251                                 }
252                         }
253                         break;
254                 default:
255                         assert(!"listen at wrong depth level");
256                 }
257         }
258         ;
259
260 replication_statement:  REPLICATION replication_type
261         {
262                 switch (depth) {
263                 case 0:
264                         depth0_replication = $2;
265                         break;
266                 case 1:
267                         if (curres != NULL)
268                                 curres->hr_replication = $2;
269                         break;
270                 default:
271                         assert(!"replication at wrong depth level");
272                 }
273         }
274         ;
275
276 replication_type:
277         FULLSYNC        { $$ = HAST_REPLICATION_FULLSYNC; }
278         |
279         MEMSYNC         { $$ = HAST_REPLICATION_MEMSYNC; }
280         |
281         ASYNC           { $$ = HAST_REPLICATION_ASYNC; }
282         ;
283
284 node_statement:         ON node_start OB node_entries CB
285         {
286                 mynode = false;
287         }
288         ;
289
290 node_start:     STR
291         {
292                 if (isitme($1))
293                         mynode = true;
294         }
295         ;
296
297 node_entries:
298         |
299         node_entries node_entry
300         ;
301
302 node_entry:
303         control_statement
304         |
305         listen_statement
306         ;
307
308 resource_statement:     RESOURCE resource_start OB resource_entries CB
309         {
310                 if (curres != NULL) {
311                         /*
312                          * Let's see there are some resource-level settings
313                          * that we can use for node-level settings.
314                          */
315                         if (curres->hr_provname[0] == '\0' &&
316                             depth1_provname[0] != '\0') {
317                                 /*
318                                  * Provider name is not set at node-level,
319                                  * but is set at resource-level, use it.
320                                  */
321                                 strlcpy(curres->hr_provname, depth1_provname,
322                                     sizeof(curres->hr_provname));
323                         }
324                         if (curres->hr_localpath[0] == '\0' &&
325                             depth1_localpath[0] != '\0') {
326                                 /*
327                                  * Path to local provider is not set at
328                                  * node-level, but is set at resource-level,
329                                  * use it.
330                                  */
331                                 strlcpy(curres->hr_localpath, depth1_localpath,
332                                     sizeof(curres->hr_localpath));
333                         }
334
335                         /*
336                          * If provider name is not given, use resource name
337                          * as provider name.
338                          */
339                         if (curres->hr_provname[0] == '\0') {
340                                 strlcpy(curres->hr_provname, curres->hr_name,
341                                     sizeof(curres->hr_provname));
342                         }
343
344                         /*
345                          * Remote address has to be configured at this point.
346                          */
347                         if (curres->hr_remoteaddr[0] == '\0') {
348                                 errx(EX_CONFIG,
349                                     "remote address not configured for resource %s",
350                                     curres->hr_name);
351                         }
352                         /*
353                          * Path to local provider has to be configured at this
354                          * point.
355                          */
356                         if (curres->hr_localpath[0] == '\0') {
357                                 errx(EX_CONFIG,
358                                     "path local component not configured for resource %s",
359                                     curres->hr_name);
360                         }
361
362                         /* Put it onto resource list. */
363                         TAILQ_INSERT_TAIL(&lconfig.hc_resources, curres, hr_next);
364                         curres = NULL;
365                 }
366         }
367         ;
368
369 resource_start: STR
370         {
371                 /*
372                  * Clear those, so we can tell if they were set at
373                  * resource-level or not.
374                  */
375                 depth1_provname[0] = '\0';
376                 depth1_localpath[0] = '\0';
377
378                 curres = calloc(1, sizeof(*curres));
379                 if (curres == NULL) {
380                         errx(EX_TEMPFAIL,
381                             "cannot allocate memory for resource");
382                 }
383                 if (strlcpy(curres->hr_name, $1,
384                     sizeof(curres->hr_name)) >=
385                     sizeof(curres->hr_name)) {
386                         errx(EX_CONFIG,
387                             "resource name (%s) too long", $1);
388                 }
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;
397         }
398         ;
399
400 resource_entries:
401         |
402         resource_entries resource_entry
403         ;
404
405 resource_entry:
406         replication_statement
407         |
408         name_statement
409         |
410         local_statement
411         |
412         resource_node_statement
413         ;
414
415 name_statement:         NAME STR
416         {
417                 switch (depth) {
418                 case 1:
419                         if (strlcpy(depth1_provname, $2,
420                             sizeof(depth1_provname)) >=
421                             sizeof(depth1_provname)) {
422                                 errx(EX_CONFIG, "name argument too long");
423                         }
424                         break;
425                 case 2:
426                         if (mynode) {
427                                 assert(curres != NULL);
428                                 if (strlcpy(curres->hr_provname, $2,
429                                     sizeof(curres->hr_provname)) >=
430                                     sizeof(curres->hr_provname)) {
431                                         errx(EX_CONFIG,
432                                             "name argument too long");
433                                 }
434                         }
435                         break;
436                 default:
437                         assert(!"name at wrong depth level");
438                 }
439         }
440         ;
441
442 local_statement:        LOCAL STR
443         {
444                 switch (depth) {
445                 case 1:
446                         if (strlcpy(depth1_localpath, $2,
447                             sizeof(depth1_localpath)) >=
448                             sizeof(depth1_localpath)) {
449                                 errx(EX_CONFIG, "local argument too long");
450                         }
451                         break;
452                 case 2:
453                         if (mynode) {
454                                 assert(curres != NULL);
455                                 if (strlcpy(curres->hr_localpath, $2,
456                                     sizeof(curres->hr_localpath)) >=
457                                     sizeof(curres->hr_localpath)) {
458                                         errx(EX_CONFIG,
459                                             "local argument too long");
460                                 }
461                         }
462                         break;
463                 default:
464                         assert(!"local at wrong depth level");
465                 }
466         }
467         ;
468
469 resource_node_statement:ON resource_node_start OB resource_node_entries CB
470         {
471                 mynode = false;
472         }
473         ;
474
475 resource_node_start:    STR
476         {
477                 if (curres != NULL && isitme($1))
478                         mynode = true;
479         }
480         ;
481
482 resource_node_entries:
483         |
484         resource_node_entries resource_node_entry
485         ;
486
487 resource_node_entry:
488         name_statement
489         |
490         local_statement
491         |
492         remote_statement
493         ;
494
495 remote_statement:       REMOTE STR
496         {
497                 assert(depth == 2);
498                 if (mynode) {
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");
504                         }
505                 }
506         }
507         ;