sysvar.c 7.6 KB

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