Prepare configuration parsing code to be called multiple times:

- Don't exit on errors if not requested.
- Don't keep configuration in global variable, but allocate memory for
  configuration.
- Call yyrestart() before yyparse() so that on error in configuration file
  we will start from the begining next time and not from the place we left of.

MFC after:	1 month
This commit is contained in:
Pawel Jakub Dawidek 2010-08-05 19:08:54 +00:00
parent a00829bb71
commit bbbb114cda
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=210883
3 changed files with 111 additions and 58 deletions

View File

@ -183,7 +183,7 @@ struct hast_resource {
TAILQ_ENTRY(hast_resource) hr_next; TAILQ_ENTRY(hast_resource) hr_next;
}; };
struct hastd_config *yy_config_parse(const char *config); struct hastd_config *yy_config_parse(const char *config, bool exitonerror);
void yy_config_free(struct hastd_config *config); void yy_config_free(struct hastd_config *config);
void yyerror(const char *); void yyerror(const char *);

View File

@ -493,7 +493,7 @@ main(int argc, char *argv[])
pjdlog_errno(LOG_WARNING, "Unable to open or create pidfile"); pjdlog_errno(LOG_WARNING, "Unable to open or create pidfile");
} }
cfg = yy_config_parse(cfgpath); cfg = yy_config_parse(cfgpath, true);
assert(cfg != NULL); assert(cfg != NULL);
signal(SIGHUP, sighandler); signal(SIGHUP, sighandler);

View File

