int settings_parse(JsonNode *root) { int have_error = 0; #ifdef WEBSERVER int web_port = 0; int own_port = 0; char *webgui_tpl = malloc(strlen(WEBGUI_TEMPLATE)+1); if(!webgui_tpl) { logprintf(LOG_ERR, "out of memory"); exit(EXIT_FAILURE); } strcpy(webgui_tpl, WEBGUI_TEMPLATE); char *webgui_root = malloc(strlen(WEBSERVER_ROOT)+1); if(!webgui_root) { logprintf(LOG_ERR, "out of memory"); exit(EXIT_FAILURE); } strcpy(webgui_root, WEBSERVER_ROOT); #endif #ifndef __FreeBSD__ regex_t regex; int reti; #endif JsonNode *jsettings = json_first_child(root); while(jsettings) { if(strcmp(jsettings->key, "port") == 0 || strcmp(jsettings->key, "send-repeats") == 0 || strcmp(jsettings->key, "receive-repeats") == 0) { if((int)jsettings->number_ == 0) { logprintf(LOG_ERR, "setting \"%s\" must contain a number larger than 0", jsettings->key); have_error = 1; goto clear; } else { #ifdef WEBSERVER if(strcmp(jsettings->key, "port") == 0) { own_port = (int)jsettings->number_; } #endif settings_add_number(jsettings->key, (int)jsettings->number_); } } else if(strcmp(jsettings->key, "standalone") == 0) { if(jsettings->number_ < 0 || jsettings->number_ > 1) { logprintf(LOG_ERR, "setting \"%s\" must be either 0 or 1", jsettings->key); have_error = 1; goto clear; } else { settings_add_number(jsettings->key, (int)jsettings->number_); } } else if(strcmp(jsettings->key, "firmware-update") == 0) { if(jsettings->number_ < 0 || jsettings->number_ > 1) { logprintf(LOG_ERR, "setting \"%s\" must be either 0 or 1", jsettings->key); have_error = 1; goto clear; } else { settings_add_number(jsettings->key, (int)jsettings->number_); } } else if(strcmp(jsettings->key, "log-level") == 0) { if((int)jsettings->number_ < 0 || (int)jsettings->number_ > 5) { logprintf(LOG_ERR, "setting \"%s\" must contain a number from 0 till 5", jsettings->key); have_error = 1; goto clear; } else { settings_add_number(jsettings->key, (int)jsettings->number_); } } else if(strcmp(jsettings->key, "pid-file") == 0 || strcmp(jsettings->key, "log-file") == 0) { if(!jsettings->string_) { logprintf(LOG_ERR, "setting \"%s\" must contain an existing file path", jsettings->key); have_error = 1; goto clear; } else { if(path_exists(jsettings->string_) != EXIT_SUCCESS) { logprintf(LOG_ERR, "setting \"%s\" must point to an existing folder", jsettings->key); have_error = 1; goto clear; } else { settings_add_string(jsettings->key, jsettings->string_); } } } else if(strcmp(jsettings->key, "config-file") == 0 || strcmp(jsettings->key, "hardware-file") == 0) { if(!jsettings->string_) { logprintf(LOG_ERR, "setting \"%s\" must contain an existing file path", jsettings->key); have_error = 1; goto clear; } else if(strlen(jsettings->string_) > 0) { if(settings_file_exists(jsettings->string_) == EXIT_SUCCESS) { settings_add_string(jsettings->key, jsettings->string_); } else { logprintf(LOG_ERR, "setting \"%s\" must point to an existing file", jsettings->key); have_error = 1; goto clear; } } } else if(strcmp(jsettings->key, "whitelist") == 0) { if(!jsettings->string_) { logprintf(LOG_ERR, "setting \"%s\" must contain valid ip addresses", jsettings->key); have_error = 1; goto clear; } else if(strlen(jsettings->string_) > 0) { #ifndef __FreeBSD__ char validate[] = "^((\\*|[0-9]|[1-9][0-9]|1[0-9][0-9]|2([0-4][0-9]|5[0-5]))\\.(\\*|[0-9]|[1-9][0-9]|1[0-9][0-9]|2([0-4][0-9]|5[0-5]))\\.(\\*|[0-9]|[1-9][0-9]|1[0-9][0-9]|2([0-4][0-9]|5[0-5]))\\.(\\*|[0-9]|[1-9][0-9]|1[0-9][0-9]|2([0-4][0-9]|5[0-5]))(,[\\ ]|,|$))+$"; reti = regcomp(®ex, validate, REG_EXTENDED); if(reti) { logprintf(LOG_ERR, "could not compile regex"); have_error = 1; goto clear; } reti = regexec(®ex, jsettings->string_, 0, NULL, 0); if(reti == REG_NOMATCH || reti != 0) { logprintf(LOG_ERR, "setting \"%s\" must contain valid ip addresses", jsettings->key); have_error = 1; regfree(®ex); goto clear; } regfree(®ex); #endif int l = (int)strlen(jsettings->string_)-1; if(jsettings->string_[l] == ' ' || jsettings->string_[l] == ',') { logprintf(LOG_ERR, "setting \"%s\" must contain valid ip addresses", jsettings->key); have_error = 1; goto clear; } settings_add_string(jsettings->key, jsettings->string_); } #ifdef WEBSERVER } else if(strcmp(jsettings->key, "webserver-port") == 0) { if(jsettings->number_ < 0) { logprintf(LOG_ERR, "setting \"%s\" must contain a number larger than 0", jsettings->key); have_error = 1; goto clear; } else { web_port = (int)jsettings->number_; settings_add_number(jsettings->key, (int)jsettings->number_); } } else if(strcmp(jsettings->key, "webserver-root") == 0) { if(!jsettings->string_ || path_exists(jsettings->string_) != 0) { logprintf(LOG_ERR, "setting \"%s\" must contain a valid path", jsettings->key); have_error = 1; goto clear; } else { webgui_root = realloc(webgui_root, strlen(jsettings->string_)+1); if(!webgui_root) { logprintf(LOG_ERR, "out of memory"); exit(EXIT_FAILURE); } strcpy(webgui_root, jsettings->string_); settings_add_string(jsettings->key, jsettings->string_); } } else if(strcmp(jsettings->key, "webserver-enable") == 0) { if(jsettings->number_ < 0 || jsettings->number_ > 1) { logprintf(LOG_ERR, "setting \"%s\" must be either 0 or 1", jsettings->key); have_error = 1; goto clear; } else { settings_add_number(jsettings->key, (int)jsettings->number_); } } else if(strcmp(jsettings->key, "webserver-cache") == 0) { if(jsettings->number_ < 0 || jsettings->number_ > 1) { logprintf(LOG_ERR, "setting \"%s\" must be either 0 or 1", jsettings->key); have_error = 1; goto clear; } else { settings_add_number(jsettings->key, (int)jsettings->number_); } } else if(strcmp(jsettings->key, "webserver-user") == 0) { if(jsettings->string_ || strlen(jsettings->string_) > 0) { if(name2uid(jsettings->string_) == -1) { logprintf(LOG_ERR, "setting \"%s\" must contain a valid system user", jsettings->key); have_error = 1; goto clear; } else { settings_add_string(jsettings->key, jsettings->string_); } } } else if(strcmp(jsettings->key, "webserver-authentication") == 0 && jsettings->tag == JSON_ARRAY) { JsonNode *jtmp = json_first_child(jsettings); unsigned short i = 0; while(jtmp) { i++; if(jtmp->tag == JSON_STRING) { if(i == 1) { settings_add_string("webserver-authentication-username", jtmp->string_); } else if(i == 2) { settings_add_string("webserver-authentication-password", jtmp->string_); } } else { have_error = 1; break; } if(i > 2) { have_error = 1; break; } jtmp = jtmp->next; } if(i != 2 || have_error == 1) { logprintf(LOG_ERR, "setting \"%s\" must be in the format of [ \"username\", \"password\" ]", jsettings->key); have_error = 1; goto clear; } } else if(strcmp(jsettings->key, "webgui-template") == 0) { if(!jsettings->string_) { logprintf(LOG_ERR, "setting \"%s\" must be a valid template", jsettings->key); have_error = 1; goto clear; } else { webgui_tpl = realloc(webgui_tpl, strlen(jsettings->string_)+1); if(!webgui_tpl) { logprintf(LOG_ERR, "out of memory"); exit(EXIT_FAILURE); } strcpy(webgui_tpl, jsettings->string_); settings_add_string(jsettings->key, jsettings->string_); } #endif #ifdef UPDATE } else if(strcmp(jsettings->key, "update-check") == 0) { if(jsettings->number_ < 0 || jsettings->number_ > 1) { logprintf(LOG_ERR, "setting \"%s\" must be either 0 or 1", jsettings->key); have_error = 1; goto clear; } else { settings_add_number(jsettings->key, (int)jsettings->number_); } } else if(strcmp(jsettings->key, "update-development") == 0) { if(jsettings->number_ < 0 || jsettings->number_ > 1) { logprintf(LOG_ERR, "setting \"%s\" must be either 0 or 1", jsettings->key); have_error = 1; goto clear; } else { settings_add_number(jsettings->key, (int)jsettings->number_); } } else if(strcmp(jsettings->key, "update-mirror") == 0) { char *filename = NULL; char *url = NULL; char *data = NULL; int lg = 0; char typebuf[70]; if(jsettings->string_) { url = malloc(strlen(jsettings->string_)+1); if(!url) { logprintf(LOG_ERR, "out of memory"); exit(EXIT_FAILURE); } strcpy(url, jsettings->string_); http_parse_url(url, &filename); } if(!jsettings->string_ || http_get(filename, &data, &lg, typebuf) != 200) { logprintf(LOG_ERR, "setting \"%s\" must be point to a valid (online) file", jsettings->key); /* clean-up http_lib global */ if(http_server) sfree((void *)&http_server); if(filename) sfree((void *)&filename); if(url) sfree((void *)&url); if(data) sfree((void *)&data); have_error = 1; goto clear; } else { settings_add_string(jsettings->key, jsettings->string_); /* clean-up http_lib global */ if(http_server) sfree((void *)&http_server); if(filename) sfree((void *)&filename); if(url) sfree((void *)&url); if(data) sfree((void *)&data); } #endif } else { logprintf(LOG_ERR, "setting \"%s\" is invalid", jsettings->key); have_error = 1; goto clear; } jsettings = jsettings->next; } json_delete(jsettings); #ifdef WEBSERVER if(webgui_tpl) { char *tmp = malloc(strlen(webgui_root)+strlen(webgui_tpl)+13); if(!tmp) { logprintf(LOG_ERR, "out of memory"); exit(EXIT_FAILURE); } sprintf(tmp, "%s/%s/index.html", webgui_root, webgui_tpl); if(path_exists(tmp) != EXIT_SUCCESS) { logprintf(LOG_ERR, "setting \"webgui-template\", template does not exists"); have_error = 1; sfree((void *)&tmp); goto clear; } sfree((void *)&tmp); } if(web_port == own_port) { logprintf(LOG_ERR, "setting \"port\" and \"webserver-port\" cannot be the same"); have_error = 1; goto clear; } #endif clear: #ifdef WEBSERVER if(webgui_tpl) { sfree((void *)&webgui_tpl); } if(webgui_root) { sfree((void *)&webgui_root); } #endif return have_error; }
int settings_parse(JsonNode *root) { int have_error = 0; int is_node = 0; char *server_ip = NULL; int server_port = 0; int web_port = 0; int own_port = 0; int has_config = 0; int has_lirc = 0; int has_socket = 0; int gpio_in = -1; int gpio_out = -1; JsonNode *jsettings = json_first_child(root); while(jsettings) { if(strcmp(jsettings->key, "port") == 0 || strcmp(jsettings->key, "send-repeats") == 0 || strcmp(jsettings->key, "receive-repeats") == 0) { if((int)jsettings->number_ == 0) { logprintf(LOG_ERR, "setting \"%s\" must contain a number larger than 0", jsettings->key); have_error = 1; goto clear; } else { if(strcmp(jsettings->key, "port") == 0) { own_port = (int)jsettings->number_; } settings_add_number_node(jsettings->key, (int)jsettings->number_); } } else if(strcmp(jsettings->key, "mode") == 0) { if(jsettings->string_ == NULL) { logprintf(LOG_ERR, "setting \"%s\" must be \"server\" or \"client\"", jsettings->key); have_error = 1; goto clear; } else { if(strcmp(jsettings->string_, "client") == 0) { is_node = 1; } if(strcmp(jsettings->string_, "server") == 0 || strcmp(jsettings->string_, "client") == 0) { settings_add_string_node(jsettings->key, jsettings->string_); } else { logprintf(LOG_ERR, "setting \"%s\" must be \"server\" or \"client\"", jsettings->key); have_error = 1; goto clear; } } } else if(strcmp(jsettings->key, "log-level") == 0) { if((int)jsettings->number_ == 0 || (int)jsettings->number_ > 5) { logprintf(LOG_ERR, "setting \"%s\" must contain a number from 0 till 5", jsettings->key); have_error = 1; goto clear; } else { settings_add_number_node(jsettings->key, (int)jsettings->number_); } } else if(strcmp(jsettings->key, "pid-file") == 0 || strcmp(jsettings->key, "log-file") == 0) { if(jsettings->string_ == NULL) { logprintf(LOG_ERR, "setting \"%s\" must contain an existing file path", jsettings->key); have_error = 1; goto clear; } else { if(settings_path_exists(jsettings->string_) != 0) { logprintf(LOG_ERR, "setting \"%s\" must point to an existing folder", jsettings->key); have_error = 1; goto clear; } else { settings_add_string_node(jsettings->key, jsettings->string_); } } } else if(strcmp(jsettings->key, "config-file") == 0 || strcmp(jsettings->key, "process-file") == 0) { if(jsettings->string_ == NULL) { logprintf(LOG_ERR, "setting \"%s\" must contain an existing file path", jsettings->key); have_error = 1; goto clear; } else if(strlen(jsettings->string_) > 0) { if(settings_file_exists(jsettings->string_) == 0) { has_config = 1; settings_add_string_node(jsettings->key, jsettings->string_); } else { logprintf(LOG_ERR, "setting \"%s\" must point to an existing file", jsettings->key); have_error = 1; goto clear; } } } else if(strcmp(jsettings->key, "socket") == 0) { if(jsettings->string_ == NULL) { logprintf(LOG_ERR, "setting \"%s\" must point an existing socket", jsettings->key); have_error = 1; goto clear; } else { has_socket = 1; settings_add_string_node(jsettings->key, jsettings->string_); } } else if(strcmp(jsettings->key, "use-lirc") == 0) { if(jsettings->number_ < 0 || jsettings->number_ > 1) { logprintf(LOG_ERR, "setting \"%s\" must be either 0 or 1", jsettings->key); have_error = 1; goto clear; } else { if((int)jsettings->number_ == 1) { has_lirc = 1; } settings_add_number_node(jsettings->key, (int)jsettings->number_); } } else if(strcmp(jsettings->key, "webserver-port") == 0) { if(jsettings->number_ < 0) { logprintf(LOG_ERR, "setting \"%s\" must contain a number larger than 0", jsettings->key); have_error = 1; goto clear; } else { web_port = (int)jsettings->number_; settings_add_number_node(jsettings->key, (int)jsettings->number_); } } else if(strcmp(jsettings->key, "webserver-root") == 0) { if(jsettings->string_ == NULL) { logprintf(LOG_ERR, "setting \"%s\" must contain a valid path", jsettings->key); have_error = 1; goto clear; } else { settings_add_string_node(jsettings->key, jsettings->string_); } } else if(strcmp(jsettings->key, "webserver-enable") == 0) { if(jsettings->number_ < 0 || jsettings->number_ > 1) { logprintf(LOG_ERR, "setting \"%s\" must be either 0 or 1", jsettings->key); have_error = 1; goto clear; } else { settings_add_number_node(jsettings->key, (int)jsettings->number_); } } else if(strcmp(jsettings->key, "gpio-receiver") == 0) { if(jsettings->number_ < 0 || jsettings->number_ > 7) { logprintf(LOG_ERR, "setting \"%s\" must be between 0 and 7", jsettings->key); have_error = 1; goto clear; } else { gpio_out = (int)jsettings->number_; settings_add_number_node(jsettings->key, (int)jsettings->number_); } } else if(strcmp(jsettings->key, "gpio-sender") == 0) { if(jsettings->number_ < 0 || jsettings->number_ > 7) { logprintf(LOG_ERR, "setting \"%s\" must be between 0 and 7", jsettings->key); have_error = 1; goto clear; } else { gpio_in = (int)jsettings->number_; settings_add_number_node(jsettings->key, (int)jsettings->number_); } } else if(strcmp(jsettings->key, "server") == 0) { JsonNode *jserver = json_find_member(root, "server"); JsonNode *jtmp = json_first_child(jserver); int i = 0; while(jtmp != NULL) { i++; if(jtmp->tag == JSON_STRING) { server_ip = strdup(jtmp->string_); } else if(jtmp->tag == JSON_NUMBER) { server_port = (int)jtmp->number_; } if(i > 2) { i++; break; } jtmp = jtmp->next; } if(i > 2) { logprintf(LOG_ERR, "setting \"%s\" must be in the format of [ \"x.x.x.x\", xxxx ]", jsettings->key); have_error = 1; goto clear; } else if(server_ip != NULL && server_port > 0 && is_node == 1) { settings_add_string_node("server-ip", server_ip); settings_add_number_node("server-port", server_port); } else { logprintf(LOG_ERR, "setting \"%s\" must be in the format of [ \"x.x.x.x\", xxxx ]", jsettings->key); have_error = 1; goto clear; } } else { logprintf(LOG_ERR, "setting \"%s\" is invalid", jsettings->key); have_error = 1; goto clear; } jsettings = jsettings->next; } json_delete(jsettings); if(has_lirc == 1 && gpio_in > -1) { logprintf(LOG_ERR, "setting \"gpio-receiver\" and use-lirc cannot be combined"); have_error = 1; goto clear; } if(has_lirc == 1 && gpio_out > -1) { logprintf(LOG_ERR, "setting \"gpio-sender\" and use-lirc cannot be combined"); have_error = 1; goto clear; } if(has_lirc == 0 && has_socket == 1) { logprintf(LOG_ERR, "setting \"socket\" must be combined with use-lirc"); have_error = 1; goto clear; } if(server_port > 0 && server_port == own_port && is_node == 1) { logprintf(LOG_ERR, "setting \"port\" and \"server port\" cannot be the same"); have_error = 1; goto clear; } if(web_port == own_port) { logprintf(LOG_ERR, "setting \"port\" and \"webserver-port\" cannot be the same"); have_error = 1; goto clear; } if(is_node == 1 && has_config == 1) { logprintf(LOG_ERR, "a daemon running as client cannot have a config file defined"); have_error = 1; goto clear; } clear: return have_error; }