configuration.c 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2006, 2007, 2008, 2009, 2013, 2020 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file src/util/configuration.c
  18. * @brief configuration management
  19. * @author Christian Grothoff
  20. */
  21. #include "platform.h"
  22. #include "gnunet_crypto_lib.h"
  23. #include "gnunet_strings_lib.h"
  24. #include "gnunet_os_lib.h"
  25. #include "gnunet_configuration_lib.h"
  26. #include "gnunet_disk_lib.h"
  27. #define LOG(kind, ...) GNUNET_log_from (kind, "util", __VA_ARGS__)
  28. #define LOG_STRERROR_FILE(kind, syscall, filename) \
  29. GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
  30. /**
  31. * @brief configuration entry
  32. */
  33. struct ConfigEntry
  34. {
  35. /**
  36. * This is a linked list.
  37. */
  38. struct ConfigEntry *next;
  39. /**
  40. * key for this entry
  41. */
  42. char *key;
  43. /**
  44. * current, commited value
  45. */
  46. char *val;
  47. };
  48. /**
  49. * @brief configuration section
  50. */
  51. struct ConfigSection
  52. {
  53. /**
  54. * This is a linked list.
  55. */
  56. struct ConfigSection *next;
  57. /**
  58. * entries in the section
  59. */
  60. struct ConfigEntry *entries;
  61. /**
  62. * name of the section
  63. */
  64. char *name;
  65. };
  66. /**
  67. * @brief configuration data
  68. */
  69. struct GNUNET_CONFIGURATION_Handle
  70. {
  71. /**
  72. * Configuration sections.
  73. */
  74. struct ConfigSection *sections;
  75. /**
  76. * Modification indication since last save
  77. * #GNUNET_NO if clean, #GNUNET_YES if dirty,
  78. * #GNUNET_SYSERR on error (i.e. last save failed)
  79. */
  80. int dirty;
  81. };
  82. /**
  83. * Used for diffing a configuration object against
  84. * the default one
  85. */
  86. struct DiffHandle
  87. {
  88. const struct GNUNET_CONFIGURATION_Handle *cfg_default;
  89. struct GNUNET_CONFIGURATION_Handle *cfgDiff;
  90. };
  91. /**
  92. * Create a GNUNET_CONFIGURATION_Handle.
  93. *
  94. * @return fresh configuration object
  95. */
  96. struct GNUNET_CONFIGURATION_Handle *
  97. GNUNET_CONFIGURATION_create ()
  98. {
  99. struct GNUNET_CONFIGURATION_Handle *cfg;
  100. char *p;
  101. cfg = GNUNET_new (struct GNUNET_CONFIGURATION_Handle);
  102. /* make certain values from the project data available
  103. as PATHS */
  104. p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
  105. if (NULL != p)
  106. {
  107. GNUNET_CONFIGURATION_set_value_string (cfg,
  108. "PATHS",
  109. "DATADIR",
  110. p);
  111. GNUNET_free (p);
  112. }
  113. p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
  114. if (NULL != p)
  115. {
  116. GNUNET_CONFIGURATION_set_value_string (cfg,
  117. "PATHS",
  118. "LIBDIR",
  119. p);
  120. GNUNET_free (p);
  121. }
  122. p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR);
  123. if (NULL != p)
  124. {
  125. GNUNET_CONFIGURATION_set_value_string (cfg,
  126. "PATHS",
  127. "BINDIR",
  128. p);
  129. GNUNET_free (p);
  130. }
  131. p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_PREFIX);
  132. if (NULL != p)
  133. {
  134. GNUNET_CONFIGURATION_set_value_string (cfg,
  135. "PATHS",
  136. "PREFIX",
  137. p);
  138. GNUNET_free (p);
  139. }
  140. p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LOCALEDIR);
  141. if (NULL != p)
  142. {
  143. GNUNET_CONFIGURATION_set_value_string (cfg,
  144. "PATHS",
  145. "LOCALEDIR",
  146. p);
  147. GNUNET_free (p);
  148. }
  149. p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_ICONDIR);
  150. if (NULL != p)
  151. {
  152. GNUNET_CONFIGURATION_set_value_string (cfg,
  153. "PATHS",
  154. "ICONDIR",
  155. p);
  156. GNUNET_free (p);
  157. }
  158. p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DOCDIR);
  159. if (NULL != p)
  160. {
  161. GNUNET_CONFIGURATION_set_value_string (cfg,
  162. "PATHS",
  163. "DOCDIR",
  164. p);
  165. GNUNET_free (p);
  166. }
  167. p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBEXECDIR);
  168. if (NULL != p)
  169. {
  170. GNUNET_CONFIGURATION_set_value_string (cfg,
  171. "PATHS",
  172. "LIBEXECDIR",
  173. p);
  174. GNUNET_free (p);
  175. }
  176. return cfg;
  177. }
  178. /**
  179. * Destroy configuration object.
  180. *
  181. * @param cfg configuration to destroy
  182. */
  183. void
  184. GNUNET_CONFIGURATION_destroy (struct GNUNET_CONFIGURATION_Handle *cfg)
  185. {
  186. struct ConfigSection *sec;
  187. while (NULL != (sec = cfg->sections))
  188. GNUNET_CONFIGURATION_remove_section (cfg, sec->name);
  189. GNUNET_free (cfg);
  190. }
  191. /**
  192. * Parse a configuration file @a filename and run the function
  193. * @a cb with the resulting configuration object. Then free the
  194. * configuration object and return the status value from @a cb.
  195. *
  196. * @param filename configuration to parse, NULL for "default"
  197. * @param cb function to run
  198. * @param cb_cls closure for @a cb
  199. * @return #GNUNET_SYSERR if parsing the configuration failed,
  200. * otherwise return value from @a cb.
  201. */
  202. int
  203. GNUNET_CONFIGURATION_parse_and_run (const char *filename,
  204. GNUNET_CONFIGURATION_Callback cb,
  205. void *cb_cls)
  206. {
  207. struct GNUNET_CONFIGURATION_Handle *cfg;
  208. int ret;
  209. cfg = GNUNET_CONFIGURATION_create ();
  210. if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, filename))
  211. {
  212. GNUNET_break (0);
  213. GNUNET_CONFIGURATION_destroy (cfg);
  214. return GNUNET_SYSERR;
  215. }
  216. ret = cb (cb_cls, cfg);
  217. GNUNET_CONFIGURATION_destroy (cfg);
  218. return ret;
  219. }
  220. /**
  221. * De-serializes configuration
  222. *
  223. * @param cfg configuration to update
  224. * @param mem the memory block of serialized configuration
  225. * @param size the size of the memory block
  226. * @param basedir set to path from which we recursively load configuration
  227. * from inlined configurations; NULL if not and raise warnings
  228. * when we come across them
  229. * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  230. */
  231. int
  232. GNUNET_CONFIGURATION_deserialize (struct GNUNET_CONFIGURATION_Handle *cfg,
  233. const char *mem,
  234. size_t size,
  235. const char *basedir)
  236. {
  237. char *line;
  238. char *line_orig;
  239. size_t line_size;
  240. char *pos;
  241. unsigned int nr;
  242. size_t r_bytes;
  243. size_t to_read;
  244. size_t i;
  245. int emptyline;
  246. int ret;
  247. char *section;
  248. char *eq;
  249. char *tag;
  250. char *value;
  251. ret = GNUNET_OK;
  252. section = GNUNET_strdup ("");
  253. nr = 0;
  254. r_bytes = 0;
  255. line_orig = NULL;
  256. while (r_bytes < size)
  257. {
  258. GNUNET_free (line_orig);
  259. /* fgets-like behaviour on buffer */
  260. to_read = size - r_bytes;
  261. pos = memchr (&mem[r_bytes], '\n', to_read);
  262. if (NULL == pos)
  263. {
  264. line_orig = GNUNET_strndup (&mem[r_bytes], line_size = to_read);
  265. r_bytes += line_size;
  266. }
  267. else
  268. {
  269. line_orig =
  270. GNUNET_strndup (&mem[r_bytes], line_size = (pos - &mem[r_bytes]));
  271. r_bytes += line_size + 1;
  272. }
  273. line = line_orig;
  274. /* increment line number */
  275. nr++;
  276. /* tabs and '\r' are whitespace */
  277. emptyline = GNUNET_YES;
  278. for (i = 0; i < line_size; i++)
  279. {
  280. if (line[i] == '\t')
  281. line[i] = ' ';
  282. if (line[i] == '\r')
  283. line[i] = ' ';
  284. if (' ' != line[i])
  285. emptyline = GNUNET_NO;
  286. }
  287. /* ignore empty lines */
  288. if (GNUNET_YES == emptyline)
  289. continue;
  290. /* remove tailing whitespace */
  291. for (i = line_size - 1; (i >= 1) && (isspace ((unsigned char) line[i]));
  292. i--)
  293. line[i] = '\0';
  294. /* remove leading whitespace */
  295. for (; line[0] != '\0' && (isspace ((unsigned char) line[0])); line++)
  296. ;
  297. /* ignore comments */
  298. if (('#' == line[0]) || ('%' == line[0]))
  299. continue;
  300. /* handle special "@INLINE@" directive */
  301. if (0 == strncasecmp (line, "@INLINE@ ", strlen ("@INLINE@ ")))
  302. {
  303. /* @INLINE@ value */
  304. value = &line[strlen ("@INLINE@ ")];
  305. if (NULL != basedir)
  306. {
  307. char *fn;
  308. GNUNET_asprintf (&fn, "%s/%s", basedir, value);
  309. if (GNUNET_OK != GNUNET_CONFIGURATION_parse (cfg, fn))
  310. {
  311. GNUNET_free (fn);
  312. ret = GNUNET_SYSERR; /* failed to parse included config */
  313. break;
  314. }
  315. GNUNET_free (fn);
  316. }
  317. else
  318. {
  319. LOG (GNUNET_ERROR_TYPE_DEBUG,
  320. "Ignoring parsing @INLINE@ configurations, not allowed!\n");
  321. ret = GNUNET_SYSERR;
  322. break;
  323. }
  324. continue;
  325. }
  326. if (('[' == line[0]) && (']' == line[line_size - 1]))
  327. {
  328. /* [value] */
  329. line[line_size - 1] = '\0';
  330. value = &line[1];
  331. GNUNET_free (section);
  332. section = GNUNET_strdup (value);
  333. continue;
  334. }
  335. if (NULL != (eq = strchr (line, '=')))
  336. {
  337. /* tag = value */
  338. tag = GNUNET_strndup (line, eq - line);
  339. /* remove tailing whitespace */
  340. for (i = strlen (tag) - 1; (i >= 1) && (isspace ((unsigned char) tag[i]));
  341. i--)
  342. tag[i] = '\0';
  343. /* Strip whitespace */
  344. value = eq + 1;
  345. while (isspace ((unsigned char) value[0]))
  346. value++;
  347. for (i = strlen (value) - 1;
  348. (i >= 1) && (isspace ((unsigned char) value[i]));
  349. i--)
  350. value[i] = '\0';
  351. /* remove quotes */
  352. i = 0;
  353. if (('"' == value[0]) && ('"' == value[strlen (value) - 1]))
  354. {
  355. value[strlen (value) - 1] = '\0';
  356. value++;
  357. }
  358. GNUNET_CONFIGURATION_set_value_string (cfg, section, tag, &value[i]);
  359. GNUNET_free (tag);
  360. continue;
  361. }
  362. /* parse error */
  363. LOG (GNUNET_ERROR_TYPE_WARNING,
  364. _ ("Syntax error while deserializing in line %u\n"),
  365. nr);
  366. ret = GNUNET_SYSERR;
  367. break;
  368. }
  369. GNUNET_free (line_orig);
  370. GNUNET_free (section);
  371. GNUNET_assert ((GNUNET_OK != ret) || (r_bytes == size));
  372. return ret;
  373. }
  374. /**
  375. * Parse a configuration file, add all of the options in the
  376. * file to the configuration environment.
  377. *
  378. * @param cfg configuration to update
  379. * @param filename name of the configuration file
  380. * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  381. */
  382. int
  383. GNUNET_CONFIGURATION_parse (struct GNUNET_CONFIGURATION_Handle *cfg,
  384. const char *filename)
  385. {
  386. uint64_t fs64;
  387. size_t fs;
  388. char *fn;
  389. char *mem;
  390. char *endsep;
  391. int dirty;
  392. int ret;
  393. ssize_t sret;
  394. fn = GNUNET_STRINGS_filename_expand (filename);
  395. LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to parse config file `%s'\n", fn);
  396. if (NULL == fn)
  397. return GNUNET_SYSERR;
  398. dirty = cfg->dirty; /* back up value! */
  399. if (GNUNET_SYSERR ==
  400. GNUNET_DISK_file_size (fn, &fs64, GNUNET_YES, GNUNET_YES))
  401. {
  402. LOG (GNUNET_ERROR_TYPE_WARNING,
  403. "Error while determining the file size of `%s'\n",
  404. fn);
  405. GNUNET_free (fn);
  406. return GNUNET_SYSERR;
  407. }
  408. if (fs64 > SIZE_MAX)
  409. {
  410. GNUNET_break (0); /* File size is more than the heap size */
  411. GNUNET_free (fn);
  412. return GNUNET_SYSERR;
  413. }
  414. fs = fs64;
  415. mem = GNUNET_malloc (fs);
  416. sret = GNUNET_DISK_fn_read (fn, mem, fs);
  417. if ((sret < 0) || (fs != (size_t) sret))
  418. {
  419. LOG (GNUNET_ERROR_TYPE_WARNING, _ ("Error while reading file `%s'\n"), fn);
  420. GNUNET_free (fn);
  421. GNUNET_free (mem);
  422. return GNUNET_SYSERR;
  423. }
  424. LOG (GNUNET_ERROR_TYPE_DEBUG, "Deserializing contents of file `%s'\n", fn);
  425. endsep = strrchr (fn, (int) '/');
  426. if (NULL != endsep)
  427. *endsep = '\0';
  428. ret = GNUNET_CONFIGURATION_deserialize (cfg, mem, fs, fn);
  429. GNUNET_free (fn);
  430. GNUNET_free (mem);
  431. /* restore dirty flag - anything we set in the meantime
  432. * came from disk */
  433. cfg->dirty = dirty;
  434. return ret;
  435. }
  436. /**
  437. * Test if there are configuration options that were
  438. * changed since the last save.
  439. *
  440. * @param cfg configuration to inspect
  441. * @return #GNUNET_NO if clean, #GNUNET_YES if dirty, #GNUNET_SYSERR on error (i.e. last save failed)
  442. */
  443. int
  444. GNUNET_CONFIGURATION_is_dirty (const struct GNUNET_CONFIGURATION_Handle *cfg)
  445. {
  446. return cfg->dirty;
  447. }
  448. /**
  449. * Serializes the given configuration.
  450. *
  451. * @param cfg configuration to serialize
  452. * @param size will be set to the size of the serialized memory block
  453. * @return the memory block where the serialized configuration is
  454. * present. This memory should be freed by the caller
  455. */
  456. char *
  457. GNUNET_CONFIGURATION_serialize (const struct GNUNET_CONFIGURATION_Handle *cfg,
  458. size_t *size)
  459. {
  460. struct ConfigSection *sec;
  461. struct ConfigEntry *ent;
  462. char *mem;
  463. char *cbuf;
  464. char *val;
  465. char *pos;
  466. size_t m_size;
  467. size_t c_size;
  468. /* Pass1 : calculate the buffer size required */
  469. m_size = 0;
  470. for (sec = cfg->sections; NULL != sec; sec = sec->next)
  471. {
  472. /* For each section we need to add 3 charaters: {'[',']','\n'} */
  473. m_size += strlen (sec->name) + 3;
  474. for (ent = sec->entries; NULL != ent; ent = ent->next)
  475. {
  476. if (NULL != ent->val)
  477. {
  478. /* if val has any '\n' then they occupy +1 character as '\n'->'\\','n' */
  479. pos = ent->val;
  480. while (NULL != (pos = strstr (pos, "\n")))
  481. {
  482. m_size++;
  483. pos++;
  484. }
  485. /* For each key = value pair we need to add 4 characters (2
  486. spaces and 1 equal-to character and 1 new line) */
  487. m_size += strlen (ent->key) + strlen (ent->val) + 4;
  488. }
  489. }
  490. /* A new line after section end */
  491. m_size++;
  492. }
  493. /* Pass2: Allocate memory and write the configuration to it */
  494. mem = GNUNET_malloc (m_size);
  495. sec = cfg->sections;
  496. c_size = 0;
  497. *size = c_size;
  498. while (NULL != sec)
  499. {
  500. int len;
  501. len = GNUNET_asprintf (&cbuf, "[%s]\n", sec->name);
  502. GNUNET_assert (0 < len);
  503. GNUNET_memcpy (mem + c_size, cbuf, len);
  504. c_size += len;
  505. GNUNET_free (cbuf);
  506. for (ent = sec->entries; NULL != ent; ent = ent->next)
  507. {
  508. if (NULL != ent->val)
  509. {
  510. val = GNUNET_malloc (strlen (ent->val) * 2 + 1);
  511. strcpy (val, ent->val);
  512. while (NULL != (pos = strstr (val, "\n")))
  513. {
  514. memmove (&pos[2], &pos[1], strlen (&pos[1]));
  515. pos[0] = '\\';
  516. pos[1] = 'n';
  517. }
  518. len = GNUNET_asprintf (&cbuf, "%s = %s\n", ent->key, val);
  519. GNUNET_free (val);
  520. GNUNET_memcpy (mem + c_size, cbuf, len);
  521. c_size += len;
  522. GNUNET_free (cbuf);
  523. }
  524. }
  525. GNUNET_memcpy (mem + c_size, "\n", 1);
  526. c_size++;
  527. sec = sec->next;
  528. }
  529. GNUNET_assert (c_size == m_size);
  530. *size = c_size;
  531. return mem;
  532. }
  533. /**
  534. * Write configuration file.
  535. *
  536. * @param cfg configuration to write
  537. * @param filename where to write the configuration
  538. * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  539. */
  540. int
  541. GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *cfg,
  542. const char *filename)
  543. {
  544. char *fn;
  545. char *cfg_buf;
  546. size_t size;
  547. ssize_t sret;
  548. fn = GNUNET_STRINGS_filename_expand (filename);
  549. if (fn == NULL)
  550. return GNUNET_SYSERR;
  551. if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (fn))
  552. {
  553. GNUNET_free (fn);
  554. return GNUNET_SYSERR;
  555. }
  556. cfg_buf = GNUNET_CONFIGURATION_serialize (cfg, &size);
  557. sret = GNUNET_DISK_fn_write (fn,
  558. cfg_buf,
  559. size,
  560. GNUNET_DISK_PERM_USER_READ
  561. | GNUNET_DISK_PERM_USER_WRITE
  562. | GNUNET_DISK_PERM_GROUP_READ
  563. | GNUNET_DISK_PERM_GROUP_WRITE);
  564. if ((sret < 0) || (size != (size_t) sret))
  565. {
  566. GNUNET_free (fn);
  567. GNUNET_free (cfg_buf);
  568. LOG (GNUNET_ERROR_TYPE_WARNING,
  569. "Writing configuration to file `%s' failed\n",
  570. filename);
  571. cfg->dirty = GNUNET_SYSERR; /* last write failed */
  572. return GNUNET_SYSERR;
  573. }
  574. GNUNET_free (fn);
  575. GNUNET_free (cfg_buf);
  576. cfg->dirty = GNUNET_NO; /* last write succeeded */
  577. return GNUNET_OK;
  578. }
  579. /**
  580. * Iterate over all options in the configuration.
  581. *
  582. * @param cfg configuration to inspect
  583. * @param iter function to call on each option
  584. * @param iter_cls closure for @a iter
  585. */
  586. void
  587. GNUNET_CONFIGURATION_iterate (const struct GNUNET_CONFIGURATION_Handle *cfg,
  588. GNUNET_CONFIGURATION_Iterator iter,
  589. void *iter_cls)
  590. {
  591. struct ConfigSection *spos;
  592. struct ConfigEntry *epos;
  593. for (spos = cfg->sections; NULL != spos; spos = spos->next)
  594. for (epos = spos->entries; NULL != epos; epos = epos->next)
  595. if (NULL != epos->val)
  596. iter (iter_cls, spos->name, epos->key, epos->val);
  597. }
  598. /**
  599. * Iterate over values of a section in the configuration.
  600. *
  601. * @param cfg configuration to inspect
  602. * @param section the section
  603. * @param iter function to call on each option
  604. * @param iter_cls closure for @a iter
  605. */
  606. void
  607. GNUNET_CONFIGURATION_iterate_section_values (
  608. const struct GNUNET_CONFIGURATION_Handle *cfg,
  609. const char *section,
  610. GNUNET_CONFIGURATION_Iterator iter,
  611. void *iter_cls)
  612. {
  613. struct ConfigSection *spos;
  614. struct ConfigEntry *epos;
  615. spos = cfg->sections;
  616. while ((spos != NULL) && (0 != strcasecmp (spos->name, section)))
  617. spos = spos->next;
  618. if (NULL == spos)
  619. return;
  620. for (epos = spos->entries; NULL != epos; epos = epos->next)
  621. if (NULL != epos->val)
  622. iter (iter_cls, spos->name, epos->key, epos->val);
  623. }
  624. /**
  625. * Iterate over all sections in the configuration.
  626. *
  627. * @param cfg configuration to inspect
  628. * @param iter function to call on each section
  629. * @param iter_cls closure for @a iter
  630. */
  631. void
  632. GNUNET_CONFIGURATION_iterate_sections (
  633. const struct GNUNET_CONFIGURATION_Handle *cfg,
  634. GNUNET_CONFIGURATION_Section_Iterator iter,
  635. void *iter_cls)
  636. {
  637. struct ConfigSection *spos;
  638. struct ConfigSection *next;
  639. next = cfg->sections;
  640. while (next != NULL)
  641. {
  642. spos = next;
  643. next = spos->next;
  644. iter (iter_cls, spos->name);
  645. }
  646. }
  647. /**
  648. * Remove the given section and all options in it.
  649. *
  650. * @param cfg configuration to inspect
  651. * @param section name of the section to remove
  652. */
  653. void
  654. GNUNET_CONFIGURATION_remove_section (struct GNUNET_CONFIGURATION_Handle *cfg,
  655. const char *section)
  656. {
  657. struct ConfigSection *spos;
  658. struct ConfigSection *prev;
  659. struct ConfigEntry *ent;
  660. prev = NULL;
  661. spos = cfg->sections;
  662. while (NULL != spos)
  663. {
  664. if (0 == strcasecmp (section, spos->name))
  665. {
  666. if (NULL == prev)
  667. cfg->sections = spos->next;
  668. else
  669. prev->next = spos->next;
  670. while (NULL != (ent = spos->entries))
  671. {
  672. spos->entries = ent->next;
  673. GNUNET_free (ent->key);
  674. GNUNET_free (ent->val);
  675. GNUNET_free (ent);
  676. cfg->dirty = GNUNET_YES;
  677. }
  678. GNUNET_free (spos->name);
  679. GNUNET_free (spos);
  680. return;
  681. }
  682. prev = spos;
  683. spos = spos->next;
  684. }
  685. }
  686. /**
  687. * Copy a configuration value to the given target configuration.
  688. * Overwrites existing entries.
  689. *
  690. * @param cls the destination configuration (`struct GNUNET_CONFIGURATION_Handle *`)
  691. * @param section section for the value
  692. * @param option option name of the value
  693. * @param value value to copy
  694. */
  695. static void
  696. copy_entry (void *cls,
  697. const char *section,
  698. const char *option,
  699. const char *value)
  700. {
  701. struct GNUNET_CONFIGURATION_Handle *dst = cls;
  702. GNUNET_CONFIGURATION_set_value_string (dst, section, option, value);
  703. }
  704. /**
  705. * Duplicate an existing configuration object.
  706. *
  707. * @param cfg configuration to duplicate
  708. * @return duplicate configuration
  709. */
  710. struct GNUNET_CONFIGURATION_Handle *
  711. GNUNET_CONFIGURATION_dup (const struct GNUNET_CONFIGURATION_Handle *cfg)
  712. {
  713. struct GNUNET_CONFIGURATION_Handle *ret;
  714. ret = GNUNET_CONFIGURATION_create ();
  715. GNUNET_CONFIGURATION_iterate (cfg, &copy_entry, ret);
  716. return ret;
  717. }
  718. /**
  719. * Find a section entry from a configuration.
  720. *
  721. * @param cfg configuration to search in
  722. * @param section name of the section to look for
  723. * @return matching entry, NULL if not found
  724. */
  725. static struct ConfigSection *
  726. find_section (const struct GNUNET_CONFIGURATION_Handle *cfg,
  727. const char *section)
  728. {
  729. struct ConfigSection *pos;
  730. pos = cfg->sections;
  731. while ((pos != NULL) && (0 != strcasecmp (section, pos->name)))
  732. pos = pos->next;
  733. return pos;
  734. }
  735. /**
  736. * Find an entry from a configuration.
  737. *
  738. * @param cfg handle to the configuration
  739. * @param section section the option is in
  740. * @param key the option
  741. * @return matching entry, NULL if not found
  742. */
  743. static struct ConfigEntry *
  744. find_entry (const struct GNUNET_CONFIGURATION_Handle *cfg,
  745. const char *section,
  746. const char *key)
  747. {
  748. struct ConfigSection *sec;
  749. struct ConfigEntry *pos;
  750. if (NULL == (sec = find_section (cfg, section)))
  751. return NULL;
  752. pos = sec->entries;
  753. while ((pos != NULL) && (0 != strcasecmp (key, pos->key)))
  754. pos = pos->next;
  755. return pos;
  756. }
  757. /**
  758. * A callback function, compares entries from two configurations
  759. * (default against a new configuration) and write the diffs in a
  760. * diff-configuration object (the callback object).
  761. *
  762. * @param cls the diff configuration (`struct DiffHandle *`)
  763. * @param section section for the value (of the default conf.)
  764. * @param option option name of the value (of the default conf.)
  765. * @param value value to copy (of the default conf.)
  766. */
  767. static void
  768. compare_entries (void *cls,
  769. const char *section,
  770. const char *option,
  771. const char *value)
  772. {
  773. struct DiffHandle *dh = cls;
  774. struct ConfigEntry *entNew;
  775. entNew = find_entry (dh->cfg_default, section, option);
  776. if ((NULL != entNew) && (NULL != entNew->val) &&
  777. (0 == strcmp (entNew->val, value)))
  778. return;
  779. GNUNET_CONFIGURATION_set_value_string (dh->cfgDiff, section, option, value);
  780. }
  781. /**
  782. * Compute configuration with only entries that have been changed
  783. *
  784. * @param cfg_default original configuration
  785. * @param cfg_new new configuration
  786. * @return configuration with only the differences, never NULL
  787. */
  788. struct GNUNET_CONFIGURATION_Handle *
  789. GNUNET_CONFIGURATION_get_diff (
  790. const struct GNUNET_CONFIGURATION_Handle *cfg_default,
  791. const struct GNUNET_CONFIGURATION_Handle *cfg_new)
  792. {
  793. struct DiffHandle diffHandle;
  794. diffHandle.cfgDiff = GNUNET_CONFIGURATION_create ();
  795. diffHandle.cfg_default = cfg_default;
  796. GNUNET_CONFIGURATION_iterate (cfg_new, &compare_entries, &diffHandle);
  797. return diffHandle.cfgDiff;
  798. }
  799. /**
  800. * Write only configuration entries that have been changed to configuration file
  801. *
  802. * @param cfg_default default configuration
  803. * @param cfg_new new configuration
  804. * @param filename where to write the configuration diff between default and new
  805. * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  806. */
  807. int
  808. GNUNET_CONFIGURATION_write_diffs (
  809. const struct GNUNET_CONFIGURATION_Handle *cfg_default,
  810. const struct GNUNET_CONFIGURATION_Handle *cfg_new,
  811. const char *filename)
  812. {
  813. int ret;
  814. struct GNUNET_CONFIGURATION_Handle *diff;
  815. diff = GNUNET_CONFIGURATION_get_diff (cfg_default, cfg_new);
  816. ret = GNUNET_CONFIGURATION_write (diff, filename);
  817. GNUNET_CONFIGURATION_destroy (diff);
  818. return ret;
  819. }
  820. /**
  821. * Set a configuration value that should be a string.
  822. *
  823. * @param cfg configuration to update
  824. * @param section section of interest
  825. * @param option option of interest
  826. * @param value value to set
  827. */
  828. void
  829. GNUNET_CONFIGURATION_set_value_string (struct GNUNET_CONFIGURATION_Handle *cfg,
  830. const char *section,
  831. const char *option,
  832. const char *value)
  833. {
  834. struct ConfigSection *sec;
  835. struct ConfigEntry *e;
  836. char *nv;
  837. e = find_entry (cfg, section, option);
  838. if (NULL != e)
  839. {
  840. if (NULL == value)
  841. {
  842. GNUNET_free (e->val);
  843. e->val = NULL;
  844. }
  845. else
  846. {
  847. nv = GNUNET_strdup (value);
  848. GNUNET_free (e->val);
  849. e->val = nv;
  850. }
  851. return;
  852. }
  853. sec = find_section (cfg, section);
  854. if (sec == NULL)
  855. {
  856. sec = GNUNET_new (struct ConfigSection);
  857. sec->name = GNUNET_strdup (section);
  858. sec->next = cfg->sections;
  859. cfg->sections = sec;
  860. }
  861. e = GNUNET_new (struct ConfigEntry);
  862. e->key = GNUNET_strdup (option);
  863. e->val = GNUNET_strdup (value);
  864. e->next = sec->entries;
  865. sec->entries = e;
  866. }
  867. /**
  868. * Set a configuration value that should be a number.
  869. *
  870. * @param cfg configuration to update
  871. * @param section section of interest
  872. * @param option option of interest
  873. * @param number value to set
  874. */
  875. void
  876. GNUNET_CONFIGURATION_set_value_number (struct GNUNET_CONFIGURATION_Handle *cfg,
  877. const char *section,
  878. const char *option,
  879. unsigned long long number)
  880. {
  881. char s[64];
  882. GNUNET_snprintf (s, 64, "%llu", number);
  883. GNUNET_CONFIGURATION_set_value_string (cfg, section, option, s);
  884. }
  885. /**
  886. * Get a configuration value that should be a number.
  887. *
  888. * @param cfg configuration to inspect
  889. * @param section section of interest
  890. * @param option option of interest
  891. * @param number where to store the numeric value of the option
  892. * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  893. */
  894. int
  895. GNUNET_CONFIGURATION_get_value_number (
  896. const struct GNUNET_CONFIGURATION_Handle *cfg,
  897. const char *section,
  898. const char *option,
  899. unsigned long long *number)
  900. {
  901. struct ConfigEntry *e;
  902. char dummy[2];
  903. if (NULL == (e = find_entry (cfg, section, option)))
  904. return GNUNET_SYSERR;
  905. if (NULL == e->val)
  906. return GNUNET_SYSERR;
  907. if (1 != sscanf (e->val, "%llu%1s", number, dummy))
  908. return GNUNET_SYSERR;
  909. return GNUNET_OK;
  910. }
  911. /**
  912. * Get a configuration value that should be a floating point number.
  913. *
  914. * @param cfg configuration to inspect
  915. * @param section section of interest
  916. * @param option option of interest
  917. * @param number where to store the floating value of the option
  918. * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  919. */
  920. int
  921. GNUNET_CONFIGURATION_get_value_float (
  922. const struct GNUNET_CONFIGURATION_Handle *cfg,
  923. const char *section,
  924. const char *option,
  925. float *number)
  926. {
  927. struct ConfigEntry *e;
  928. char dummy[2];
  929. if (NULL == (e = find_entry (cfg, section, option)))
  930. return GNUNET_SYSERR;
  931. if (NULL == e->val)
  932. return GNUNET_SYSERR;
  933. if (1 != sscanf (e->val, "%f%1s", number, dummy))
  934. return GNUNET_SYSERR;
  935. return GNUNET_OK;
  936. }
  937. /**
  938. * Get a configuration value that should be a relative time.
  939. *
  940. * @param cfg configuration to inspect
  941. * @param section section of interest
  942. * @param option option of interest
  943. * @param time set to the time value stored in the configuration
  944. * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  945. */
  946. int
  947. GNUNET_CONFIGURATION_get_value_time (
  948. const struct GNUNET_CONFIGURATION_Handle *cfg,
  949. const char *section,
  950. const char *option,
  951. struct GNUNET_TIME_Relative *time)
  952. {
  953. struct ConfigEntry *e;
  954. int ret;
  955. if (NULL == (e = find_entry (cfg, section, option)))
  956. return GNUNET_SYSERR;
  957. if (NULL == e->val)
  958. return GNUNET_SYSERR;
  959. ret = GNUNET_STRINGS_fancy_time_to_relative (e->val, time);
  960. if (GNUNET_OK != ret)
  961. GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
  962. section,
  963. option,
  964. _ ("Not a valid relative time specification"));
  965. return ret;
  966. }
  967. /**
  968. * Get a configuration value that should be a size in bytes.
  969. *
  970. * @param cfg configuration to inspect
  971. * @param section section of interest
  972. * @param option option of interest
  973. * @param size set to the size in bytes as stored in the configuration
  974. * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  975. */
  976. int
  977. GNUNET_CONFIGURATION_get_value_size (
  978. const struct GNUNET_CONFIGURATION_Handle *cfg,
  979. const char *section,
  980. const char *option,
  981. unsigned long long *size)
  982. {
  983. struct ConfigEntry *e;
  984. if (NULL == (e = find_entry (cfg, section, option)))
  985. return GNUNET_SYSERR;
  986. if (NULL == e->val)
  987. return GNUNET_SYSERR;
  988. return GNUNET_STRINGS_fancy_size_to_bytes (e->val, size);
  989. }
  990. /**
  991. * Get a configuration value that should be a string.
  992. *
  993. * @param cfg configuration to inspect
  994. * @param section section of interest
  995. * @param option option of interest
  996. * @param value will be set to a freshly allocated configuration
  997. * value, or NULL if option is not specified
  998. * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  999. */
  1000. int
  1001. GNUNET_CONFIGURATION_get_value_string (
  1002. const struct GNUNET_CONFIGURATION_Handle *cfg,
  1003. const char *section,
  1004. const char *option,
  1005. char **value)
  1006. {
  1007. struct ConfigEntry *e;
  1008. if ((NULL == (e = find_entry (cfg, section, option))) || (NULL == e->val))
  1009. {
  1010. *value = NULL;
  1011. return GNUNET_SYSERR;
  1012. }
  1013. *value = GNUNET_strdup (e->val);
  1014. return GNUNET_OK;
  1015. }
  1016. /**
  1017. * Get a configuration value that should be in a set of
  1018. * predefined strings
  1019. *
  1020. * @param cfg configuration to inspect
  1021. * @param section section of interest
  1022. * @param option option of interest
  1023. * @param choices NULL-terminated list of legal values
  1024. * @param value will be set to an entry in the legal list,
  1025. * or NULL if option is not specified and no default given
  1026. * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  1027. */
  1028. int
  1029. GNUNET_CONFIGURATION_get_value_choice (
  1030. const struct GNUNET_CONFIGURATION_Handle *cfg,
  1031. const char *section,
  1032. const char *option,
  1033. const char *const *choices,
  1034. const char **value)
  1035. {
  1036. struct ConfigEntry *e;
  1037. unsigned int i;
  1038. if (NULL == (e = find_entry (cfg, section, option)))
  1039. return GNUNET_SYSERR;
  1040. for (i = 0; NULL != choices[i]; i++)
  1041. if (0 == strcasecmp (choices[i], e->val))
  1042. break;
  1043. if (NULL == choices[i])
  1044. {
  1045. LOG (GNUNET_ERROR_TYPE_ERROR,
  1046. _ ("Configuration value '%s' for '%s'"
  1047. " in section '%s' is not in set of legal choices\n"),
  1048. e->val,
  1049. option,
  1050. section);
  1051. return GNUNET_SYSERR;
  1052. }
  1053. *value = choices[i];
  1054. return GNUNET_OK;
  1055. }
  1056. /**
  1057. * Get crockford32-encoded fixed-size binary data from a configuration.
  1058. *
  1059. * @param cfg configuration to access
  1060. * @param section section to access
  1061. * @param option option to access
  1062. * @param buf where to store the decoded binary result
  1063. * @param buf_size exact number of bytes to store in @a buf
  1064. * @return #GNUNET_OK on success
  1065. * #GNUNET_NO is the value does not exist
  1066. * #GNUNET_SYSERR on decoding error
  1067. */
  1068. int
  1069. GNUNET_CONFIGURATION_get_data (const struct GNUNET_CONFIGURATION_Handle *cfg,
  1070. const char *section,
  1071. const char *option,
  1072. void *buf,
  1073. size_t buf_size)
  1074. {
  1075. char *enc;
  1076. int res;
  1077. size_t data_size;
  1078. if (GNUNET_OK !=
  1079. (res =
  1080. GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &enc)))
  1081. return res;
  1082. data_size = (strlen (enc) * 5) / 8;
  1083. if (data_size != buf_size)
  1084. {
  1085. GNUNET_free (enc);
  1086. return GNUNET_SYSERR;
  1087. }
  1088. if (GNUNET_OK !=
  1089. GNUNET_STRINGS_string_to_data (enc, strlen (enc), buf, buf_size))
  1090. {
  1091. GNUNET_free (enc);
  1092. return GNUNET_SYSERR;
  1093. }
  1094. GNUNET_free (enc);
  1095. return GNUNET_OK;
  1096. }
  1097. /**
  1098. * Test if we have a value for a particular option
  1099. *
  1100. * @param cfg configuration to inspect
  1101. * @param section section of interest
  1102. * @param option option of interest
  1103. * @return #GNUNET_YES if so, #GNUNET_NO if not.
  1104. */
  1105. int
  1106. GNUNET_CONFIGURATION_have_value (const struct GNUNET_CONFIGURATION_Handle *cfg,
  1107. const char *section,
  1108. const char *option)
  1109. {
  1110. struct ConfigEntry *e;
  1111. if ((NULL == (e = find_entry (cfg, section, option))) || (NULL == e->val))
  1112. return GNUNET_NO;
  1113. return GNUNET_YES;
  1114. }
  1115. /**
  1116. * Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR"
  1117. * where either in the "PATHS" section or the environtment "FOO" is
  1118. * set to "DIRECTORY". We also support default expansion,
  1119. * i.e. ${VARIABLE:-default} will expand to $VARIABLE if VARIABLE is
  1120. * set in PATHS or the environment, and otherwise to "default". Note
  1121. * that "default" itself can also be a $-expression, thus
  1122. * "${VAR1:-{$VAR2}}" will expand to VAR1 and if that is not defined
  1123. * to VAR2.
  1124. *
  1125. * @param cfg configuration to use for path expansion
  1126. * @param orig string to $-expand (will be freed!)
  1127. * @param depth recursion depth, used to detect recursive expansions
  1128. * @return $-expanded string, never NULL unless @a orig was NULL
  1129. */
  1130. static char *
  1131. expand_dollar (const struct GNUNET_CONFIGURATION_Handle *cfg,
  1132. char *orig,
  1133. unsigned int depth)
  1134. {
  1135. char *prefix;
  1136. char *result;
  1137. char *start;
  1138. const char *post;
  1139. const char *env;
  1140. char *def;
  1141. char *end;
  1142. unsigned int lopen;
  1143. char erased_char;
  1144. char *erased_pos;
  1145. size_t len;
  1146. if (NULL == orig)
  1147. return NULL;
  1148. if (depth > 128)
  1149. {
  1150. LOG (GNUNET_ERROR_TYPE_WARNING,
  1151. _ (
  1152. "Recursive expansion suspected, aborting $-expansion for term `%s'\n"),
  1153. orig);
  1154. return orig;
  1155. }
  1156. LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to $-expand %s\n", orig);
  1157. if ('$' != orig[0])
  1158. {
  1159. LOG (GNUNET_ERROR_TYPE_DEBUG, "Doesn't start with $ - not expanding\n");
  1160. return orig;
  1161. }
  1162. erased_char = 0;
  1163. erased_pos = NULL;
  1164. if ('{' == orig[1])
  1165. {
  1166. start = &orig[2];
  1167. lopen = 1;
  1168. end = &orig[1];
  1169. while (lopen > 0)
  1170. {
  1171. end++;
  1172. switch (*end)
  1173. {
  1174. case '}':
  1175. lopen--;
  1176. break;
  1177. case '{':
  1178. lopen++;
  1179. break;
  1180. case '\0':
  1181. LOG (GNUNET_ERROR_TYPE_WARNING,
  1182. _ ("Missing closing `%s' in option `%s'\n"),
  1183. "}",
  1184. orig);
  1185. return orig;
  1186. default:
  1187. break;
  1188. }
  1189. }
  1190. erased_char = *end;
  1191. erased_pos = end;
  1192. *end = '\0';
  1193. post = end + 1;
  1194. def = strchr (orig, ':');
  1195. if (NULL != def)
  1196. {
  1197. *def = '\0';
  1198. def++;
  1199. if (('-' == *def) || ('=' == *def))
  1200. def++;
  1201. def = GNUNET_strdup (def);
  1202. }
  1203. }
  1204. else
  1205. {
  1206. int i;
  1207. start = &orig[1];
  1208. def = NULL;
  1209. i = 0;
  1210. while ((orig[i] != '/') && (orig[i] != '\\') && (orig[i] != '\0') &&
  1211. (orig[i] != ' '))
  1212. i++;
  1213. if (orig[i] == '\0')
  1214. {
  1215. post = "";
  1216. }
  1217. else
  1218. {
  1219. erased_char = orig[i];
  1220. erased_pos = &orig[i];
  1221. orig[i] = '\0';
  1222. post = &orig[i + 1];
  1223. }
  1224. }
  1225. LOG (GNUNET_ERROR_TYPE_DEBUG,
  1226. "Split into `%s' and `%s' with default %s\n",
  1227. start,
  1228. post,
  1229. def);
  1230. if (GNUNET_OK !=
  1231. GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", start, &prefix))
  1232. {
  1233. if (NULL == (env = getenv (start)))
  1234. {
  1235. /* try default */
  1236. def = expand_dollar (cfg, def, depth + 1);
  1237. env = def;
  1238. }
  1239. if (NULL == env)
  1240. {
  1241. start = GNUNET_strdup (start);
  1242. if (erased_pos)
  1243. *erased_pos = erased_char;
  1244. LOG (GNUNET_ERROR_TYPE_WARNING,
  1245. _ (
  1246. "Failed to expand `%s' in `%s' as it is neither found in [PATHS] nor defined as an environmental variable\n"),
  1247. start,
  1248. orig);
  1249. GNUNET_free (start);
  1250. return orig;
  1251. }
  1252. prefix = GNUNET_strdup (env);
  1253. }
  1254. prefix = GNUNET_CONFIGURATION_expand_dollar (cfg, prefix);
  1255. if ((erased_pos) && ('}' != erased_char))
  1256. {
  1257. len = strlen (prefix) + 1;
  1258. prefix = GNUNET_realloc (prefix, len + 1);
  1259. prefix[len - 1] = erased_char;
  1260. prefix[len] = '\0';
  1261. }
  1262. result = GNUNET_malloc (strlen (prefix) + strlen (post) + 1);
  1263. strcpy (result, prefix);
  1264. strcat (result, post);
  1265. GNUNET_free (def);
  1266. GNUNET_free (prefix);
  1267. GNUNET_free (orig);
  1268. return result;
  1269. }
  1270. /**
  1271. * Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR"
  1272. * where either in the "PATHS" section or the environtment "FOO" is
  1273. * set to "DIRECTORY". We also support default expansion,
  1274. * i.e. ${VARIABLE:-default} will expand to $VARIABLE if VARIABLE is
  1275. * set in PATHS or the environment, and otherwise to "default". Note
  1276. * that "default" itself can also be a $-expression, thus
  1277. * "${VAR1:-{$VAR2}}" will expand to VAR1 and if that is not defined
  1278. * to VAR2.
  1279. *
  1280. * @param cfg configuration to use for path expansion
  1281. * @param orig string to $-expand (will be freed!). Note that multiple
  1282. * $-expressions can be present in this string. They will all be
  1283. * $-expanded.
  1284. * @return $-expanded string
  1285. */
  1286. char *
  1287. GNUNET_CONFIGURATION_expand_dollar (
  1288. const struct GNUNET_CONFIGURATION_Handle *cfg,
  1289. char *orig)
  1290. {
  1291. char *dup;
  1292. size_t i;
  1293. size_t len;
  1294. for (i = 0; '\0' != orig[i]; i++)
  1295. {
  1296. if ('$' != orig[i])
  1297. continue;
  1298. dup = GNUNET_strdup (orig + i);
  1299. dup = expand_dollar (cfg, dup, 0);
  1300. GNUNET_assert (NULL != dup); /* make compiler happy */
  1301. len = strlen (dup) + 1;
  1302. orig = GNUNET_realloc (orig, i + len);
  1303. GNUNET_memcpy (orig + i, dup, len);
  1304. GNUNET_free (dup);
  1305. }
  1306. return orig;
  1307. }
  1308. /**
  1309. * Get a configuration value that should be a string.
  1310. *
  1311. * @param cfg configuration to inspect
  1312. * @param section section of interest
  1313. * @param option option of interest
  1314. * @param value will be set to a freshly allocated configuration
  1315. * value, or NULL if option is not specified
  1316. * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  1317. */
  1318. int
  1319. GNUNET_CONFIGURATION_get_value_filename (
  1320. const struct GNUNET_CONFIGURATION_Handle *cfg,
  1321. const char *section,
  1322. const char *option,
  1323. char **value)
  1324. {
  1325. char *tmp;
  1326. if (GNUNET_OK !=
  1327. GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &tmp))
  1328. {
  1329. LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to retrieve filename\n");
  1330. *value = NULL;
  1331. return GNUNET_SYSERR;
  1332. }
  1333. tmp = GNUNET_CONFIGURATION_expand_dollar (cfg, tmp);
  1334. *value = GNUNET_STRINGS_filename_expand (tmp);
  1335. GNUNET_free (tmp);
  1336. if (*value == NULL)
  1337. return GNUNET_SYSERR;
  1338. return GNUNET_OK;
  1339. }
  1340. /**
  1341. * Get a configuration value that should be in a set of
  1342. * "YES" or "NO".
  1343. *
  1344. * @param cfg configuration to inspect
  1345. * @param section section of interest
  1346. * @param option option of interest
  1347. * @return #GNUNET_YES, #GNUNET_NO or #GNUNET_SYSERR
  1348. */
  1349. int
  1350. GNUNET_CONFIGURATION_get_value_yesno (
  1351. const struct GNUNET_CONFIGURATION_Handle *cfg,
  1352. const char *section,
  1353. const char *option)
  1354. {
  1355. static const char *yesno[] = { "YES", "NO", NULL };
  1356. const char *val;
  1357. int ret;
  1358. ret =
  1359. GNUNET_CONFIGURATION_get_value_choice (cfg, section, option, yesno, &val);
  1360. if (ret == GNUNET_SYSERR)
  1361. return ret;
  1362. if (val == yesno[0])
  1363. return GNUNET_YES;
  1364. return GNUNET_NO;
  1365. }
  1366. /**
  1367. * Iterate over the set of filenames stored in a configuration value.
  1368. *
  1369. * @param cfg configuration to inspect
  1370. * @param section section of interest
  1371. * @param option option of interest
  1372. * @param cb function to call on each filename
  1373. * @param cb_cls closure for @a cb
  1374. * @return number of filenames iterated over, -1 on error
  1375. */
  1376. int
  1377. GNUNET_CONFIGURATION_iterate_value_filenames (
  1378. const struct GNUNET_CONFIGURATION_Handle *cfg,
  1379. const char *section,
  1380. const char *option,
  1381. GNUNET_FileNameCallback cb,
  1382. void *cb_cls)
  1383. {
  1384. char *list;
  1385. char *pos;
  1386. char *end;
  1387. char old;
  1388. int ret;
  1389. if (GNUNET_OK !=
  1390. GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list))
  1391. return 0;
  1392. GNUNET_assert (list != NULL);
  1393. ret = 0;
  1394. pos = list;
  1395. while (1)
  1396. {
  1397. while (pos[0] == ' ')
  1398. pos++;
  1399. if (strlen (pos) == 0)
  1400. break;
  1401. end = pos + 1;
  1402. while ((end[0] != ' ') && (end[0] != '\0'))
  1403. {
  1404. if (end[0] == '\\')
  1405. {
  1406. switch (end[1])
  1407. {
  1408. case '\\':
  1409. case ' ':
  1410. memmove (end, &end[1], strlen (&end[1]) + 1);
  1411. case '\0':
  1412. /* illegal, but just keep it */
  1413. break;
  1414. default:
  1415. /* illegal, but just ignore that there was a '/' */
  1416. break;
  1417. }
  1418. }
  1419. end++;
  1420. }
  1421. old = end[0];
  1422. end[0] = '\0';
  1423. if (strlen (pos) > 0)
  1424. {
  1425. ret++;
  1426. if ((cb != NULL) && (GNUNET_OK != cb (cb_cls, pos)))
  1427. {
  1428. ret = GNUNET_SYSERR;
  1429. break;
  1430. }
  1431. }
  1432. if (old == '\0')
  1433. break;
  1434. pos = end + 1;
  1435. }
  1436. GNUNET_free (list);
  1437. return ret;
  1438. }
  1439. /**
  1440. * FIXME.
  1441. *
  1442. * @param value FIXME
  1443. * @return FIXME
  1444. */
  1445. static char *
  1446. escape_name (const char *value)
  1447. {
  1448. char *escaped;
  1449. const char *rpos;
  1450. char *wpos;
  1451. escaped = GNUNET_malloc (strlen (value) * 2 + 1);
  1452. memset (escaped, 0, strlen (value) * 2 + 1);
  1453. rpos = value;
  1454. wpos = escaped;
  1455. while (rpos[0] != '\0')
  1456. {
  1457. switch (rpos[0])
  1458. {
  1459. case '\\':
  1460. case ' ':
  1461. wpos[0] = '\\';
  1462. wpos[1] = rpos[0];
  1463. wpos += 2;
  1464. break;
  1465. default:
  1466. wpos[0] = rpos[0];
  1467. wpos++;
  1468. }
  1469. rpos++;
  1470. }
  1471. return escaped;
  1472. }
  1473. /**
  1474. * FIXME.
  1475. *
  1476. * @param cls string we compare with (const char*)
  1477. * @param fn filename we are currently looking at
  1478. * @return #GNUNET_OK if the names do not match, #GNUNET_SYSERR if they do
  1479. */
  1480. static int
  1481. test_match (void *cls, const char *fn)
  1482. {
  1483. const char *of = cls;
  1484. return (0 == strcmp (of, fn)) ? GNUNET_SYSERR : GNUNET_OK;
  1485. }
  1486. /**
  1487. * Append a filename to a configuration value that
  1488. * represents a list of filenames
  1489. *
  1490. * @param cfg configuration to update
  1491. * @param section section of interest
  1492. * @param option option of interest
  1493. * @param value filename to append
  1494. * @return #GNUNET_OK on success,
  1495. * #GNUNET_NO if the filename already in the list
  1496. * #GNUNET_SYSERR on error
  1497. */
  1498. int
  1499. GNUNET_CONFIGURATION_append_value_filename (
  1500. struct GNUNET_CONFIGURATION_Handle *cfg,
  1501. const char *section,
  1502. const char *option,
  1503. const char *value)
  1504. {
  1505. char *escaped;
  1506. char *old;
  1507. char *nw;
  1508. if (GNUNET_SYSERR ==
  1509. GNUNET_CONFIGURATION_iterate_value_filenames (cfg,
  1510. section,
  1511. option,
  1512. &test_match,
  1513. (void *) value))
  1514. return GNUNET_NO; /* already exists */
  1515. if (GNUNET_OK !=
  1516. GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &old))
  1517. old = GNUNET_strdup ("");
  1518. escaped = escape_name (value);
  1519. nw = GNUNET_malloc (strlen (old) + strlen (escaped) + 2);
  1520. strcpy (nw, old);
  1521. if (strlen (old) > 0)
  1522. strcat (nw, " ");
  1523. strcat (nw, escaped);
  1524. GNUNET_CONFIGURATION_set_value_string (cfg, section, option, nw);
  1525. GNUNET_free (old);
  1526. GNUNET_free (nw);
  1527. GNUNET_free (escaped);
  1528. return GNUNET_OK;
  1529. }
  1530. /**
  1531. * Remove a filename from a configuration value that
  1532. * represents a list of filenames
  1533. *
  1534. * @param cfg configuration to update
  1535. * @param section section of interest
  1536. * @param option option of interest
  1537. * @param value filename to remove
  1538. * @return #GNUNET_OK on success,
  1539. * #GNUNET_NO if the filename is not in the list,
  1540. * #GNUNET_SYSERR on error
  1541. */
  1542. int
  1543. GNUNET_CONFIGURATION_remove_value_filename (
  1544. struct GNUNET_CONFIGURATION_Handle *cfg,
  1545. const char *section,
  1546. const char *option,
  1547. const char *value)
  1548. {
  1549. char *list;
  1550. char *pos;
  1551. char *end;
  1552. char *match;
  1553. char old;
  1554. if (GNUNET_OK !=
  1555. GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list))
  1556. return GNUNET_NO;
  1557. match = escape_name (value);
  1558. pos = list;
  1559. while (1)
  1560. {
  1561. while (pos[0] == ' ')
  1562. pos++;
  1563. if (strlen (pos) == 0)
  1564. break;
  1565. end = pos + 1;
  1566. while ((end[0] != ' ') && (end[0] != '\0'))
  1567. {
  1568. if (end[0] == '\\')
  1569. {
  1570. switch (end[1])
  1571. {
  1572. case '\\':
  1573. case ' ':
  1574. end++;
  1575. break;
  1576. case '\0':
  1577. /* illegal, but just keep it */
  1578. break;
  1579. default:
  1580. /* illegal, but just ignore that there was a '/' */
  1581. break;
  1582. }
  1583. }
  1584. end++;
  1585. }
  1586. old = end[0];
  1587. end[0] = '\0';
  1588. if (0 == strcmp (pos, match))
  1589. {
  1590. if (old != '\0')
  1591. memmove (pos, &end[1], strlen (&end[1]) + 1);
  1592. else
  1593. {
  1594. if (pos != list)
  1595. pos[-1] = '\0';
  1596. else
  1597. pos[0] = '\0';
  1598. }
  1599. GNUNET_CONFIGURATION_set_value_string (cfg, section, option, list);
  1600. GNUNET_free (list);
  1601. GNUNET_free (match);
  1602. return GNUNET_OK;
  1603. }
  1604. if (old == '\0')
  1605. break;
  1606. end[0] = old;
  1607. pos = end + 1;
  1608. }
  1609. GNUNET_free (list);
  1610. GNUNET_free (match);
  1611. return GNUNET_NO;
  1612. }
  1613. /**
  1614. * Wrapper around #GNUNET_CONFIGURATION_parse. Called on each
  1615. * file in a directory, we trigger parsing on those files that
  1616. * end with ".conf".
  1617. *
  1618. * @param cls the cfg
  1619. * @param filename file to parse
  1620. * @return #GNUNET_OK on success
  1621. */
  1622. static int
  1623. parse_configuration_file (void *cls, const char *filename)
  1624. {
  1625. struct GNUNET_CONFIGURATION_Handle *cfg = cls;
  1626. char *ext;
  1627. int ret;
  1628. /* Examine file extension */
  1629. ext = strrchr (filename, '.');
  1630. if ((NULL == ext) || (0 != strcmp (ext, ".conf")))
  1631. {
  1632. GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Skipping file `%s'\n", filename);
  1633. return GNUNET_OK;
  1634. }
  1635. ret = GNUNET_CONFIGURATION_parse (cfg, filename);
  1636. return ret;
  1637. }
  1638. /**
  1639. * Load default configuration. This function will parse the
  1640. * defaults from the given defaults_d directory.
  1641. *
  1642. * @param cfg configuration to update
  1643. * @param defaults_d directory with the defaults
  1644. * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  1645. */
  1646. int
  1647. GNUNET_CONFIGURATION_load_from (struct GNUNET_CONFIGURATION_Handle *cfg,
  1648. const char *defaults_d)
  1649. {
  1650. if (GNUNET_SYSERR ==
  1651. GNUNET_DISK_directory_scan (defaults_d, &parse_configuration_file, cfg))
  1652. return GNUNET_SYSERR; /* no configuration at all found */
  1653. return GNUNET_OK;
  1654. }
  1655. /**
  1656. * Return GNUnet's default configuration. A new configuration is allocated
  1657. * each time and it's up to the caller to destroy it when done. This function
  1658. * returns GNUnet's configuration even when #GNUNET_OS_init has been called
  1659. * with a value different from #GNUNET_OS_project_data_default.
  1660. *
  1661. * @return a freshly allocated configuration
  1662. */
  1663. struct GNUNET_CONFIGURATION_Handle *
  1664. GNUNET_CONFIGURATION_default (void)
  1665. {
  1666. const struct GNUNET_OS_ProjectData *pd = GNUNET_OS_project_data_get ();
  1667. const struct GNUNET_OS_ProjectData *dpd = GNUNET_OS_project_data_default ();
  1668. GNUNET_OS_init (dpd);
  1669. struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
  1670. const char *xdg = getenv ("XDG_CONFIG_HOME");
  1671. char *cfgname = NULL;
  1672. if (NULL != xdg)
  1673. GNUNET_asprintf (&cfgname, "%s/%s", xdg, pd->config_file);
  1674. else
  1675. cfgname = GNUNET_strdup (pd->user_config_file);
  1676. if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgname))
  1677. {
  1678. GNUNET_OS_init (pd);
  1679. GNUNET_CONFIGURATION_destroy (cfg);
  1680. GNUNET_free (cfgname);
  1681. return NULL;
  1682. }
  1683. GNUNET_free (cfgname);
  1684. GNUNET_OS_init (pd);
  1685. return cfg;
  1686. }
  1687. /* end of configuration.c */