@ -43,6 +43,8 @@
#include <sysexits.h> #include <sysexits.h>
#include <unistd.h> #include <unistd.h>
#include <pjdlog.h>
#include "hast.h" #include "hast.h"
extern int depth; extern int depth;
@ -51,7 +53,7 @@ extern int lineno;
extern FILE *yyin; extern FILE *yyin;
extern char *yytext; extern char *yytext;
static struct hastd_config lconfig; static struct hastd_config *lconfig;
static struct hast_resource *curres; static struct hast_resource *curres;
static bool mynode; static bool mynode;
@ -63,7 +65,9 @@ static int depth0_timeout;
static char depth1_provname[PATH_MAX]; static char depth1_provname[PATH_MAX];
static char depth1_localpath[PATH_MAX]; static char depth1_localpath[PATH_MAX];
static bool extern void yyrestart(FILE *);
static int
isitme(const char *name) isitme(const char *name)
{ {
char buf[MAXHOSTNAMELEN]; char buf[MAXHOSTNAMELEN];
@ -73,78 +77,101 @@ isitme(const char *name)
/* /*
* First check if the give name matches our full hostname. * First check if the give name matches our full hostname.
*/ */
if (gethostname(buf, sizeof(buf)) < 0) if (gethostname(buf, sizeof(buf)) < 0) {
err(EX_OSERR, "gethostname() failed"); pjdlog_errno(LOG_ERR, "gethostname() failed");
return (-1);
}
if (strcmp(buf, name) == 0) if (strcmp(buf, name) == 0)
return (true); return (1);
/* /*
* Now check if it matches first part of the host name. * Now check if it matches first part of the host name.
*/ */
pos = strchr(buf, '.'); pos = strchr(buf, '.');
if (pos != NULL && pos != buf && strncmp(buf, name, pos - buf) == 0) if (pos != NULL && pos != buf && strncmp(buf, name, pos - buf) == 0)
return (true); return (1);
/* /*
* At the end check if name is equal to our host's UUID. * At the end check if name is equal to our host's UUID.
*/ */
bufsize = sizeof(buf); bufsize = sizeof(buf);
if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) {
err(EX_OSERR, "sysctlbyname(kern.hostuuid) failed"); pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed");
return (-1);
}
if (strcasecmp(buf, name) == 0) if (strcasecmp(buf, name) == 0)
return (true); return (1);
/* /*
* Looks like this isn't about us. * Looks like this isn't about us.
*/ */
return (false); return (0);
} }
void void
yyerror(const char *str) yyerror(const char *str)
{ {
fprintf(stderr, "error at line %d near '%s': %s\n", pjdlog_error("Unable to parse configuration file at line %d near '%s': %s",
lineno, yytext, str); lineno, yytext, str);
} }
struct hastd_config * struct hastd_config *
yy_config_parse(const char *config) yy_config_parse(const char *config, bool exitonerror)
{ {
int ret; int ret;
curres = NULL; curres = NULL;
mynode = false; mynode = false;
depth = 0;
lineno = 0;
depth0_timeout = HAST_TIMEOUT; depth0_timeout = HAST_TIMEOUT;
depth0_replication = HAST_REPLICATION_MEMSYNC; depth0_replication = HAST_REPLICATION_MEMSYNC;
strlcpy(depth0_control, HAST_CONTROL, sizeof(depth0_control)); strlcpy(depth0_control, HAST_CONTROL, sizeof(depth0_control));
strlcpy(depth0_listen, HASTD_LISTEN, sizeof(depth0_listen)); strlcpy(depth0_listen, HASTD_LISTEN, sizeof(depth0_listen));
TAILQ_INIT(&lconfig.hc_resources); lconfig = calloc(1, sizeof(*lconfig));
if (lconfig == NULL) {
pjdlog_error("Unable to allocate memory for configuration.");
if (exitonerror)
exit(EX_TEMPFAIL);
return (NULL);
}
TAILQ_INIT(&lconfig->hc_resources);
yyin = fopen(config, "r"); yyin = fopen(config, "r");
if (yyin == NULL) if (yyin == NULL) {
err(EX_OSFILE, "cannot open configuration file %s", config); pjdlog_errno(LOG_ERR, "Unable to open configuration file %s",
config);
yy_config_free(lconfig);
if (exitonerror)
exit(EX_OSFILE);
return (NULL);
}
yyrestart(yyin);
ret = yyparse(); ret = yyparse();
fclose(yyin); fclose(yyin);
if (ret != 0) { if (ret != 0) {
yy_config_free(&lconfig); yy_config_free(lconfig);
exit(EX_CONFIG); if (exitonerror)
exit(EX_CONFIG);
return (NULL);
} }
/* /*
* Let's see if everything is set up. * Let's see if everything is set up.
*/ */
if (lconfig.hc_controladdr[0] == '\0') { if (lconfig->hc_controladdr[0] == '\0') {
strlcpy(lconfig.hc_controladdr, depth0_control, strlcpy(lconfig->hc_controladdr, depth0_control,
sizeof(lconfig.hc_controladdr)); sizeof(lconfig->hc_controladdr));
} }
if (lconfig.hc_listenaddr[0] == '\0') { if (lconfig->hc_listenaddr[0] == '\0') {
strlcpy(lconfig.hc_listenaddr, depth0_listen, strlcpy(lconfig->hc_listenaddr, depth0_listen,
sizeof(lconfig.hc_listenaddr)); sizeof(lconfig->hc_listenaddr));
} }
TAILQ_FOREACH(curres, &lconfig.hc_resources, hr_next) { TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) {
assert(curres->hr_provname[0] != '\0'); assert(curres->hr_provname[0] != '\0');
assert(curres->hr_localpath[0] != '\0'); assert(curres->hr_localpath[0] != '\0');
assert(curres->hr_remoteaddr[0] != '\0'); assert(curres->hr_remoteaddr[0] != '\0');
@ -165,7 +192,7 @@ yy_config_parse(const char *config)
} }
} }
return (&lconfig); return (lconfig);
} }
void void
@ -177,6 +204,7 @@ yy_config_free(struct hastd_config *config)
TAILQ_REMOVE(&config->hc_resources, res, hr_next); TAILQ_REMOVE(&config->hc_resources, res, hr_next);
free(res); free(res);
} }
free(config);
} }
%} %}
@ -223,16 +251,17 @@ control_statement: CONTROL STR
if (strlcpy(depth0_control, $2, if (strlcpy(depth0_control, $2,
sizeof(depth0_control)) >= sizeof(depth0_control)) >=
sizeof(depth0_control)) { sizeof(depth0_control)) {
errx(EX_CONFIG, "control argument too long"); pjdlog_error("control argument is too long.");
return (1);
} }
break; break;
case 1: case 1:
if (mynode) { if (mynode) {
if (strlcpy(lconfig.hc_controladdr, $2, if (strlcpy(lconfig->hc_controladdr, $2,
sizeof(lconfig.hc_controladdr)) >= sizeof(lconfig->hc_controladdr)) >=
sizeof(lconfig.hc_controladdr)) { sizeof(lconfig->hc_controladdr)) {
errx(EX_CONFIG, pjdlog_error("control argument is too long.");
"control argument too long"); return (1);
} }
} }
break; break;
@ -249,16 +278,17 @@ listen_statement: LISTEN STR
if (strlcpy(depth0_listen, $2, if (strlcpy(depth0_listen, $2,
sizeof(depth0_listen)) >= sizeof(depth0_listen)) >=
sizeof(depth0_listen)) { sizeof(depth0_listen)) {
errx(EX_CONFIG, "listen argument too long"); pjdlog_error("listen argument is too long.");
return (1);
} }
break; break;
case 1: case 1:
if (mynode) { if (mynode) {
if (strlcpy(lconfig.hc_listenaddr, $2, if (strlcpy(lconfig->hc_listenaddr, $2,
sizeof(lconfig.hc_listenaddr)) >= sizeof(lconfig->hc_listenaddr)) >=
sizeof(lconfig.hc_listenaddr)) { sizeof(lconfig->hc_listenaddr)) {
errx(EX_CONFIG, pjdlog_error("listen argument is too long.");
"listen argument too long"); return (1);
} }
} }
break; break;
@ -316,8 +346,17 @@ node_statement: ON node_start OB node_entries CB
node_start: STR node_start: STR
{ {
if (isitme($1)) switch (isitme($1)) {
case -1:
return (1);
case 0:
break;
case 1:
mynode = true; mynode = true;
break;
default:
assert(!"invalid isitme() return value");
}
} }
; ;
@ -372,22 +411,22 @@ resource_statement: RESOURCE resource_start OB resource_entries CB
* Remote address has to be configured at this point. * Remote address has to be configured at this point.
*/ */
if (curres->hr_remoteaddr[0] == '\0') { if (curres->hr_remoteaddr[0] == '\0') {
errx(EX_CONFIG, pjdlog_error("Remote address not configured for resource %s.",
"remote address not configured for resource %s",
curres->hr_name); curres->hr_name);
return (1);
} }
/* /*
* Path to local provider has to be configured at this * Path to local provider has to be configured at this
* point. * point.
*/ */
if (curres->hr_localpath[0] == '\0') { if (curres->hr_localpath[0] == '\0') {
errx(EX_CONFIG, pjdlog_error("Path to local component not configured for resource %s.",
"path local component not configured for resource %s",
curres->hr_name); curres->hr_name);
return (1);
} }
/* Put it onto resource list. */ /* Put it onto resource list. */
TAILQ_INSERT_TAIL(&lconfig.hc_resources, curres, hr_next); TAILQ_INSERT_TAIL(&lconfig->hc_resources, curres, hr_next);
curres = NULL; curres = NULL;
} }
} }
@ -404,14 +443,14 @@ resource_start: STR
curres = calloc(1, sizeof(*curres)); curres = calloc(1, sizeof(*curres));
if (curres == NULL) { if (curres == NULL) {
errx(EX_TEMPFAIL, pjdlog_error("Unable to allocate memory for resource.");
"cannot allocate memory for resource"); return (1);
} }
if (strlcpy(curres->hr_name, $1, if (strlcpy(curres->hr_name, $1,
sizeof(curres->hr_name)) >= sizeof(curres->hr_name)) >=
sizeof(curres->hr_name)) { sizeof(curres->hr_name)) {
errx(EX_CONFIG, pjdlog_error("Resource name is too long.");
"resource name (%s) too long", $1); return (1);
} }
curres->hr_role = HAST_ROLE_INIT; curres->hr_role = HAST_ROLE_INIT;
curres->hr_previous_role = HAST_ROLE_INIT; curres->hr_previous_role = HAST_ROLE_INIT;
@ -449,7 +488,8 @@ name_statement: NAME STR
if (strlcpy(depth1_provname, $2, if (strlcpy(depth1_provname, $2,
sizeof(depth1_provname)) >= sizeof(depth1_provname)) >=
sizeof(depth1_provname)) { sizeof(depth1_provname)) {
errx(EX_CONFIG, "name argument too long"); pjdlog_error("name argument is too long.");
return (1);
} }
break; break;
case 2: case 2:
@ -458,8 +498,8 @@ name_statement: NAME STR
if (strlcpy(curres->hr_provname, $2, if (strlcpy(curres->hr_provname, $2,
sizeof(curres->hr_provname)) >= sizeof(curres->hr_provname)) >=
sizeof(curres->hr_provname)) { sizeof(curres->hr_provname)) {
errx(EX_CONFIG, pjdlog_error("name argument is too long.");
"name argument too long"); return (1);
} }
} }
break; break;
@ -476,7 +516,8 @@ local_statement: LOCAL STR
if (strlcpy(depth1_localpath, $2, if (strlcpy(depth1_localpath, $2,
sizeof(depth1_localpath)) >= sizeof(depth1_localpath)) >=
sizeof(depth1_localpath)) { sizeof(depth1_localpath)) {
errx(EX_CONFIG, "local argument too long"); pjdlog_error("local argument is too long.");
return (1);
} }
break; break;
case 2: case 2:
@ -485,8 +526,8 @@ local_statement: LOCAL STR
if (strlcpy(curres->hr_localpath, $2, if (strlcpy(curres->hr_localpath, $2,
sizeof(curres->hr_localpath)) >= sizeof(curres->hr_localpath)) >=
sizeof(curres->hr_localpath)) { sizeof(curres->hr_localpath)) {
errx(EX_CONFIG, pjdlog_error("local argument is too long.");
"local argument too long"); return (1);
} }
} }
break; break;
@ -504,8 +545,19 @@ resource_node_statement:ON resource_node_start OB resource_node_entries CB
resource_node_start: STR resource_node_start: STR
{ {
if (curres != NULL && isitme($1)) if (curres != NULL) {
mynode = true; switch (isitme($1)) {
case -1:
return (1);
case 0:
break;
case 1:
mynode = true;
break;
default:
assert(!"invalid isitme() return value");
}
}
} }
; ;
@ -530,7 +582,8 @@ remote_statement: REMOTE STR
if (strlcpy(curres->hr_remoteaddr, $2, if (strlcpy(curres->hr_remoteaddr, $2,
sizeof(curres->hr_remoteaddr)) >= sizeof(curres->hr_remoteaddr)) >=
sizeof(curres->hr_remoteaddr)) { sizeof(curres->hr_remoteaddr)) {
errx(EX_CONFIG, "remote argument too long"); pjdlog_error("remote argument is too long.");
return (1);
} }
} }
} }