|
@@ -0,0 +1,356 @@
|
|
|
+#include "sysvars.h"
|
|
|
+
|
|
|
+#include <stdlib.h>
|
|
|
+#include <string.h>
|
|
|
+#include <stdio.h>
|
|
|
+#include <time.h>
|
|
|
+
|
|
|
+static const char *sysvar_nulltype_tostr(sysvar_t from, char *buf)
|
|
|
+{
|
|
|
+ (void)from;
|
|
|
+ (void)buf;
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+static bool sysvar_nulltype_fromstr(sysvar_t *to, const char *from)
|
|
|
+{
|
|
|
+ (void)to;
|
|
|
+ (void)from;
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+const struct sysvar_ops sysvar_nulltype_ops = {
|
|
|
+ .tostr = sysvar_nulltype_tostr,
|
|
|
+ .fromstr = sysvar_nulltype_fromstr
|
|
|
+};
|
|
|
+
|
|
|
+static const char *sysvar_bool_tostr(sysvar_t from, char *buf)
|
|
|
+{
|
|
|
+ buf[0] = '0' + from.v_bool;
|
|
|
+ buf[1] = '\0';
|
|
|
+ return buf;
|
|
|
+}
|
|
|
+
|
|
|
+static bool sysvar_bool_fromstr(sysvar_t *to, const char *from)
|
|
|
+{
|
|
|
+ char c = from[0] | 0x20;
|
|
|
+ switch (c) {
|
|
|
+ case '1':
|
|
|
+ case 't':
|
|
|
+ case 'y':
|
|
|
+ case 'j':
|
|
|
+ case 's':
|
|
|
+ to->v_bool = true;
|
|
|
+ return true;
|
|
|
+ case '0':
|
|
|
+ case 'f':
|
|
|
+ case 'n':
|
|
|
+ to->v_bool = false;
|
|
|
+ return true;
|
|
|
+ default:
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const struct sysvar_ops sysvar_bool_ops = {
|
|
|
+ .tostr = sysvar_bool_tostr,
|
|
|
+ .fromstr = sysvar_bool_fromstr,
|
|
|
+ .buflen = BOOL_BUFLEN
|
|
|
+};
|
|
|
+
|
|
|
+static const char *sysvar_int_tostr(sysvar_t from, char *buf)
|
|
|
+{
|
|
|
+ snprintf(buf, INT_BUFLEN, "%"PRId32, from.v_int);
|
|
|
+ return buf;
|
|
|
+}
|
|
|
+
|
|
|
+static bool sysvar_int_fromstr(sysvar_t *to, const char *from)
|
|
|
+{
|
|
|
+ char *ep;
|
|
|
+ long v = strtol(from, &ep, 0);
|
|
|
+ if (ep == from || *ep)
|
|
|
+ return false;
|
|
|
+ to->v_int = v;
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+const struct sysvar_ops sysvar_int_ops = {
|
|
|
+ .tostr = sysvar_int_tostr,
|
|
|
+ .fromstr = sysvar_int_fromstr,
|
|
|
+ .buflen = INT_BUFLEN
|
|
|
+};
|
|
|
+
|
|
|
+static const char *sysvar_uint_tostr(sysvar_t from, char *buf)
|
|
|
+{
|
|
|
+ snprintf(buf, UINT_BUFLEN, "%"PRIu32, from.v_uint);
|
|
|
+ return buf;
|
|
|
+}
|
|
|
+
|
|
|
+static bool sysvar_uint_fromstr(sysvar_t *to, const char *from)
|
|
|
+{
|
|
|
+ char *ep;
|
|
|
+ unsigned long v = strtoul(from, &ep, 0);
|
|
|
+ if (ep == from || *ep)
|
|
|
+ return false;
|
|
|
+ to->v_uint = v;
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+const struct sysvar_ops sysvar_uint_ops = {
|
|
|
+ .tostr = sysvar_uint_tostr,
|
|
|
+ .fromstr = sysvar_uint_fromstr,
|
|
|
+ .buflen = UINT_BUFLEN
|
|
|
+};
|
|
|
+
|
|
|
+static const char *sysvar_string_tostr(sysvar_t from, char *buf)
|
|
|
+{
|
|
|
+ (void)buf;
|
|
|
+ return from.v_string;
|
|
|
+}
|
|
|
+
|
|
|
+static bool sysvar_string_fromstr(sysvar_t *to, const char *from)
|
|
|
+{
|
|
|
+ char *ns;
|
|
|
+
|
|
|
+ if (!from) {
|
|
|
+ ns = NULL;
|
|
|
+ } else {
|
|
|
+ ns = strdup(from);
|
|
|
+ if (!ns)
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ to->v_string = ns;
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+static bool sysvar_string_set(sysvar_t *to, sysvar_t from)
|
|
|
+{
|
|
|
+ return sysvar_string_fromstr(to, from.v_string);
|
|
|
+}
|
|
|
+
|
|
|
+const struct sysvar_ops sysvar_string_ops = {
|
|
|
+ .set = sysvar_string_set,
|
|
|
+ .tostr = sysvar_string_tostr,
|
|
|
+ .fromstr = sysvar_string_fromstr,
|
|
|
+ .is_ptr = true
|
|
|
+};
|
|
|
+
|
|
|
+static void sysvar_tz_update(sysvar_t val, bool isset)
|
|
|
+{
|
|
|
+ if (isset)
|
|
|
+ setenv("TZ", val.v_tz, 1);
|
|
|
+ else
|
|
|
+ unsetenv("TZ");
|
|
|
+ tzset();
|
|
|
+}
|
|
|
+
|
|
|
+const struct sysvar_ops sysvar_tz_ops = {
|
|
|
+ .set = sysvar_string_set,
|
|
|
+ .tostr = sysvar_string_tostr,
|
|
|
+ .fromstr = sysvar_string_fromstr,
|
|
|
+ .update = sysvar_tz_update,
|
|
|
+ .is_ptr = true
|
|
|
+};
|
|
|
+
|
|
|
+static const char *sysvar_ip_tostr(sysvar_t from, char *buf)
|
|
|
+{
|
|
|
+ union ip_bytes {
|
|
|
+ uint8_t b[4];
|
|
|
+ uint32_t l;
|
|
|
+ } ip;
|
|
|
+
|
|
|
+ ip.l = from.v_ip;
|
|
|
+ snprintf(buf, IP_BUFLEN, "%u.%u.%u.%u", ip.b[0], ip.b[1], ip.b[2], ip.b[3]);
|
|
|
+ return buf;
|
|
|
+}
|
|
|
+
|
|
|
+static bool sysvar_ip_fromstr(sysvar_t *to, const char *str)
|
|
|
+{
|
|
|
+ union ip_bytes {
|
|
|
+ uint8_t b[4];
|
|
|
+ uint32_t l;
|
|
|
+ } ip;
|
|
|
+
|
|
|
+ ip.l = 0;
|
|
|
+ for (int i = 0; i < 4; i++) {
|
|
|
+ char *ep;
|
|
|
+ unsigned long v = strtoul(str, &ep, 10);
|
|
|
+ if (ep == str || *ep != (i == 3) ? '\0' : '.' || v > 255)
|
|
|
+ return false;
|
|
|
+ str = ep + 1;
|
|
|
+ ip.b[i] = v;
|
|
|
+ }
|
|
|
+
|
|
|
+ to->v_ip = ip.l;
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+const struct sysvar_ops sysvar_ip_ops = {
|
|
|
+ .tostr = sysvar_ip_tostr,
|
|
|
+ .fromstr = sysvar_ip_fromstr,
|
|
|
+ .buflen = IP_BUFLEN
|
|
|
+};
|
|
|
+
|
|
|
+static bool sysvar_mac_set(sysvar_t *to, sysvar_t from)
|
|
|
+{
|
|
|
+ uint8_t *buf;
|
|
|
+
|
|
|
+ if (!from.v_mac) {
|
|
|
+ buf = NULL;
|
|
|
+ } else {
|
|
|
+ buf = malloc(6);
|
|
|
+ if (!buf)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ memcpy(buf, from.v_mac, 6);
|
|
|
+ }
|
|
|
+ to->v_mac = buf;
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+static const char *sysvar_mac_tostr(sysvar_t from, char *buf)
|
|
|
+{
|
|
|
+ const uint8_t *m = from.v_mac;
|
|
|
+ if (!m)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ snprintf(buf, MAC_BUFLEN, "%x:%x:%x:%x:%x:%x",
|
|
|
+ m[0], m[1], m[2], m[3], m[4], m[5]);
|
|
|
+ return buf;
|
|
|
+}
|
|
|
+
|
|
|
+static bool sysvar_mac_fromstr(sysvar_t *to, const char *str)
|
|
|
+{
|
|
|
+ sysvar_t from;
|
|
|
+ uint8_t m[6];
|
|
|
+
|
|
|
+ if (!str) {
|
|
|
+ from.v_mac = NULL;
|
|
|
+ } else {
|
|
|
+ for (int i = 0; i < 6; i++) {
|
|
|
+ char *ep;
|
|
|
+ unsigned long v = strtoul(str, &ep, 16);
|
|
|
+ if (ep == str || *ep != (i == 5) ? '\0' : ':' || v > 255)
|
|
|
+ return false;
|
|
|
+ str = ep + 1;
|
|
|
+ m[i] = v;
|
|
|
+ }
|
|
|
+
|
|
|
+ from.v_mac = m;
|
|
|
+ }
|
|
|
+
|
|
|
+ return sysvar_mac_set(to, from);
|
|
|
+}
|
|
|
+
|
|
|
+const struct sysvar_ops sysvar_mac_ops = {
|
|
|
+ .set = sysvar_mac_set,
|
|
|
+ .tostr = sysvar_mac_tostr,
|
|
|
+ .fromstr = sysvar_mac_fromstr,
|
|
|
+ .buflen = MAC_BUFLEN,
|
|
|
+ .is_ptr = true
|
|
|
+};
|
|
|
+
|
|
|
+/* --- Generic getters/setters --- */
|
|
|
+
|
|
|
+sysvar_t getvar(size_t var)
|
|
|
+{
|
|
|
+ if (var >= (size_t)sysvar_count)
|
|
|
+ return sysvar_defval[sysvar_null];
|
|
|
+
|
|
|
+ return sysvar_val[var];
|
|
|
+}
|
|
|
+
|
|
|
+static bool do_setvar(size_t var, sysvar_t val, bool is_set)
|
|
|
+{
|
|
|
+ const struct sysvar_ops *type = sysvar_type[var];
|
|
|
+ sysvar_t *to = &sysvar_val[var];
|
|
|
+ void *free_ptr = NULL;
|
|
|
+
|
|
|
+ if (type->is_ptr)
|
|
|
+ free_ptr = to->v_ptr;
|
|
|
+
|
|
|
+ if (!type->set || (type->is_ptr && !val.v_ptr)) {
|
|
|
+ sysvar_val[var] = val;
|
|
|
+ } else {
|
|
|
+ if (!type->set(to, val))
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (free_ptr)
|
|
|
+ free(free_ptr);
|
|
|
+
|
|
|
+ sysvar_isset[var] = is_set;
|
|
|
+ if (type->update)
|
|
|
+ type->update(*to, is_set);
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+bool setvar(size_t var, sysvar_t val)
|
|
|
+{
|
|
|
+ if (var >= (size_t)sysvar_count)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ return do_setvar(var, val, true);
|
|
|
+}
|
|
|
+
|
|
|
+bool unsetvar(size_t var)
|
|
|
+{
|
|
|
+ if (var >= (size_t)sysvar_count)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ return do_setvar(var, sysvar_defval[var], false);
|
|
|
+}
|
|
|
+
|
|
|
+/* --- Getters/setters converting to/from strings --- */
|
|
|
+
|
|
|
+const char *getvar_tostr(size_t var)
|
|
|
+{
|
|
|
+ static char buf[SYSVAR_BUFLEN];
|
|
|
+ return getvar_tostr_r(var, buf);
|
|
|
+}
|
|
|
+
|
|
|
+const char *getvar_tostr_r(size_t var, char *buf)
|
|
|
+{
|
|
|
+ if (var >= (size_t)sysvar_count || !sysvar_isset[var])
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ const struct sysvar_ops *type = sysvar_type[var];
|
|
|
+
|
|
|
+ /* A tostr method is required */
|
|
|
+ return type->tostr(sysvar_val[var], buf);
|
|
|
+}
|
|
|
+
|
|
|
+bool setvar_fromstr(size_t var, const char *str)
|
|
|
+{
|
|
|
+ if (var >= (size_t)sysvar_count)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ if (!str)
|
|
|
+ return unsetvar(var);
|
|
|
+
|
|
|
+ const struct sysvar_ops *type = sysvar_type[var];
|
|
|
+ sysvar_t *to = &sysvar_val[var];
|
|
|
+ void *free_ptr = NULL;
|
|
|
+
|
|
|
+ if (type->is_ptr)
|
|
|
+ free_ptr = to->v_ptr;
|
|
|
+
|
|
|
+ /* A fromstr method is required */
|
|
|
+ if (!type->fromstr(to, str))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ if (free_ptr)
|
|
|
+ free(free_ptr);
|
|
|
+
|
|
|
+ sysvar_isset[var] = true;
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+/* --- Initialization/reset to defaults --- */
|
|
|
+
|
|
|
+void sysvar_reset(void)
|
|
|
+{
|
|
|
+ for (size_t i = sysvar_null; i < (size_t)sysvar_count; i++)
|
|
|
+ unsetvar(i);
|
|
|
+}
|