Commit 4dd6b649d5ae192a1fbdb47669845af36e5e03e9

Con Kolivas 2012-02-22T15:40:56

Merge pull request #131 from kanoi/master Allow configuration file to include another recursively

diff --git a/README b/README
index c6a9763..183e7d2 100644
--- a/README
+++ b/README
@@ -224,6 +224,11 @@ EXECUTIVE SUMMARY ON USAGE:
 After saving configuration from the menu, you do not need to give cgminer any
 arguments and it will load your configuration.
 
+Any configuration file may also contain a single
+	"include" : "filename"
+to recursively include another configuration file.
+Writing the configuration will save all settings from all files in the output.
+
 
 Single pool, regular desktop:
 
@@ -543,10 +548,10 @@ network attached computer.
 
 You can only access the comands that reply with data in this mode.
 By default, you cannot access any privileged command that affects the miner -
-you will receive an access denied status message see --api-access below.
+you will receive an access denied status message see --api-allow below.
 
 You can specify IP addresses/prefixes that are only allowed to access the API
-with the "--api-access" option e.g. --api-access W:192.168.0.1,10.0.0/24
+with the "--api-allow" option e.g. --api-allow W:192.168.0.1,10.0.0/24
 will allow 192.168.0.1 or any address matching 10.0.0.*, but nothing else
 IP addresses are automatically padded with extra '.0's as needed
 Without a /prefix is the same as specifying /32
@@ -555,11 +560,11 @@ The 'W:' on the front gives that address/subnet privileged access to commands
 that modify cgminer.
 Without it those commands return an access denied status.
 Privileged access is checked in the order the IP addresses were supplied to
-"--api-access"
+"--api-allow"
 The first match determines the privilege level.
-Using the "--api-access" option overides the "--api-network" option if they
+Using the "--api-allow" option overides the "--api-network" option if they
 are both specified
-With "--api-access", 127.0.0.1 is not by default given access unless specified
+With "--api-allow", 127.0.0.1 is not by default given access unless specified
 
 The RPC API request can be either simple text or JSON.
 
diff --git a/cgminer.c b/cgminer.c
index 7868b24..d9d9f11 100644
--- a/cgminer.c
+++ b/cgminer.c
@@ -197,6 +197,12 @@ char *opt_socks_proxy = NULL;
 
 static const char def_conf[] = "cgminer.conf";
 static bool config_loaded = false;
+static int include_count = 0;
+#define JSON_INCLUDE_CONF "include"
+#define JSON_LOAD_ERROR "JSON decode of file '%s' failed"
+#define JSON_LOAD_ERROR_LEN strlen(JSON_LOAD_ERROR)
+#define JSON_MAX_DEPTH 10
+#define JSON_MAX_DEPTH_ERR "Too many levels of JSON includes (limit 10) or a loop"
 
 #if defined(unix)
 	static char *opt_stderr_cmd = NULL;
@@ -850,6 +856,8 @@ static struct opt_table opt_config_table[] = {
 	OPT_ENDTABLE
 };
 
+static char *load_config(const char *arg, void __maybe_unused *unused);
+
 static char *parse_config(json_t *config, bool fileconf)
 {
 	static char err_buf[200];
@@ -905,6 +913,11 @@ static char *parse_config(json_t *config, bool fileconf)
 		}
 		free(name);
 	}
+
+	val = json_object_get(config, JSON_INCLUDE_CONF);
+	if (val && json_is_string(val))
+		return load_config(json_string_value(val), NULL);
+
 	return NULL;
 }
 
@@ -912,14 +925,24 @@ static char *load_config(const char *arg, void __maybe_unused *unused)
 {
 	json_error_t err;
 	json_t *config;
+	char *json_error;
+
+	if(++include_count > JSON_MAX_DEPTH)
+		return JSON_MAX_DEPTH_ERR;
 
 #if JANSSON_MAJOR_VERSION > 1
 	config = json_load_file(arg, 0, &err);
 #else
 	config = json_load_file(arg, &err);
 #endif
-	if (!json_is_object(config))
-		return "JSON decode of file failed";
+	if (!json_is_object(config)) {
+		json_error = malloc(JSON_LOAD_ERROR_LEN + strlen(arg));
+		if (!json_error)
+			quit(1, "Malloc failure in json error");
+
+		sprintf(json_error, JSON_LOAD_ERROR, arg);
+		return json_error;
+	}
 
 	config_loaded = true;
 	/* Parse the config now, so we can override it.  That can keep pointers
@@ -2451,7 +2474,7 @@ void write_config(FILE *fcfg)
 		for (i = 0; i < nDevs; i++)
 			if (gpus[i].deven != DEV_DISABLED)
 				fprintf(fcfg, ",\n\"device\" : \"%d\"", i);
-	if (opt_api_allow != NULL)
+	if (opt_api_allow)
 		fprintf(fcfg, ",\n\"api-allow\" : \"%s\"", opt_api_allow);
 	if (strcmp(opt_api_description, PACKAGE_STRING) != 0)
 		fprintf(fcfg, ",\n\"api-description\" : \"%s\"", opt_api_description);