Kludge "config set" to fix Batphone upgrade bug

This commit is contained in:
Andrew Bettison 2012-11-14 13:15:13 +10:30
parent 9c69eaca1c
commit f2d6c6d522
3 changed files with 77 additions and 6 deletions

View File

@ -900,6 +900,7 @@ int app_config_set(int argc, const char *const *argv, struct command_line_option
return -1;
if (create_serval_instance_dir() == -1)
return -1;
confReloadIfNewer();
return confValueSet(var, val) == -1 ? -1 : confWrite();
}

78
conf.c
View File

@ -18,6 +18,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include <sys/stat.h>
#include <ctype.h>
#include "conf.h"
#include "log.h"
@ -53,9 +54,11 @@ int is_configvarname(const char *arg)
return s[-1] != '.';
}
#define CONFFILE_NAME "serval.conf"
#define MAX_CONFIG_VARS (100)
#define CONFIG_BUFFER_ALLOCSIZE (1024)
static time_t config_timestamp = 0;
static char *config_buffer = NULL;
static char *config_buffer_top = NULL;
static char *config_buffer_end = NULL;
@ -94,15 +97,25 @@ static char *grow_config_buffer(size_t needed)
static int _read_config()
{
char conffile[1024];
if (!FORM_SERVAL_INSTANCE_PATH(conffile, "serval.conf"))
if (!FORM_SERVAL_INSTANCE_PATH(conffile, CONFFILE_NAME))
return -1;
size_t size = 0;
confc = 0;
int exists = 0;
FILE *f = fopen(conffile, "r");
if (f == NULL) {
if (errno != ENOENT)
return WHYF_perror("fopen(%s)", conffile);
INFOF("non-existent config file %s", conffile);
config_timestamp = 0;
} else {
exists = 1;
struct stat st;
if (fstat(fileno(f), &st) == -1) {
WHYF_perror("fstat(%s)", conffile);
fclose(f);
return -1;
}
if (fseeko(f, (off_t) 0, SEEK_END) == -1) {
WHYF_perror("fseeko(%s, 0, SEEK_END)", conffile);
fclose(f);
@ -124,6 +137,7 @@ static int _read_config()
fclose(f);
return -1;
}
config_timestamp = 0;
if (fread(config_buffer, size, 1, f) != 1) {
if (ferror(f))
WHYF_perror("fread(%s, %llu)", conffile, (unsigned long long) size);
@ -134,10 +148,12 @@ static int _read_config()
fclose(f);
return -1;
}
config_timestamp = st.st_mtime;
if (fclose(f) == EOF)
return WHYF_perror("fclose(%s)", conffile);
INFOF("successfully read %s", conffile);
}
config_buffer_top = config_buffer_end = config_buffer + size;
config_buffer_top = config_buffer + size;
char *c = config_buffer;
char *e = config_buffer_top;
unsigned int linenum;
@ -187,7 +203,7 @@ static int _read_config()
}
if (problem)
return WHYF("Error in %s at line %u: %s%s", conffile, linenum, problem, extra);
return 0;
return exists;
}
static int read_config()
@ -195,6 +211,38 @@ static int read_config()
return _read_config();
}
/* Check if the config file has changed since we last read it, and if so, invalidate the buffer so
* that the next call to read_config() will re-load it. Returns 1 if the buffer was invalidated, 0
* if not, -1 on error.
*
* TODO: when the config system is overhauled to provide proper dynamic config reloading in JNI and
* in the servald daemon, this method will become unnecessary.
*
* @author Andrew Bettison <andrew@servalproject.com>
*/
int confReloadIfNewer()
{
char conffile[1024];
if (!FORM_SERVAL_INSTANCE_PATH(conffile, CONFFILE_NAME))
return -1;
struct stat st;
if (stat(conffile, &st) == -1) {
if (errno != ENOENT)
return WHYF_perror("stat(%s)", conffile);
st.st_mtime = 0;
}
if (config_timestamp != st.st_mtime) {
INFOF("detected new version of %s", conffile);
_read_config();
return 1;
}
return 0;
}
/* Return the number of config options.
*
* @author Andrew Bettison <andrew@servalproject.com>
*/
int confVarCount()
{
if (!config_buffer && read_config() == -1)
@ -202,6 +250,12 @@ int confVarCount()
return confc;
}
/* Return the string value of the config option with the given index, which must be in the range
* 0..confVarCount(). The returned pointer is only valid until the next call to confVar() or any
* other configuration query function.
*
* @author Andrew Bettison <andrew@servalproject.com>
*/
const char *confVar(unsigned int index)
{
if (!config_buffer && read_config() == -1)
@ -224,6 +278,14 @@ const char *confValue(unsigned int index)
return confvalue[index];
}
/* Return the string value of the config option with the given name. The returned pointer is only
* valid until the next call to confVarCount(), confVar(), confValue() or any other configuration
* query function. If the named config option is not defined, then returns the given default value.
* If the named config option cannot be determined for any other reason, then logs the reason and
* returns the given default value.
*
* @author Andrew Bettison <andrew@servalproject.com>
*/
const char *confValueGet(const char *var, const char *defaultValue)
{
if (var == NULL) {
@ -357,8 +419,6 @@ int confValueSet(const char *var, const char *value)
}
}
} else {
if (confc >= MAX_CONFIG_VARS)
return WHYF("Cannot set %s: too many variables", var);
size_t valuelen = strlen(value);
unsigned int i;
for (i = 0; i != confc; ++i) {
@ -373,6 +433,8 @@ int confValueSet(const char *var, const char *value)
return 0;
}
}
if (confc >= MAX_CONFIG_VARS)
return WHYF("Cannot set %s: too many variables", var);
size_t varlen = strlen(var);
char *buf = grow_config_buffer(varlen + 1 + valuelen + 1);
if (buf == NULL)
@ -381,6 +443,7 @@ int confValueSet(const char *var, const char *value)
confvalue[confc] = strcpy(buf + varlen + 1, value);
++confc;
}
INFOF("config set %s = %s", var, value ? alloca_str_toprint(value) : "NULL");
return 0;
}
@ -406,6 +469,11 @@ int confWrite()
unlink(tempfile);
return -1;
}
struct stat st;
if (stat(conffile, &st) == -1)
return WHYF_perror("stat(%s)", conffile);
config_timestamp = st.st_mtime;
INFOF("successfully wrote %s", conffile);
}
return 0;
}

4
conf.h
View File

@ -31,9 +31,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
/* Handy statement for forming a path to an instance file in a char buffer whose declaration
* is in scope (so that sizeof(buf) will work). Evaluates to true if the pathname fitted into
* the provided buffer, false (0) otherwise (after printing a message to stderr). */
* the provided buffer, false (0) otherwise (after logging an error).
*/
#define FORM_SERVAL_INSTANCE_PATH(buf, path) (form_serval_instance_path(buf, sizeof(buf), (path)))
int confReloadIfNewer();
const char *confValueGet(const char *var, const char *defaultValue);
int confValueGetBoolean(const char *var, int defaultValue);
int64_t confValueGetInt64(const char *var, int64_t defaultValue);