#include "sysvars.h" #include #include #include #include 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); }