sysvars.c 7.5 KB

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