1%{
2/*-
3 * Copyright (c) 2009-2010 The FreeBSD Foundation
4 * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>
5 * All rights reserved.
6 *
7 * This software was developed by Pawel Jakub Dawidek under sponsorship from
8 * the FreeBSD Foundation.
--- 14 unchanged lines hidden (view full) ---
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * $FreeBSD: head/sbin/hastd/parse.y 230976 2012-02-04 07:59:12Z pjd $
32 */
33
34#include <sys/param.h> /* MAXHOSTNAMELEN */
35#include <sys/queue.h>
36#include <sys/socket.h>
37#include <sys/sysctl.h>
38
39#include <arpa/inet.h>
--- 32 unchanged lines hidden (view full) ---
72static int depth0_metaflush;
73
74static char depth1_provname[PATH_MAX];
75static char depth1_localpath[PATH_MAX];
76static int depth1_metaflush;
77
78extern void yyrestart(FILE *);
79
80static int
81isitme(const char *name)
82{
83 char buf[MAXHOSTNAMELEN];
84 char *pos;
85 size_t bufsize;
86
87 /*
88 * First check if the given name matches our full hostname.
89 */
90 if (gethostname(buf, sizeof(buf)) < 0) {
91 pjdlog_errno(LOG_ERR, "gethostname() failed");
92 return (-1);
93 }
94 if (strcmp(buf, name) == 0)
95 return (1);
96
97 /*
98 * Now check if it matches first part of the host name.
99 */
100 pos = strchr(buf, '.');
101 if (pos != NULL && (size_t)(pos - buf) == strlen(name) &&
102 strncmp(buf, name, pos - buf) == 0) {
103 return (1);
104 }
105
106 /*
107 * At the end check if name is equal to our host's UUID.
108 */
109 bufsize = sizeof(buf);
110 if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) {
111 pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed");
112 return (-1);
113 }
114 if (strcasecmp(buf, name) == 0)
115 return (1);
116
117 /*
118 * Looks like this isn't about us.
119 */
120 return (0);
121}
122
123static bool
124family_supported(int family)
125{
126 int sock;
127
128 sock = socket(family, SOCK_STREAM, 0);
129 if (sock == -1 && errno == EPROTONOSUPPORT)
130 return (false);
131 if (sock >= 0)
132 (void)close(sock);
133 return (true);
134}
135
136static int
137node_names(char **namesp)
138{
139 static char names[MAXHOSTNAMELEN * 3];
140 char buf[MAXHOSTNAMELEN];
141 char *pos;
142 size_t bufsize;
143
144 if (gethostname(buf, sizeof(buf)) < 0) {
145 pjdlog_errno(LOG_ERR, "gethostname() failed");
146 return (-1);
147 }
148
149 /* First component of the host name. */
150 pos = strchr(buf, '.');
151 if (pos != NULL && pos != buf) {
152 (void)strlcpy(names, buf, MIN((size_t)(pos - buf + 1),
153 sizeof(names)));
154 (void)strlcat(names, ", ", sizeof(names));
155 }
156
157 /* Full host name. */
158 (void)strlcat(names, buf, sizeof(names));
159 (void)strlcat(names, ", ", sizeof(names));
160
161 /* Host UUID. */
162 bufsize = sizeof(buf);
163 if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) {
164 pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed");
165 return (-1);
166 }
167 (void)strlcat(names, buf, sizeof(names));
168
169 *namesp = names;
170
171 return (0);
172}
173
174void
175yyerror(const char *str)
176{
177
178 pjdlog_error("Unable to parse configuration file at line %d near '%s': %s",
179 lineno, yytext, str);
180}
181
182struct hastd_config *
183yy_config_parse(const char *config, bool exitonerror)
184{
185 int ret;
186
187 curres = NULL;
188 mynode = false;
189 depth = 0;
190 lineno = 0;
191
192 depth0_timeout = HAST_TIMEOUT;
193 depth0_replication = HAST_REPLICATION_FULLSYNC;
194 depth0_checksum = HAST_CHECKSUM_NONE;
195 depth0_compression = HAST_COMPRESSION_HOLE;
196 strlcpy(depth0_control, HAST_CONTROL, sizeof(depth0_control));
197 strlcpy(depth0_pidfile, HASTD_PIDFILE, sizeof(depth0_pidfile));
198 TAILQ_INIT(&depth0_listen);
199 strlcpy(depth0_listen_tcp4, HASTD_LISTEN_TCP4,
200 sizeof(depth0_listen_tcp4));
201 strlcpy(depth0_listen_tcp6, HASTD_LISTEN_TCP6,
202 sizeof(depth0_listen_tcp6));
203 depth0_exec[0] = '\0';
204 depth0_metaflush = 1;
205
206 lconfig = calloc(1, sizeof(*lconfig));
207 if (lconfig == NULL) {
208 pjdlog_error("Unable to allocate memory for configuration.");
209 if (exitonerror)
210 exit(EX_TEMPFAIL);
211 return (NULL);
212 }
213
214 TAILQ_INIT(&lconfig->hc_listen);
215 TAILQ_INIT(&lconfig->hc_resources);
216
217 yyin = fopen(config, "r");
218 if (yyin == NULL) {
219 pjdlog_errno(LOG_ERR, "Unable to open configuration file %s",
220 config);
221 yy_config_free(lconfig);
222 if (exitonerror)
223 exit(EX_OSFILE);
224 return (NULL);
225 }
226 yyrestart(yyin);
227 ret = yyparse();
228 fclose(yyin);
229 if (ret != 0) {
230 yy_config_free(lconfig);
231 if (exitonerror)
232 exit(EX_CONFIG);
233 return (NULL);
234 }
235
236 /*
237 * Let's see if everything is set up.
238 */
239 if (lconfig->hc_controladdr[0] == '\0') {
240 strlcpy(lconfig->hc_controladdr, depth0_control,
241 sizeof(lconfig->hc_controladdr));
242 }
243 if (lconfig->hc_pidfile[0] == '\0') {
244 strlcpy(lconfig->hc_pidfile, depth0_pidfile,
245 sizeof(lconfig->hc_pidfile));
246 }
247 if (!TAILQ_EMPTY(&depth0_listen))
248 TAILQ_CONCAT(&lconfig->hc_listen, &depth0_listen, hl_next);
249 if (TAILQ_EMPTY(&lconfig->hc_listen)) {
250 struct hastd_listen *lst;
251
252 if (family_supported(AF_INET)) {
253 lst = calloc(1, sizeof(*lst));
254 if (lst == NULL) {
255 pjdlog_error("Unable to allocate memory for listen address.");
256 yy_config_free(lconfig);
257 if (exitonerror)
258 exit(EX_TEMPFAIL);
259 return (NULL);
260 }
261 (void)strlcpy(lst->hl_addr, depth0_listen_tcp4,
262 sizeof(lst->hl_addr));
263 TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next);
264 } else {
265 pjdlog_debug(1,
266 "No IPv4 support in the kernel, not listening on IPv4 address.");
267 }
268 if (family_supported(AF_INET6)) {
269 lst = calloc(1, sizeof(*lst));
270 if (lst == NULL) {
271 pjdlog_error("Unable to allocate memory for listen address.");
272 yy_config_free(lconfig);
273 if (exitonerror)
274 exit(EX_TEMPFAIL);
275 return (NULL);
276 }
277 (void)strlcpy(lst->hl_addr, depth0_listen_tcp6,
278 sizeof(lst->hl_addr));
279 TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next);
280 } else {
281 pjdlog_debug(1,
282 "No IPv6 support in the kernel, not listening on IPv6 address.");
283 }
284 if (TAILQ_EMPTY(&lconfig->hc_listen)) {
285 pjdlog_error("No address to listen on.");
286 yy_config_free(lconfig);
287 if (exitonerror)
288 exit(EX_TEMPFAIL);
289 return (NULL);
290 }
291 }
292 TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) {
293 PJDLOG_ASSERT(curres->hr_provname[0] != '\0');
294 PJDLOG_ASSERT(curres->hr_localpath[0] != '\0');
295 PJDLOG_ASSERT(curres->hr_remoteaddr[0] != '\0');
296
297 if (curres->hr_replication == -1) {
298 /*
299 * Replication is not set at resource-level.
300 * Use global or default setting.
301 */
302 curres->hr_replication = depth0_replication;
303 }
304 if (curres->hr_replication == HAST_REPLICATION_MEMSYNC) {
305 pjdlog_warning("Replication mode \"%s\" is not implemented, falling back to \"%s\".",
306 "memsync", "fullsync");
307 curres->hr_replication = HAST_REPLICATION_FULLSYNC;
308 }
309 if (curres->hr_checksum == -1) {
310 /*
311 * Checksum is not set at resource-level.
312 * Use global or default setting.
313 */
314 curres->hr_checksum = depth0_checksum;
315 }
316 if (curres->hr_compression == -1) {
317 /*
318 * Compression is not set at resource-level.
319 * Use global or default setting.
320 */
321 curres->hr_compression = depth0_compression;
322 }
323 if (curres->hr_timeout == -1) {
324 /*
325 * Timeout is not set at resource-level.
326 * Use global or default setting.
327 */
328 curres->hr_timeout = depth0_timeout;
329 }
330 if (curres->hr_exec[0] == '\0') {
331 /*
332 * Exec is not set at resource-level.
333 * Use global or default setting.
334 */
335 strlcpy(curres->hr_exec, depth0_exec,
336 sizeof(curres->hr_exec));
337 }
338 if (curres->hr_metaflush == -1) {
339 /*
340 * Metaflush is not set at resource-level.
341 * Use global or default setting.
342 */
343 curres->hr_metaflush = depth0_metaflush;
344 }
345 }
346
347 return (lconfig);
348}
349
350void
351yy_config_free(struct hastd_config *config)
352{
353 struct hastd_listen *lst;
354 struct hast_resource *res;
355
356 while ((lst = TAILQ_FIRST(&depth0_listen)) != NULL) {
357 TAILQ_REMOVE(&depth0_listen, lst, hl_next);
358 free(lst);
359 }
360 while ((lst = TAILQ_FIRST(&config->hc_listen)) != NULL) {
361 TAILQ_REMOVE(&config->hc_listen, lst, hl_next);
362 free(lst);
363 }
364 while ((res = TAILQ_FIRST(&config->hc_resources)) != NULL) {
365 TAILQ_REMOVE(&config->hc_resources, res, hr_next);
366 free(res);
367 }
368 free(config);
369}
370%}
371
372%token CONTROL PIDFILE LISTEN REPLICATION CHECKSUM COMPRESSION METAFLUSH
373%token TIMEOUT EXEC RESOURCE NAME LOCAL REMOTE SOURCE ON OFF
374%token FULLSYNC MEMSYNC ASYNC NONE CRC32 SHA256 HOLE LZF
375%token NUM STR OB CB
376
377%type <str> remote_str
--- 621 unchanged lines hidden (view full) ---
999 pjdlog_error("source argument is too long.");
1000 free($2);
1001 return (1);
1002 }
1003 }
1004 free($2);
1005 }
1006 ;
2/*-
3 * Copyright (c) 2009-2010 The FreeBSD Foundation
4 * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>
5 * All rights reserved.
6 *
7 * This software was developed by Pawel Jakub Dawidek under sponsorship from
8 * the FreeBSD Foundation.
--- 14 unchanged lines hidden (view full) ---
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * $FreeBSD: head/sbin/hastd/parse.y 230976 2012-02-04 07:59:12Z pjd $
32 */
33
34#include <sys/param.h> /* MAXHOSTNAMELEN */
35#include <sys/queue.h>
36#include <sys/socket.h>
37#include <sys/sysctl.h>
38
39#include <arpa/inet.h>
--- 32 unchanged lines hidden (view full) ---
72static int depth0_metaflush;
73
74static char depth1_provname[PATH_MAX];
75static char depth1_localpath[PATH_MAX];
76static int depth1_metaflush;
77
78extern void yyrestart(FILE *);
79
80static int
81isitme(const char *name)
82{
83 char buf[MAXHOSTNAMELEN];
84 char *pos;
85 size_t bufsize;
86
87 /*
88 * First check if the given name matches our full hostname.
89 */
90 if (gethostname(buf, sizeof(buf)) < 0) {
91 pjdlog_errno(LOG_ERR, "gethostname() failed");
92 return (-1);
93 }
94 if (strcmp(buf, name) == 0)
95 return (1);
96
97 /*
98 * Now check if it matches first part of the host name.
99 */
100 pos = strchr(buf, '.');
101 if (pos != NULL && (size_t)(pos - buf) == strlen(name) &&
102 strncmp(buf, name, pos - buf) == 0) {
103 return (1);
104 }
105
106 /*
107 * At the end check if name is equal to our host's UUID.
108 */
109 bufsize = sizeof(buf);
110 if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) {
111 pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed");
112 return (-1);
113 }
114 if (strcasecmp(buf, name) == 0)
115 return (1);
116
117 /*
118 * Looks like this isn't about us.
119 */
120 return (0);
121}
122
123static bool
124family_supported(int family)
125{
126 int sock;
127
128 sock = socket(family, SOCK_STREAM, 0);
129 if (sock == -1 && errno == EPROTONOSUPPORT)
130 return (false);
131 if (sock >= 0)
132 (void)close(sock);
133 return (true);
134}
135
136static int
137node_names(char **namesp)
138{
139 static char names[MAXHOSTNAMELEN * 3];
140 char buf[MAXHOSTNAMELEN];
141 char *pos;
142 size_t bufsize;
143
144 if (gethostname(buf, sizeof(buf)) < 0) {
145 pjdlog_errno(LOG_ERR, "gethostname() failed");
146 return (-1);
147 }
148
149 /* First component of the host name. */
150 pos = strchr(buf, '.');
151 if (pos != NULL && pos != buf) {
152 (void)strlcpy(names, buf, MIN((size_t)(pos - buf + 1),
153 sizeof(names)));
154 (void)strlcat(names, ", ", sizeof(names));
155 }
156
157 /* Full host name. */
158 (void)strlcat(names, buf, sizeof(names));
159 (void)strlcat(names, ", ", sizeof(names));
160
161 /* Host UUID. */
162 bufsize = sizeof(buf);
163 if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) {
164 pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed");
165 return (-1);
166 }
167 (void)strlcat(names, buf, sizeof(names));
168
169 *namesp = names;
170
171 return (0);
172}
173
174void
175yyerror(const char *str)
176{
177
178 pjdlog_error("Unable to parse configuration file at line %d near '%s': %s",
179 lineno, yytext, str);
180}
181
182struct hastd_config *
183yy_config_parse(const char *config, bool exitonerror)
184{
185 int ret;
186
187 curres = NULL;
188 mynode = false;
189 depth = 0;
190 lineno = 0;
191
192 depth0_timeout = HAST_TIMEOUT;
193 depth0_replication = HAST_REPLICATION_FULLSYNC;
194 depth0_checksum = HAST_CHECKSUM_NONE;
195 depth0_compression = HAST_COMPRESSION_HOLE;
196 strlcpy(depth0_control, HAST_CONTROL, sizeof(depth0_control));
197 strlcpy(depth0_pidfile, HASTD_PIDFILE, sizeof(depth0_pidfile));
198 TAILQ_INIT(&depth0_listen);
199 strlcpy(depth0_listen_tcp4, HASTD_LISTEN_TCP4,
200 sizeof(depth0_listen_tcp4));
201 strlcpy(depth0_listen_tcp6, HASTD_LISTEN_TCP6,
202 sizeof(depth0_listen_tcp6));
203 depth0_exec[0] = '\0';
204 depth0_metaflush = 1;
205
206 lconfig = calloc(1, sizeof(*lconfig));
207 if (lconfig == NULL) {
208 pjdlog_error("Unable to allocate memory for configuration.");
209 if (exitonerror)
210 exit(EX_TEMPFAIL);
211 return (NULL);
212 }
213
214 TAILQ_INIT(&lconfig->hc_listen);
215 TAILQ_INIT(&lconfig->hc_resources);
216
217 yyin = fopen(config, "r");
218 if (yyin == NULL) {
219 pjdlog_errno(LOG_ERR, "Unable to open configuration file %s",
220 config);
221 yy_config_free(lconfig);
222 if (exitonerror)
223 exit(EX_OSFILE);
224 return (NULL);
225 }
226 yyrestart(yyin);
227 ret = yyparse();
228 fclose(yyin);
229 if (ret != 0) {
230 yy_config_free(lconfig);
231 if (exitonerror)
232 exit(EX_CONFIG);
233 return (NULL);
234 }
235
236 /*
237 * Let's see if everything is set up.
238 */
239 if (lconfig->hc_controladdr[0] == '\0') {
240 strlcpy(lconfig->hc_controladdr, depth0_control,
241 sizeof(lconfig->hc_controladdr));
242 }
243 if (lconfig->hc_pidfile[0] == '\0') {
244 strlcpy(lconfig->hc_pidfile, depth0_pidfile,
245 sizeof(lconfig->hc_pidfile));
246 }
247 if (!TAILQ_EMPTY(&depth0_listen))
248 TAILQ_CONCAT(&lconfig->hc_listen, &depth0_listen, hl_next);
249 if (TAILQ_EMPTY(&lconfig->hc_listen)) {
250 struct hastd_listen *lst;
251
252 if (family_supported(AF_INET)) {
253 lst = calloc(1, sizeof(*lst));
254 if (lst == NULL) {
255 pjdlog_error("Unable to allocate memory for listen address.");
256 yy_config_free(lconfig);
257 if (exitonerror)
258 exit(EX_TEMPFAIL);
259 return (NULL);
260 }
261 (void)strlcpy(lst->hl_addr, depth0_listen_tcp4,
262 sizeof(lst->hl_addr));
263 TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next);
264 } else {
265 pjdlog_debug(1,
266 "No IPv4 support in the kernel, not listening on IPv4 address.");
267 }
268 if (family_supported(AF_INET6)) {
269 lst = calloc(1, sizeof(*lst));
270 if (lst == NULL) {
271 pjdlog_error("Unable to allocate memory for listen address.");
272 yy_config_free(lconfig);
273 if (exitonerror)
274 exit(EX_TEMPFAIL);
275 return (NULL);
276 }
277 (void)strlcpy(lst->hl_addr, depth0_listen_tcp6,
278 sizeof(lst->hl_addr));
279 TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next);
280 } else {
281 pjdlog_debug(1,
282 "No IPv6 support in the kernel, not listening on IPv6 address.");
283 }
284 if (TAILQ_EMPTY(&lconfig->hc_listen)) {
285 pjdlog_error("No address to listen on.");
286 yy_config_free(lconfig);
287 if (exitonerror)
288 exit(EX_TEMPFAIL);
289 return (NULL);
290 }
291 }
292 TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) {
293 PJDLOG_ASSERT(curres->hr_provname[0] != '\0');
294 PJDLOG_ASSERT(curres->hr_localpath[0] != '\0');
295 PJDLOG_ASSERT(curres->hr_remoteaddr[0] != '\0');
296
297 if (curres->hr_replication == -1) {
298 /*
299 * Replication is not set at resource-level.
300 * Use global or default setting.
301 */
302 curres->hr_replication = depth0_replication;
303 }
304 if (curres->hr_replication == HAST_REPLICATION_MEMSYNC) {
305 pjdlog_warning("Replication mode \"%s\" is not implemented, falling back to \"%s\".",
306 "memsync", "fullsync");
307 curres->hr_replication = HAST_REPLICATION_FULLSYNC;
308 }
309 if (curres->hr_checksum == -1) {
310 /*
311 * Checksum is not set at resource-level.
312 * Use global or default setting.
313 */
314 curres->hr_checksum = depth0_checksum;
315 }
316 if (curres->hr_compression == -1) {
317 /*
318 * Compression is not set at resource-level.
319 * Use global or default setting.
320 */
321 curres->hr_compression = depth0_compression;
322 }
323 if (curres->hr_timeout == -1) {
324 /*
325 * Timeout is not set at resource-level.
326 * Use global or default setting.
327 */
328 curres->hr_timeout = depth0_timeout;
329 }
330 if (curres->hr_exec[0] == '\0') {
331 /*
332 * Exec is not set at resource-level.
333 * Use global or default setting.
334 */
335 strlcpy(curres->hr_exec, depth0_exec,
336 sizeof(curres->hr_exec));
337 }
338 if (curres->hr_metaflush == -1) {
339 /*
340 * Metaflush is not set at resource-level.
341 * Use global or default setting.
342 */
343 curres->hr_metaflush = depth0_metaflush;
344 }
345 }
346
347 return (lconfig);
348}
349
350void
351yy_config_free(struct hastd_config *config)
352{
353 struct hastd_listen *lst;
354 struct hast_resource *res;
355
356 while ((lst = TAILQ_FIRST(&depth0_listen)) != NULL) {
357 TAILQ_REMOVE(&depth0_listen, lst, hl_next);
358 free(lst);
359 }
360 while ((lst = TAILQ_FIRST(&config->hc_listen)) != NULL) {
361 TAILQ_REMOVE(&config->hc_listen, lst, hl_next);
362 free(lst);
363 }
364 while ((res = TAILQ_FIRST(&config->hc_resources)) != NULL) {
365 TAILQ_REMOVE(&config->hc_resources, res, hr_next);
366 free(res);
367 }
368 free(config);
369}
370%}
371
372%token CONTROL PIDFILE LISTEN REPLICATION CHECKSUM COMPRESSION METAFLUSH
373%token TIMEOUT EXEC RESOURCE NAME LOCAL REMOTE SOURCE ON OFF
374%token FULLSYNC MEMSYNC ASYNC NONE CRC32 SHA256 HOLE LZF
375%token NUM STR OB CB
376
377%type <str> remote_str
--- 621 unchanged lines hidden (view full) ---
999 pjdlog_error("source argument is too long.");
1000 free($2);
1001 return (1);
1002 }
1003 }
1004 free($2);
1005 }
1006 ;