Generate and publish developer Wiki / publish-wiki (push) Canceled after 0s
Generate and publish developer Wiki / validate-wiki (push) Canceled after 9s
Build and publish release / create-release (push) Canceled after 0s
Build and publish release / build (push) Canceled after 0s
Build and publish release / publish-release (push) Canceled after 0s
Build and publish release / metadata (push) Canceled after 10s
Reviewed-on: #42 Co-authored-by: Koda YeenBean <n122330@gmail.com>
138 lines
4.6 KiB
C
138 lines
4.6 KiB
C
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <json-c/json.h>
|
|
#include "state.h"
|
|
#include "config.h"
|
|
|
|
#if ENABLE_LOGGING
|
|
#include <stdio.h>
|
|
extern FILE *log_fp;
|
|
#define LOG(fmt, ...) do { if (log_fp) openuf_log_emit(log_fp, __func__, fmt, ##__VA_ARGS__); } while(0)
|
|
#else
|
|
#define LOG(fmt, ...) do {} while(0)
|
|
#endif
|
|
|
|
static void state_defaults(openuf_state_t *st)
|
|
{
|
|
memset(st, 0, sizeof(*st));
|
|
st->adopted = false;
|
|
strncpy(st->authkey, DEFAULT_AUTH_KEY, sizeof(st->authkey) - 1);
|
|
strncpy(st->cfgversion, "0", sizeof(st->cfgversion) - 1);
|
|
st->config_applied = false;
|
|
st->config_schema = 0;
|
|
st->use_aes_gcm = false;
|
|
}
|
|
|
|
void state_load(openuf_state_t *st)
|
|
{
|
|
state_defaults(st);
|
|
|
|
FILE *f = fopen(OPENUF_STATE_FILE, "r");
|
|
if (!f) {
|
|
LOG("State file not found, using defaults");
|
|
return;
|
|
}
|
|
|
|
/* Read whole file */
|
|
fseek(f, 0, SEEK_END);
|
|
long sz = ftell(f);
|
|
rewind(f);
|
|
if (sz <= 0 || sz > 4096) { fclose(f); return; }
|
|
|
|
char *buf = malloc(sz + 1);
|
|
if (!buf) { fclose(f); return; }
|
|
fread(buf, 1, sz, f);
|
|
buf[sz] = '\0';
|
|
fclose(f);
|
|
|
|
struct json_object *root = json_tokener_parse(buf);
|
|
free(buf);
|
|
if (!root) {
|
|
LOG("Failed to parse state file");
|
|
return;
|
|
}
|
|
|
|
struct json_object *v;
|
|
#define LOAD_STR(field, key) \
|
|
if (json_object_object_get_ex(root, key, &v) && json_object_is_type(v, json_type_string)) \
|
|
strncpy(st->field, json_object_get_string(v), sizeof(st->field) - 1)
|
|
#define LOAD_BOOL(field, key) \
|
|
if (json_object_object_get_ex(root, key, &v)) \
|
|
st->field = json_object_get_boolean(v)
|
|
#define LOAD_INT(field, key) \
|
|
if (json_object_object_get_ex(root, key, &v)) \
|
|
st->field = json_object_get_int(v)
|
|
|
|
LOAD_BOOL(adopted, "adopted");
|
|
LOAD_STR (authkey, "authkey");
|
|
LOAD_STR (inform_url, "inform_url");
|
|
LOAD_STR (cfgversion, "cfgversion");
|
|
LOAD_STR (firmware_version, "firmware_version");
|
|
LOAD_BOOL(config_applied, "config_applied");
|
|
LOAD_INT (config_schema, "config_schema");
|
|
LOAD_BOOL(use_aes_gcm, "use_aes_gcm");
|
|
LOAD_STR (mac, "mac");
|
|
LOAD_STR (ip, "ip");
|
|
LOAD_STR (hostname, "hostname");
|
|
|
|
/*
|
|
* Older versions stored cfgversion from setparam before applying the
|
|
* corresponding setstate. Force one provisioning request when migrating.
|
|
*/
|
|
if (!st->config_applied ||
|
|
st->config_schema < OPENUF_CONFIG_SCHEMA) {
|
|
st->config_applied = false;
|
|
strncpy(st->cfgversion, "0", sizeof(st->cfgversion) - 1);
|
|
}
|
|
|
|
/* CRITICAL: If not adopted, force DEFAULT_AUTH_KEY */
|
|
if (!st->adopted) {
|
|
LOG("Device not adopted - resetting authkey to DEFAULT");
|
|
strncpy(st->authkey, DEFAULT_AUTH_KEY, sizeof(st->authkey) - 1);
|
|
}
|
|
|
|
LOG("State loaded: adopted=%d, authkey=%.8s..., inform_url=%s, aes_gcm=%d",
|
|
st->adopted, st->authkey[0] ? st->authkey : "DEFAULT",
|
|
st->inform_url, st->use_aes_gcm);
|
|
|
|
json_object_put(root);
|
|
}
|
|
|
|
int state_save(const openuf_state_t *st)
|
|
{
|
|
/* Ensure directory exists */
|
|
mkdir("/etc/openuf", 0755);
|
|
|
|
LOG("Saving state: adopted=%d, authkey=%.8s..., inform_url=%s, aes_gcm=%d",
|
|
st->adopted, st->authkey[0] ? st->authkey : "DEFAULT",
|
|
st->inform_url, st->use_aes_gcm);
|
|
|
|
struct json_object *root = json_object_new_object();
|
|
json_object_object_add(root, "adopted", json_object_new_boolean(st->adopted));
|
|
json_object_object_add(root, "authkey", json_object_new_string(st->authkey));
|
|
json_object_object_add(root, "inform_url", json_object_new_string(st->inform_url));
|
|
json_object_object_add(root, "cfgversion", json_object_new_string(st->cfgversion));
|
|
json_object_object_add(root, "firmware_version", json_object_new_string(st->firmware_version));
|
|
json_object_object_add(root, "config_applied", json_object_new_boolean(st->config_applied));
|
|
json_object_object_add(root, "config_schema", json_object_new_int(st->config_schema));
|
|
json_object_object_add(root, "use_aes_gcm", json_object_new_boolean(st->use_aes_gcm));
|
|
json_object_object_add(root, "mac", json_object_new_string(st->mac));
|
|
json_object_object_add(root, "ip", json_object_new_string(st->ip));
|
|
json_object_object_add(root, "hostname", json_object_new_string(st->hostname));
|
|
|
|
const char *s = json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY);
|
|
|
|
FILE *f = fopen(OPENUF_STATE_FILE, "w");
|
|
if (!f) {
|
|
LOG("Failed to open state file for writing");
|
|
json_object_put(root);
|
|
return -1;
|
|
}
|
|
fputs(s, f);
|
|
fclose(f);
|
|
json_object_put(root);
|
|
LOG("State saved successfully");
|
|
return 0;
|
|
}
|