sysvars.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. #include "common.h"
  2. #include "sysvars.h"
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <stdio.h>
  6. #include <time.h>
  7. #define DEBUG 1
  8. #ifndef DEBUG
  9. # define DEBUG 0
  10. #endif
  11. static const char *sysvar_bool_tostr(sysvar_t from, char *buf)
  12. {
  13. buf[0] = '0' + from.v_bool;
  14. buf[1] = '\0';
  15. return buf;
  16. }
  17. static bool sysvar_bool_fromstr(sysvar_t *to, const char *from)
  18. {
  19. char c = from[0] | 0x20;
  20. switch (c) {
  21. case '1':
  22. case 't':
  23. case 'y':
  24. case 'j':
  25. case 's':
  26. to->v_bool = true;
  27. return true;
  28. case ' ': /* Blank or null */
  29. case '0':
  30. case 'f':
  31. case 'n':
  32. to->v_bool = false;
  33. return true;
  34. default:
  35. return false;
  36. }
  37. }
  38. const struct sysvar_ops sysvar_bool_ops = {
  39. .tostr = sysvar_bool_tostr,
  40. .fromstr = sysvar_bool_fromstr,
  41. .buflen = BOOL_BUFLEN
  42. };
  43. static const char *sysvar_int_tostr(sysvar_t from, char *buf)
  44. {
  45. snprintf(buf, INT_BUFLEN, "%ld", from.v_int);
  46. return buf;
  47. }
  48. static bool sysvar_int_fromstr(sysvar_t *to, const char *from)
  49. {
  50. char *ep;
  51. long v = strtol(from, &ep, 0);
  52. if (ep == from || *ep)
  53. return false;
  54. to->v_int = v;
  55. return true;
  56. }
  57. const struct sysvar_ops sysvar_int_ops = {
  58. .tostr = sysvar_int_tostr,
  59. .fromstr = sysvar_int_fromstr,
  60. .buflen = INT_BUFLEN
  61. };
  62. static const char *sysvar_uint_tostr(sysvar_t from, char *buf)
  63. {
  64. snprintf(buf, UINT_BUFLEN, "%lu", from.v_uint);
  65. return buf;
  66. }
  67. static bool sysvar_uint_fromstr(sysvar_t *to, const char *from)
  68. {
  69. char *ep;
  70. unsigned long v = strtoul(from, &ep, 0);
  71. if (ep == from || *ep)
  72. return false;
  73. to->v_uint = v;
  74. return true;
  75. }
  76. const struct sysvar_ops sysvar_uint_ops = {
  77. .tostr = sysvar_uint_tostr,
  78. .fromstr = sysvar_uint_fromstr,
  79. .buflen = UINT_BUFLEN
  80. };
  81. static const char *sysvar_str_tostr(sysvar_t from, char *buf)
  82. {
  83. (void)buf;
  84. return from.v_str;
  85. }
  86. static bool sysvar_str_fromstr(sysvar_t *to, const char *from)
  87. {
  88. char *ns;
  89. if (!from) {
  90. ns = NULL;
  91. } else {
  92. ns = strdup(from);
  93. if (!ns)
  94. return false;
  95. }
  96. to->v_str = ns;
  97. return true;
  98. }
  99. static bool sysvar_str_set(sysvar_t *to, sysvar_t from)
  100. {
  101. return sysvar_str_fromstr(to, from.v_str);
  102. }
  103. static size_t sysvar_str_datasize(sysvar_t val)
  104. {
  105. return (val.v_str ? strlen(val.v_str) : 0) + 1;
  106. }
  107. const struct sysvar_ops sysvar_str_ops = {
  108. .set = sysvar_str_set,
  109. .tostr = sysvar_str_tostr,
  110. .fromstr = sysvar_str_fromstr,
  111. .datasize = sysvar_str_datasize
  112. };
  113. static void sysvar_tz_update(sysvar_t val, bool isset)
  114. {
  115. if (isset)
  116. setenv("TZ", val.v_tz, 1);
  117. else
  118. unsetenv("TZ");
  119. tzset();
  120. }
  121. const struct sysvar_ops sysvar_tz_ops = {
  122. .set = sysvar_str_set,
  123. .tostr = sysvar_str_tostr,
  124. .fromstr = sysvar_str_fromstr,
  125. .update = sysvar_tz_update,
  126. .datasize = sysvar_str_datasize
  127. };
  128. static const char *sysvar_ip_tostr(sysvar_t from, char *buf)
  129. {
  130. union ip_bytes {
  131. uint8_t b[4];
  132. uint32_t l;
  133. } ip;
  134. ip.l = from.v_ip;
  135. snprintf(buf, IP_BUFLEN,
  136. "%u.%u.%u.%u", ip.b[0], ip.b[1], ip.b[2], ip.b[3]);
  137. return buf;
  138. }
  139. static bool sysvar_ip_fromstr(sysvar_t *to, const char *str)
  140. {
  141. union ip_bytes {
  142. uint8_t b[4];
  143. uint32_t l;
  144. } ip;
  145. ip.l = 0;
  146. for (int i = 0; i < 4; i++) {
  147. char *ep;
  148. unsigned long v = strtoul(str, &ep, 10);
  149. if (ep == str || *ep != (i == 3) ? '\0' : '.' || v > 255)
  150. return false;
  151. str = ep + 1;
  152. ip.b[i] = v;
  153. }
  154. to->v_ip = ip.l;
  155. return true;
  156. }
  157. const struct sysvar_ops sysvar_ip_ops = {
  158. .tostr = sysvar_ip_tostr,
  159. .fromstr = sysvar_ip_fromstr,
  160. .buflen = IP_BUFLEN
  161. };
  162. static bool sysvar_mac_set(sysvar_t *to, sysvar_t from)
  163. {
  164. uint8_t *buf;
  165. if (!from.v_mac) {
  166. buf = NULL;
  167. } else {
  168. buf = malloc(6);
  169. if (!buf)
  170. return false;
  171. memcpy(buf, from.v_mac, 6);
  172. }
  173. to->v_mac = buf;
  174. return true;
  175. }
  176. static const char *sysvar_mac_tostr(sysvar_t from, char *buf)
  177. {
  178. const uint8_t *m = from.v_mac;
  179. if (!m)
  180. return NULL;
  181. snprintf(buf, MAC_BUFLEN, "%x:%x:%x:%x:%x:%x",
  182. m[0], m[1], m[2], m[3], m[4], m[5]);
  183. return buf;
  184. }
  185. static bool sysvar_mac_fromstr(sysvar_t *to, const char *str)
  186. {
  187. sysvar_t from;
  188. uint8_t m[6];
  189. if (!str) {
  190. from.v_mac = NULL;
  191. } else {
  192. for (int i = 0; i < 6; i++) {
  193. char *ep;
  194. unsigned long v = strtoul(str, &ep, 16);
  195. if (ep == str || *ep != (i == 5) ? '\0' : ':' || v > 255)
  196. return false;
  197. str = ep + 1;
  198. m[i] = v;
  199. }
  200. from.v_mac = m;
  201. }
  202. return sysvar_mac_set(to, from);
  203. }
  204. static size_t sysvar_mac_datasize(sysvar_t val)
  205. {
  206. (void)val;
  207. return 6;
  208. }
  209. const struct sysvar_ops sysvar_mac_ops = {
  210. .set = sysvar_mac_set,
  211. .tostr = sysvar_mac_tostr,
  212. .fromstr = sysvar_mac_fromstr,
  213. .buflen = MAC_BUFLEN,
  214. .datasize = sysvar_mac_datasize
  215. };
  216. /* --- Generic getters/setters --- */
  217. /* Contains the lowest numbered sysvar changed; or sysvar_count if nothing */
  218. enum sysvar_enum sysvar_changed;
  219. sysvar_t getvar(size_t var)
  220. {
  221. if (var >= (size_t)sysvar_count)
  222. return sysvar_defval[sysvar_null];
  223. return sysvar_val[var];
  224. }
  225. static bool do_setvar(size_t var, sysvar_t val, bool is_set)
  226. {
  227. const struct sysvar_ops *type = sysvar_types[var];
  228. sysvar_t *to = &sysvar_val[var];
  229. void *free_ptr = NULL;
  230. if (type->datasize)
  231. free_ptr = to->v_ptr;
  232. if (DEBUG) {
  233. char tostr_buf[SYSVAR_BUFLEN];
  234. printf("%ssetvar %zu %s <- %s\n", is_set ? "" : "un",
  235. var, sysvar_name[var],
  236. notempty(type->tostr(val, tostr_buf)));
  237. }
  238. if (!type->set || (type->datasize && !val.v_ptr)) {
  239. sysvar_val[var] = val;
  240. } else {
  241. if (!type->set(to, val))
  242. return false;
  243. }
  244. if (free_ptr)
  245. free(free_ptr);
  246. if (var < (size_t)sysvar_changed)
  247. sysvar_changed = (enum sysvar_enum)var;
  248. sysvar_isset[var] = is_set;
  249. if (type->update)
  250. type->update(*to, is_set);
  251. return true;
  252. }
  253. bool setvar(size_t var, sysvar_t val)
  254. {
  255. if (var >= (size_t)sysvar_count)
  256. return false;
  257. return do_setvar(var, val, true);
  258. }
  259. bool unsetvar(size_t var)
  260. {
  261. if (var >= (size_t)sysvar_count)
  262. return false;
  263. return do_setvar(var, sysvar_defval[var], false);
  264. }
  265. /* --- Getters/setters converting to/from strings --- */
  266. const char *getvar_tostr(size_t var)
  267. {
  268. static char buf[SYSVAR_BUFLEN];
  269. return getvar_tostr_r(var, buf);
  270. }
  271. const char *getvar_tostr_r(size_t var, char *buf)
  272. {
  273. if (var >= (size_t)sysvar_count)
  274. return NULL;
  275. const struct sysvar_ops *type = sysvar_types[var];
  276. /* A tostr method is required */
  277. return type->tostr(sysvar_val[var], buf);
  278. }
  279. bool setvar_fromstr(size_t var, const char *str)
  280. {
  281. if (var >= (size_t)sysvar_count)
  282. return NULL;
  283. if (!str)
  284. return unsetvar(var);
  285. const struct sysvar_ops *type = sysvar_types[var];
  286. sysvar_t *to = &sysvar_val[var];
  287. void *free_ptr = NULL;
  288. if (type->datasize)
  289. free_ptr = to->v_ptr;
  290. if (DEBUG) {
  291. printf("setvar_fromstr %zu %s <- %s\n", var, sysvar_name[var], str);
  292. }
  293. /* A fromstr method is required */
  294. if (!type->fromstr(to, str))
  295. return false;
  296. if (var < (size_t)sysvar_changed)
  297. sysvar_changed = (enum sysvar_enum)var;
  298. if (free_ptr)
  299. free(free_ptr);
  300. sysvar_isset[var] = true;
  301. return true;
  302. }
  303. /* --- Find the index of a specific variable --- */
  304. static int string_ptr_compare(const void *a, const void *b)
  305. {
  306. const char * const *aa = a;
  307. const char * const *bb = b;
  308. return strcmp(*aa, *bb);
  309. }
  310. size_t sysvar_find(size_t ns, const char *name)
  311. {
  312. if (ns >= (size_t)sysvar_nscount)
  313. return 0;
  314. const sysvar_ns_t *nsi = &sysvar_ns[ns];
  315. const char * const *varname;
  316. const size_t count = nsi[1].first - nsi->first;
  317. varname = bsearch(&name, sysvar_name + nsi->first,
  318. count, sizeof *sysvar_name,
  319. string_ptr_compare);
  320. if (!varname)
  321. return 0;
  322. return varname - sysvar_name;
  323. }
  324. /* --- Initialization/reset to defaults --- */
  325. void sysvar_reset(size_t ns)
  326. {
  327. if (ns >= (size_t)sysvar_nscount)
  328. return;
  329. enum sysvar_enum i;
  330. for (i = sysvar_ns[ns].first; i < sysvar_ns[ns+1].first; i++)
  331. unsetvar(i);
  332. if (sysvar_changed < i)
  333. sysvar_changed = i;
  334. }
  335. void sysvar_init(void)
  336. {
  337. for (enum sysvar_enum i = sysvar_null+1; i < sysvar_count; i++)
  338. unsetvar(i);
  339. sysvar_changed = sysvar_count;
  340. }