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