sysvars.c 7.4 KB

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