configuration.c 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639
  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, committed 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. enum GNUNET_GenericReturnValue 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. struct GNUNET_CONFIGURATION_Handle *
  92. GNUNET_CONFIGURATION_create ()
  93. {
  94. struct GNUNET_CONFIGURATION_Handle *cfg;
  95. char *p;
  96. cfg = GNUNET_new (struct GNUNET_CONFIGURATION_Handle);
  97. /* make certain values from the project data available
  98. as PATHS */
  99. p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
  100. if (NULL != p)
  101. {
  102. GNUNET_CONFIGURATION_set_value_string (cfg,
  103. "PATHS",
  104. "DATADIR",
  105. p);
  106. GNUNET_free (p);
  107. }
  108. p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
  109. if (NULL != p)
  110. {
  111. GNUNET_CONFIGURATION_set_value_string (cfg,
  112. "PATHS",
  113. "LIBDIR",
  114. p);
  115. GNUNET_free (p);
  116. }
  117. p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR);
  118. if (NULL != p)
  119. {
  120. GNUNET_CONFIGURATION_set_value_string (cfg,
  121. "PATHS",
  122. "BINDIR",
  123. p);
  124. GNUNET_free (p);
  125. }
  126. p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_PREFIX);
  127. if (NULL != p)
  128. {
  129. GNUNET_CONFIGURATION_set_value_string (cfg,
  130. "PATHS",
  131. "PREFIX",
  132. p);
  133. GNUNET_free (p);
  134. }
  135. p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LOCALEDIR);
  136. if (NULL != p)
  137. {
  138. GNUNET_CONFIGURATION_set_value_string (cfg,
  139. "PATHS",
  140. "LOCALEDIR",
  141. p);
  142. GNUNET_free (p);
  143. }
  144. p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_ICONDIR);
  145. if (NULL != p)
  146. {
  147. GNUNET_CONFIGURATION_set_value_string (cfg,
  148. "PATHS",
  149. "ICONDIR",
  150. p);
  151. GNUNET_free (p);
  152. }
  153. p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DOCDIR);
  154. if (NULL != p)
  155. {
  156. GNUNET_CONFIGURATION_set_value_string (cfg,
  157. "PATHS",
  158. "DOCDIR",
  159. p);
  160. GNUNET_free (p);
  161. }
  162. p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBEXECDIR);
  163. if (NULL != p)
  164. {
  165. GNUNET_CONFIGURATION_set_value_string (cfg,
  166. "PATHS",
  167. "LIBEXECDIR",
  168. p);
  169. GNUNET_free (p);
  170. }
  171. return cfg;
  172. }
  173. void
  174. GNUNET_CONFIGURATION_destroy (struct GNUNET_CONFIGURATION_Handle *cfg)
  175. {
  176. struct ConfigSection *sec;
  177. while (NULL != (sec = cfg->sections))
  178. GNUNET_CONFIGURATION_remove_section (cfg, sec->name);
  179. GNUNET_free (cfg);
  180. }
  181. enum GNUNET_GenericReturnValue
  182. GNUNET_CONFIGURATION_parse_and_run (const char *filename,
  183. GNUNET_CONFIGURATION_Callback cb,
  184. void *cb_cls)
  185. {
  186. struct GNUNET_CONFIGURATION_Handle *cfg;
  187. enum GNUNET_GenericReturnValue ret;
  188. cfg = GNUNET_CONFIGURATION_create ();
  189. if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, filename))
  190. {
  191. GNUNET_break (0);
  192. GNUNET_CONFIGURATION_destroy (cfg);
  193. return GNUNET_SYSERR;
  194. }
  195. ret = cb (cb_cls, cfg);
  196. GNUNET_CONFIGURATION_destroy (cfg);
  197. return ret;
  198. }
  199. enum GNUNET_GenericReturnValue
  200. GNUNET_CONFIGURATION_deserialize (struct GNUNET_CONFIGURATION_Handle *cfg,
  201. const char *mem,
  202. size_t size,
  203. const char *basedir)
  204. {
  205. char *line;
  206. char *line_orig;
  207. size_t line_size;
  208. char *pos;
  209. unsigned int nr;
  210. size_t r_bytes;
  211. size_t to_read;
  212. size_t i;
  213. int emptyline;
  214. enum GNUNET_GenericReturnValue ret;
  215. char *section;
  216. char *eq;
  217. char *tag;
  218. char *value;
  219. ret = GNUNET_OK;
  220. section = GNUNET_strdup ("");
  221. nr = 0;
  222. r_bytes = 0;
  223. line_orig = NULL;
  224. while (r_bytes < size)
  225. {
  226. GNUNET_free (line_orig);
  227. /* fgets-like behaviour on buffer */
  228. to_read = size - r_bytes;
  229. pos = memchr (&mem[r_bytes], '\n', to_read);
  230. if (NULL == pos)
  231. {
  232. line_orig = GNUNET_strndup (&mem[r_bytes], line_size = to_read);
  233. r_bytes += line_size;
  234. }
  235. else
  236. {
  237. line_orig =
  238. GNUNET_strndup (&mem[r_bytes], line_size = (pos - &mem[r_bytes]));
  239. r_bytes += line_size + 1;
  240. }
  241. line = line_orig;
  242. /* increment line number */
  243. nr++;
  244. /* tabs and '\r' are whitespace */
  245. emptyline = GNUNET_YES;
  246. for (i = 0; i < line_size; i++)
  247. {
  248. if (line[i] == '\t')
  249. line[i] = ' ';
  250. if (line[i] == '\r')
  251. line[i] = ' ';
  252. if (' ' != line[i])
  253. emptyline = GNUNET_NO;
  254. }
  255. /* ignore empty lines */
  256. if (GNUNET_YES == emptyline)
  257. continue;
  258. /* remove tailing whitespace */
  259. for (i = line_size - 1; (i >= 1) && (isspace ((unsigned char) line[i]));
  260. i--)
  261. line[i] = '\0';
  262. /* remove leading whitespace */
  263. for (; line[0] != '\0' && (isspace ((unsigned char) line[0])); line++)
  264. ;
  265. /* ignore comments */
  266. if (('#' == line[0]) || ('%' == line[0]))
  267. continue;
  268. /* handle special "@INLINE@" directive */
  269. if (0 == strncasecmp (line, "@INLINE@ ", strlen ("@INLINE@ ")))
  270. {
  271. /* @INLINE@ value */
  272. value = &line[strlen ("@INLINE@ ")];
  273. if (NULL != basedir)
  274. {
  275. char *fn;
  276. GNUNET_asprintf (&fn, "%s/%s", basedir, value);
  277. if (GNUNET_OK != GNUNET_CONFIGURATION_parse (cfg, fn))
  278. {
  279. GNUNET_free (fn);
  280. ret = GNUNET_SYSERR; /* failed to parse included config */
  281. break;
  282. }
  283. GNUNET_free (fn);
  284. }
  285. else
  286. {
  287. LOG (GNUNET_ERROR_TYPE_DEBUG,
  288. "Ignoring parsing @INLINE@ configurations, not allowed!\n");
  289. ret = GNUNET_SYSERR;
  290. break;
  291. }
  292. continue;
  293. }
  294. if (('[' == line[0]) && (']' == line[line_size - 1]))
  295. {
  296. /* [value] */
  297. line[line_size - 1] = '\0';
  298. value = &line[1];
  299. GNUNET_free (section);
  300. section = GNUNET_strdup (value);
  301. continue;
  302. }
  303. if (NULL != (eq = strchr (line, '=')))
  304. {
  305. /* tag = value */
  306. tag = GNUNET_strndup (line, eq - line);
  307. /* remove tailing whitespace */
  308. for (i = strlen (tag) - 1; (i >= 1) && (isspace ((unsigned char) tag[i]));
  309. i--)
  310. tag[i] = '\0';
  311. /* Strip whitespace */
  312. value = eq + 1;
  313. while (isspace ((unsigned char) value[0]))
  314. value++;
  315. for (i = strlen (value) - 1;
  316. (i >= 1) && (isspace ((unsigned char) value[i]));
  317. i--)
  318. value[i] = '\0';
  319. /* remove quotes */
  320. i = 0;
  321. if (('"' == value[0]) && ('"' == value[strlen (value) - 1]))
  322. {
  323. value[strlen (value) - 1] = '\0';
  324. value++;
  325. }
  326. GNUNET_CONFIGURATION_set_value_string (cfg, section, tag, &value[i]);
  327. GNUNET_free (tag);
  328. continue;
  329. }
  330. /* parse error */
  331. LOG (GNUNET_ERROR_TYPE_WARNING,
  332. _ ("Syntax error while deserializing in line %u\n"),
  333. nr);
  334. ret = GNUNET_SYSERR;
  335. break;
  336. }
  337. GNUNET_free (line_orig);
  338. GNUNET_free (section);
  339. GNUNET_assert ((GNUNET_OK != ret) || (r_bytes == size));
  340. return ret;
  341. }
  342. enum GNUNET_GenericReturnValue
  343. GNUNET_CONFIGURATION_parse (struct GNUNET_CONFIGURATION_Handle *cfg,
  344. const char *filename)
  345. {
  346. uint64_t fs64;
  347. size_t fs;
  348. char *fn;
  349. char *mem;
  350. char *endsep;
  351. int dirty;
  352. enum GNUNET_GenericReturnValue ret;
  353. ssize_t sret;
  354. fn = GNUNET_STRINGS_filename_expand (filename);
  355. LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to parse config file `%s'\n", fn);
  356. if (NULL == fn)
  357. return GNUNET_SYSERR;
  358. dirty = cfg->dirty; /* back up value! */
  359. if (GNUNET_SYSERR ==
  360. GNUNET_DISK_file_size (fn, &fs64, GNUNET_YES, GNUNET_YES))
  361. {
  362. LOG (GNUNET_ERROR_TYPE_WARNING,
  363. "Error while determining the file size of `%s'\n",
  364. fn);
  365. GNUNET_free (fn);
  366. return GNUNET_SYSERR;
  367. }
  368. if (fs64 > SIZE_MAX)
  369. {
  370. GNUNET_break (0); /* File size is more than the heap size */
  371. GNUNET_free (fn);
  372. return GNUNET_SYSERR;
  373. }
  374. fs = fs64;
  375. mem = GNUNET_malloc (fs);
  376. sret = GNUNET_DISK_fn_read (fn, mem, fs);
  377. if ((sret < 0) || (fs != (size_t) sret))
  378. {
  379. LOG (GNUNET_ERROR_TYPE_WARNING, _ ("Error while reading file `%s'\n"), fn);
  380. GNUNET_free (fn);
  381. GNUNET_free (mem);
  382. return GNUNET_SYSERR;
  383. }
  384. LOG (GNUNET_ERROR_TYPE_DEBUG, "Deserializing contents of file `%s'\n", fn);
  385. endsep = strrchr (fn, (int) '/');
  386. if (NULL != endsep)
  387. *endsep = '\0';
  388. ret = GNUNET_CONFIGURATION_deserialize (cfg, mem, fs, fn);
  389. GNUNET_free (fn);
  390. GNUNET_free (mem);
  391. /* restore dirty flag - anything we set in the meantime
  392. * came from disk */
  393. cfg->dirty = dirty;
  394. return ret;
  395. }
  396. enum GNUNET_GenericReturnValue
  397. GNUNET_CONFIGURATION_is_dirty (const struct GNUNET_CONFIGURATION_Handle *cfg)
  398. {
  399. return cfg->dirty;
  400. }
  401. /**
  402. * Should we skip this configuration entry when serializing?
  403. *
  404. * @param sec section name
  405. * @param key key
  406. * @return true if we should skip it
  407. */
  408. static bool
  409. do_skip (const char *sec,
  410. const char *key)
  411. {
  412. if (0 != strcasecmp ("PATHS",
  413. sec))
  414. return false;
  415. return ( (0 == strcasecmp ("DATADIR",
  416. key)) ||
  417. (0 == strcasecmp ("LIBDIR",
  418. key)) ||
  419. (0 == strcasecmp ("BINDIR",
  420. key)) ||
  421. (0 == strcasecmp ("PREFIX",
  422. key)) ||
  423. (0 == strcasecmp ("LOCALEDIR",
  424. key)) ||
  425. (0 == strcasecmp ("ICONDIR",
  426. key)) ||
  427. (0 == strcasecmp ("DOCDIR",
  428. key)) ||
  429. (0 == strcasecmp ("DEFAULTCONFIG",
  430. key)) ||
  431. (0 == strcasecmp ("LIBEXECDIR",
  432. key)) );
  433. }
  434. char *
  435. GNUNET_CONFIGURATION_serialize (const struct GNUNET_CONFIGURATION_Handle *cfg,
  436. size_t *size)
  437. {
  438. char *mem;
  439. char *cbuf;
  440. char *val;
  441. char *pos;
  442. size_t m_size;
  443. size_t c_size;
  444. /* Pass1 : calculate the buffer size required */
  445. m_size = 0;
  446. for (struct ConfigSection *sec = cfg->sections;
  447. NULL != sec;
  448. sec = sec->next)
  449. {
  450. /* For each section we need to add 3 characters: {'[',']','\n'} */
  451. m_size += strlen (sec->name) + 3;
  452. for (struct ConfigEntry *ent = sec->entries;
  453. NULL != ent;
  454. ent = ent->next)
  455. {
  456. if (do_skip (sec->name,
  457. ent->key))
  458. continue;
  459. if (NULL != ent->val)
  460. {
  461. /* if val has any '\n' then they occupy +1 character as '\n'->'\\','n' */
  462. pos = ent->val;
  463. while (NULL != (pos = strstr (pos, "\n")))
  464. {
  465. m_size++;
  466. pos++;
  467. }
  468. /* For each key = value pair we need to add 4 characters (2
  469. spaces and 1 equal-to character and 1 new line) */
  470. m_size += strlen (ent->key) + strlen (ent->val) + 4;
  471. }
  472. }
  473. /* A new line after section end */
  474. m_size++;
  475. }
  476. /* Pass2: Allocate memory and write the configuration to it */
  477. mem = GNUNET_malloc (m_size);
  478. c_size = 0;
  479. *size = c_size;
  480. for (struct ConfigSection *sec = cfg->sections;
  481. NULL != sec;
  482. sec = sec->next)
  483. {
  484. int len;
  485. len = GNUNET_asprintf (&cbuf,
  486. "[%s]\n",
  487. sec->name);
  488. GNUNET_assert (0 < len);
  489. GNUNET_memcpy (mem + c_size,
  490. cbuf,
  491. len);
  492. c_size += len;
  493. GNUNET_free (cbuf);
  494. for (struct ConfigEntry *ent = sec->entries;
  495. NULL != ent;
  496. ent = ent->next)
  497. {
  498. if (do_skip (sec->name,
  499. ent->key))
  500. continue;
  501. if (NULL != ent->val)
  502. {
  503. val = GNUNET_malloc (strlen (ent->val) * 2 + 1);
  504. strcpy (val, ent->val);
  505. while (NULL != (pos = strstr (val, "\n")))
  506. {
  507. memmove (&pos[2], &pos[1], strlen (&pos[1]));
  508. pos[0] = '\\';
  509. pos[1] = 'n';
  510. }
  511. len = GNUNET_asprintf (&cbuf, "%s = %s\n", ent->key, val);
  512. GNUNET_free (val);
  513. GNUNET_memcpy (mem + c_size, cbuf, len);
  514. c_size += len;
  515. GNUNET_free (cbuf);
  516. }
  517. }
  518. GNUNET_memcpy (mem + c_size, "\n", 1);
  519. c_size++;
  520. }
  521. GNUNET_assert (c_size == m_size);
  522. *size = c_size;
  523. return mem;
  524. }
  525. enum GNUNET_GenericReturnValue
  526. GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *cfg,
  527. const char *filename)
  528. {
  529. char *fn;
  530. char *cfg_buf;
  531. size_t size;
  532. fn = GNUNET_STRINGS_filename_expand (filename);
  533. if (fn == NULL)
  534. return GNUNET_SYSERR;
  535. if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (fn))
  536. {
  537. GNUNET_free (fn);
  538. return GNUNET_SYSERR;
  539. }
  540. cfg_buf = GNUNET_CONFIGURATION_serialize (cfg,
  541. &size);
  542. {
  543. struct GNUNET_DISK_FileHandle *h;
  544. h = GNUNET_DISK_file_open (fn,
  545. GNUNET_DISK_OPEN_WRITE
  546. | GNUNET_DISK_OPEN_TRUNCATE
  547. | GNUNET_DISK_OPEN_CREATE,
  548. GNUNET_DISK_PERM_USER_READ
  549. | GNUNET_DISK_PERM_USER_WRITE
  550. | GNUNET_DISK_PERM_GROUP_READ
  551. | GNUNET_DISK_PERM_GROUP_WRITE);
  552. if (NULL == h)
  553. {
  554. GNUNET_free (fn);
  555. GNUNET_free (cfg_buf);
  556. return GNUNET_SYSERR;
  557. }
  558. if (((ssize_t) size) !=
  559. GNUNET_DISK_file_write (h,
  560. cfg_buf,
  561. size))
  562. {
  563. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
  564. "write",
  565. fn);
  566. GNUNET_DISK_file_close (h);
  567. (void) GNUNET_DISK_directory_remove (fn);
  568. GNUNET_free (fn);
  569. GNUNET_free (cfg_buf);
  570. cfg->dirty = GNUNET_SYSERR; /* last write failed */
  571. return GNUNET_SYSERR;
  572. }
  573. GNUNET_assert (GNUNET_OK ==
  574. GNUNET_DISK_file_close (h));
  575. }
  576. GNUNET_free (fn);
  577. GNUNET_free (cfg_buf);
  578. cfg->dirty = GNUNET_NO; /* last write succeeded */
  579. return GNUNET_OK;
  580. }
  581. void
  582. GNUNET_CONFIGURATION_iterate (const struct GNUNET_CONFIGURATION_Handle *cfg,
  583. GNUNET_CONFIGURATION_Iterator iter,
  584. void *iter_cls)
  585. {
  586. for (struct ConfigSection *spos = cfg->sections;
  587. NULL != spos;
  588. spos = spos->next)
  589. for (struct ConfigEntry *epos = spos->entries;
  590. NULL != epos;
  591. epos = epos->next)
  592. if (NULL != epos->val)
  593. iter (iter_cls,
  594. spos->name,
  595. epos->key,
  596. epos->val);
  597. }
  598. void
  599. GNUNET_CONFIGURATION_iterate_section_values (
  600. const struct GNUNET_CONFIGURATION_Handle *cfg,
  601. const char *section,
  602. GNUNET_CONFIGURATION_Iterator iter,
  603. void *iter_cls)
  604. {
  605. struct ConfigSection *spos;
  606. struct ConfigEntry *epos;
  607. spos = cfg->sections;
  608. while ((spos != NULL) && (0 != strcasecmp (spos->name, section)))
  609. spos = spos->next;
  610. if (NULL == spos)
  611. return;
  612. for (epos = spos->entries; NULL != epos; epos = epos->next)
  613. if (NULL != epos->val)
  614. iter (iter_cls, spos->name, epos->key, epos->val);
  615. }
  616. void
  617. GNUNET_CONFIGURATION_iterate_sections (
  618. const struct GNUNET_CONFIGURATION_Handle *cfg,
  619. GNUNET_CONFIGURATION_Section_Iterator iter,
  620. void *iter_cls)
  621. {
  622. struct ConfigSection *spos;
  623. struct ConfigSection *next;
  624. next = cfg->sections;
  625. while (next != NULL)
  626. {
  627. spos = next;
  628. next = spos->next;
  629. iter (iter_cls, spos->name);
  630. }
  631. }
  632. void
  633. GNUNET_CONFIGURATION_remove_section (struct GNUNET_CONFIGURATION_Handle *cfg,
  634. const char *section)
  635. {
  636. struct ConfigSection *spos;
  637. struct ConfigSection *prev;
  638. struct ConfigEntry *ent;
  639. prev = NULL;
  640. spos = cfg->sections;
  641. while (NULL != spos)
  642. {
  643. if (0 == strcasecmp (section, spos->name))
  644. {
  645. if (NULL == prev)
  646. cfg->sections = spos->next;
  647. else
  648. prev->next = spos->next;
  649. while (NULL != (ent = spos->entries))
  650. {
  651. spos->entries = ent->next;
  652. GNUNET_free (ent->key);
  653. GNUNET_free (ent->val);
  654. GNUNET_free (ent);
  655. cfg->dirty = GNUNET_YES;
  656. }
  657. GNUNET_free (spos->name);
  658. GNUNET_free (spos);
  659. return;
  660. }
  661. prev = spos;
  662. spos = spos->next;
  663. }
  664. }
  665. /**
  666. * Copy a configuration value to the given target configuration.
  667. * Overwrites existing entries.
  668. *
  669. * @param cls the destination configuration (`struct GNUNET_CONFIGURATION_Handle *`)
  670. * @param section section for the value
  671. * @param option option name of the value
  672. * @param value value to copy
  673. */
  674. static void
  675. copy_entry (void *cls,
  676. const char *section,
  677. const char *option,
  678. const char *value)
  679. {
  680. struct GNUNET_CONFIGURATION_Handle *dst = cls;
  681. GNUNET_CONFIGURATION_set_value_string (dst, section, option, value);
  682. }
  683. struct GNUNET_CONFIGURATION_Handle *
  684. GNUNET_CONFIGURATION_dup (const struct GNUNET_CONFIGURATION_Handle *cfg)
  685. {
  686. struct GNUNET_CONFIGURATION_Handle *ret;
  687. ret = GNUNET_CONFIGURATION_create ();
  688. GNUNET_CONFIGURATION_iterate (cfg, &copy_entry, ret);
  689. return ret;
  690. }
  691. /**
  692. * Find a section entry from a configuration.
  693. *
  694. * @param cfg configuration to search in
  695. * @param section name of the section to look for
  696. * @return matching entry, NULL if not found
  697. */
  698. static struct ConfigSection *
  699. find_section (const struct GNUNET_CONFIGURATION_Handle *cfg,
  700. const char *section)
  701. {
  702. struct ConfigSection *pos;
  703. pos = cfg->sections;
  704. while ((pos != NULL) && (0 != strcasecmp (section, pos->name)))
  705. pos = pos->next;
  706. return pos;
  707. }
  708. /**
  709. * Find an entry from a configuration.
  710. *
  711. * @param cfg handle to the configuration
  712. * @param section section the option is in
  713. * @param key the option
  714. * @return matching entry, NULL if not found
  715. */
  716. static struct ConfigEntry *
  717. find_entry (const struct GNUNET_CONFIGURATION_Handle *cfg,
  718. const char *section,
  719. const char *key)
  720. {
  721. struct ConfigSection *sec;
  722. struct ConfigEntry *pos;
  723. if (NULL == (sec = find_section (cfg, section)))
  724. return NULL;
  725. pos = sec->entries;
  726. while ((pos != NULL) && (0 != strcasecmp (key, pos->key)))
  727. pos = pos->next;
  728. return pos;
  729. }
  730. /**
  731. * A callback function, compares entries from two configurations
  732. * (default against a new configuration) and write the diffs in a
  733. * diff-configuration object (the callback object).
  734. *
  735. * @param cls the diff configuration (`struct DiffHandle *`)
  736. * @param section section for the value (of the default conf.)
  737. * @param option option name of the value (of the default conf.)
  738. * @param value value to copy (of the default conf.)
  739. */
  740. static void
  741. compare_entries (void *cls,
  742. const char *section,
  743. const char *option,
  744. const char *value)
  745. {
  746. struct DiffHandle *dh = cls;
  747. struct ConfigEntry *entNew;
  748. entNew = find_entry (dh->cfg_default, section, option);
  749. if ((NULL != entNew) && (NULL != entNew->val) &&
  750. (0 == strcmp (entNew->val, value)))
  751. return;
  752. GNUNET_CONFIGURATION_set_value_string (dh->cfgDiff, section, option, value);
  753. }
  754. struct GNUNET_CONFIGURATION_Handle *
  755. GNUNET_CONFIGURATION_get_diff (
  756. const struct GNUNET_CONFIGURATION_Handle *cfg_default,
  757. const struct GNUNET_CONFIGURATION_Handle *cfg_new)
  758. {
  759. struct DiffHandle diffHandle;
  760. diffHandle.cfgDiff = GNUNET_CONFIGURATION_create ();
  761. diffHandle.cfg_default = cfg_default;
  762. GNUNET_CONFIGURATION_iterate (cfg_new, &compare_entries, &diffHandle);
  763. return diffHandle.cfgDiff;
  764. }
  765. enum GNUNET_GenericReturnValue
  766. GNUNET_CONFIGURATION_write_diffs (
  767. const struct GNUNET_CONFIGURATION_Handle *cfg_default,
  768. const struct GNUNET_CONFIGURATION_Handle *cfg_new,
  769. const char *filename)
  770. {
  771. int ret;
  772. struct GNUNET_CONFIGURATION_Handle *diff;
  773. diff = GNUNET_CONFIGURATION_get_diff (cfg_default, cfg_new);
  774. ret = GNUNET_CONFIGURATION_write (diff, filename);
  775. GNUNET_CONFIGURATION_destroy (diff);
  776. return ret;
  777. }
  778. void
  779. GNUNET_CONFIGURATION_set_value_string (struct GNUNET_CONFIGURATION_Handle *cfg,
  780. const char *section,
  781. const char *option,
  782. const char *value)
  783. {
  784. struct ConfigSection *sec;
  785. struct ConfigEntry *e;
  786. char *nv;
  787. e = find_entry (cfg, section, option);
  788. if (NULL != e)
  789. {
  790. if (NULL == value)
  791. {
  792. GNUNET_free (e->val);
  793. e->val = NULL;
  794. }
  795. else
  796. {
  797. nv = GNUNET_strdup (value);
  798. GNUNET_free (e->val);
  799. e->val = nv;
  800. }
  801. return;
  802. }
  803. sec = find_section (cfg, section);
  804. if (sec == NULL)
  805. {
  806. sec = GNUNET_new (struct ConfigSection);
  807. sec->name = GNUNET_strdup (section);
  808. sec->next = cfg->sections;
  809. cfg->sections = sec;
  810. }
  811. e = GNUNET_new (struct ConfigEntry);
  812. e->key = GNUNET_strdup (option);
  813. e->val = GNUNET_strdup (value);
  814. e->next = sec->entries;
  815. sec->entries = e;
  816. }
  817. void
  818. GNUNET_CONFIGURATION_set_value_number (struct GNUNET_CONFIGURATION_Handle *cfg,
  819. const char *section,
  820. const char *option,
  821. unsigned long long number)
  822. {
  823. char s[64];
  824. GNUNET_snprintf (s, 64, "%llu", number);
  825. GNUNET_CONFIGURATION_set_value_string (cfg, section, option, s);
  826. }
  827. enum GNUNET_GenericReturnValue
  828. GNUNET_CONFIGURATION_get_value_number (
  829. const struct GNUNET_CONFIGURATION_Handle *cfg,
  830. const char *section,
  831. const char *option,
  832. unsigned long long *number)
  833. {
  834. struct ConfigEntry *e;
  835. char dummy[2];
  836. if (NULL == (e = find_entry (cfg, section, option)))
  837. return GNUNET_SYSERR;
  838. if (NULL == e->val)
  839. return GNUNET_SYSERR;
  840. if (1 != sscanf (e->val, "%llu%1s", number, dummy))
  841. return GNUNET_SYSERR;
  842. return GNUNET_OK;
  843. }
  844. enum GNUNET_GenericReturnValue
  845. GNUNET_CONFIGURATION_get_value_float (
  846. const struct GNUNET_CONFIGURATION_Handle *cfg,
  847. const char *section,
  848. const char *option,
  849. float *number)
  850. {
  851. struct ConfigEntry *e;
  852. char dummy[2];
  853. if (NULL == (e = find_entry (cfg, section, option)))
  854. return GNUNET_SYSERR;
  855. if (NULL == e->val)
  856. return GNUNET_SYSERR;
  857. if (1 != sscanf (e->val, "%f%1s", number, dummy))
  858. return GNUNET_SYSERR;
  859. return GNUNET_OK;
  860. }
  861. enum GNUNET_GenericReturnValue
  862. GNUNET_CONFIGURATION_get_value_time (
  863. const struct GNUNET_CONFIGURATION_Handle *cfg,
  864. const char *section,
  865. const char *option,
  866. struct GNUNET_TIME_Relative *time)
  867. {
  868. struct ConfigEntry *e;
  869. int ret;
  870. if (NULL == (e = find_entry (cfg, section, option)))
  871. return GNUNET_SYSERR;
  872. if (NULL == e->val)
  873. return GNUNET_SYSERR;
  874. ret = GNUNET_STRINGS_fancy_time_to_relative (e->val, time);
  875. if (GNUNET_OK != ret)
  876. GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
  877. section,
  878. option,
  879. _ ("Not a valid relative time specification"));
  880. return ret;
  881. }
  882. enum GNUNET_GenericReturnValue
  883. GNUNET_CONFIGURATION_get_value_size (
  884. const struct GNUNET_CONFIGURATION_Handle *cfg,
  885. const char *section,
  886. const char *option,
  887. unsigned long long *size)
  888. {
  889. struct ConfigEntry *e;
  890. if (NULL == (e = find_entry (cfg, section, option)))
  891. return GNUNET_SYSERR;
  892. if (NULL == e->val)
  893. return GNUNET_SYSERR;
  894. return GNUNET_STRINGS_fancy_size_to_bytes (e->val, size);
  895. }
  896. /**
  897. * Get a configuration value that should be a string.
  898. *
  899. * @param cfg configuration to inspect
  900. * @param section section of interest
  901. * @param option option of interest
  902. * @param value will be set to a freshly allocated configuration
  903. * value, or NULL if option is not specified
  904. * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  905. */
  906. enum GNUNET_GenericReturnValue
  907. GNUNET_CONFIGURATION_get_value_string (
  908. const struct GNUNET_CONFIGURATION_Handle *cfg,
  909. const char *section,
  910. const char *option,
  911. char **value)
  912. {
  913. struct ConfigEntry *e;
  914. if ((NULL == (e = find_entry (cfg, section, option))) || (NULL == e->val))
  915. {
  916. *value = NULL;
  917. return GNUNET_SYSERR;
  918. }
  919. *value = GNUNET_strdup (e->val);
  920. return GNUNET_OK;
  921. }
  922. enum GNUNET_GenericReturnValue
  923. GNUNET_CONFIGURATION_get_value_choice (
  924. const struct GNUNET_CONFIGURATION_Handle *cfg,
  925. const char *section,
  926. const char *option,
  927. const char *const *choices,
  928. const char **value)
  929. {
  930. struct ConfigEntry *e;
  931. unsigned int i;
  932. if (NULL == (e = find_entry (cfg, section, option)))
  933. return GNUNET_SYSERR;
  934. for (i = 0; NULL != choices[i]; i++)
  935. if (0 == strcasecmp (choices[i], e->val))
  936. break;
  937. if (NULL == choices[i])
  938. {
  939. LOG (GNUNET_ERROR_TYPE_ERROR,
  940. _ ("Configuration value '%s' for '%s'"
  941. " in section '%s' is not in set of legal choices\n"),
  942. e->val,
  943. option,
  944. section);
  945. return GNUNET_SYSERR;
  946. }
  947. *value = choices[i];
  948. return GNUNET_OK;
  949. }
  950. enum GNUNET_GenericReturnValue
  951. GNUNET_CONFIGURATION_get_data (const struct GNUNET_CONFIGURATION_Handle *cfg,
  952. const char *section,
  953. const char *option,
  954. void *buf,
  955. size_t buf_size)
  956. {
  957. char *enc;
  958. int res;
  959. size_t data_size;
  960. if (GNUNET_OK !=
  961. (res =
  962. GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &enc)))
  963. return res;
  964. data_size = (strlen (enc) * 5) / 8;
  965. if (data_size != buf_size)
  966. {
  967. GNUNET_free (enc);
  968. return GNUNET_SYSERR;
  969. }
  970. if (GNUNET_OK !=
  971. GNUNET_STRINGS_string_to_data (enc, strlen (enc), buf, buf_size))
  972. {
  973. GNUNET_free (enc);
  974. return GNUNET_SYSERR;
  975. }
  976. GNUNET_free (enc);
  977. return GNUNET_OK;
  978. }
  979. enum GNUNET_GenericReturnValue
  980. GNUNET_CONFIGURATION_have_value (const struct GNUNET_CONFIGURATION_Handle *cfg,
  981. const char *section,
  982. const char *option)
  983. {
  984. struct ConfigEntry *e;
  985. if ((NULL == (e = find_entry (cfg, section, option))) || (NULL == e->val))
  986. return GNUNET_NO;
  987. return GNUNET_YES;
  988. }
  989. /**
  990. * Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR"
  991. * where either in the "PATHS" section or the environment "FOO" is
  992. * set to "DIRECTORY". We also support default expansion,
  993. * i.e. ${VARIABLE:-default} will expand to $VARIABLE if VARIABLE is
  994. * set in PATHS or the environment, and otherwise to "default". Note
  995. * that "default" itself can also be a $-expression, thus
  996. * "${VAR1:-{$VAR2}}" will expand to VAR1 and if that is not defined
  997. * to VAR2.
  998. *
  999. * @param cfg configuration to use for path expansion
  1000. * @param orig string to $-expand (will be freed!)
  1001. * @param depth recursion depth, used to detect recursive expansions
  1002. * @return $-expanded string, never NULL unless @a orig was NULL
  1003. */
  1004. static char *
  1005. expand_dollar (const struct GNUNET_CONFIGURATION_Handle *cfg,
  1006. char *orig,
  1007. unsigned int depth)
  1008. {
  1009. char *prefix;
  1010. char *result;
  1011. char *start;
  1012. const char *post;
  1013. const char *env;
  1014. char *def;
  1015. char *end;
  1016. unsigned int lopen;
  1017. char erased_char;
  1018. char *erased_pos;
  1019. size_t len;
  1020. if (NULL == orig)
  1021. return NULL;
  1022. if (depth > 128)
  1023. {
  1024. LOG (GNUNET_ERROR_TYPE_WARNING,
  1025. _ (
  1026. "Recursive expansion suspected, aborting $-expansion for term `%s'\n"),
  1027. orig);
  1028. return orig;
  1029. }
  1030. LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to $-expand %s\n", orig);
  1031. if ('$' != orig[0])
  1032. {
  1033. LOG (GNUNET_ERROR_TYPE_DEBUG, "Doesn't start with $ - not expanding\n");
  1034. return orig;
  1035. }
  1036. erased_char = 0;
  1037. erased_pos = NULL;
  1038. if ('{' == orig[1])
  1039. {
  1040. start = &orig[2];
  1041. lopen = 1;
  1042. end = &orig[1];
  1043. while (lopen > 0)
  1044. {
  1045. end++;
  1046. switch (*end)
  1047. {
  1048. case '}':
  1049. lopen--;
  1050. break;
  1051. case '{':
  1052. lopen++;
  1053. break;
  1054. case '\0':
  1055. LOG (GNUNET_ERROR_TYPE_WARNING,
  1056. _ ("Missing closing `%s' in option `%s'\n"),
  1057. "}",
  1058. orig);
  1059. return orig;
  1060. default:
  1061. break;
  1062. }
  1063. }
  1064. erased_char = *end;
  1065. erased_pos = end;
  1066. *end = '\0';
  1067. post = end + 1;
  1068. def = strchr (orig, ':');
  1069. if (NULL != def)
  1070. {
  1071. *def = '\0';
  1072. def++;
  1073. if (('-' == *def) || ('=' == *def))
  1074. def++;
  1075. def = GNUNET_strdup (def);
  1076. }
  1077. }
  1078. else
  1079. {
  1080. int i;
  1081. start = &orig[1];
  1082. def = NULL;
  1083. i = 0;
  1084. while ((orig[i] != '/') && (orig[i] != '\\') && (orig[i] != '\0') &&
  1085. (orig[i] != ' '))
  1086. i++;
  1087. if (orig[i] == '\0')
  1088. {
  1089. post = "";
  1090. }
  1091. else
  1092. {
  1093. erased_char = orig[i];
  1094. erased_pos = &orig[i];
  1095. orig[i] = '\0';
  1096. post = &orig[i + 1];
  1097. }
  1098. }
  1099. LOG (GNUNET_ERROR_TYPE_DEBUG,
  1100. "Split into `%s' and `%s' with default %s\n",
  1101. start,
  1102. post,
  1103. def);
  1104. if (GNUNET_OK !=
  1105. GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", start, &prefix))
  1106. {
  1107. if (NULL == (env = getenv (start)))
  1108. {
  1109. /* try default */
  1110. def = expand_dollar (cfg, def, depth + 1);
  1111. env = def;
  1112. }
  1113. if (NULL == env)
  1114. {
  1115. start = GNUNET_strdup (start);
  1116. if (erased_pos)
  1117. *erased_pos = erased_char;
  1118. LOG (GNUNET_ERROR_TYPE_WARNING,
  1119. _ (
  1120. "Failed to expand `%s' in `%s' as it is neither found in [PATHS] nor defined as an environmental variable\n"),
  1121. start,
  1122. orig);
  1123. GNUNET_free (start);
  1124. return orig;
  1125. }
  1126. prefix = GNUNET_strdup (env);
  1127. }
  1128. prefix = GNUNET_CONFIGURATION_expand_dollar (cfg, prefix);
  1129. if ((erased_pos) && ('}' != erased_char))
  1130. {
  1131. len = strlen (prefix) + 1;
  1132. prefix = GNUNET_realloc (prefix, len + 1);
  1133. prefix[len - 1] = erased_char;
  1134. prefix[len] = '\0';
  1135. }
  1136. result = GNUNET_malloc (strlen (prefix) + strlen (post) + 1);
  1137. strcpy (result, prefix);
  1138. strcat (result, post);
  1139. GNUNET_free (def);
  1140. GNUNET_free (prefix);
  1141. GNUNET_free (orig);
  1142. return result;
  1143. }
  1144. char *
  1145. GNUNET_CONFIGURATION_expand_dollar (
  1146. const struct GNUNET_CONFIGURATION_Handle *cfg,
  1147. char *orig)
  1148. {
  1149. char *dup;
  1150. size_t i;
  1151. size_t len;
  1152. for (i = 0; '\0' != orig[i]; i++)
  1153. {
  1154. if ('$' != orig[i])
  1155. continue;
  1156. dup = GNUNET_strdup (orig + i);
  1157. dup = expand_dollar (cfg, dup, 0);
  1158. GNUNET_assert (NULL != dup); /* make compiler happy */
  1159. len = strlen (dup) + 1;
  1160. orig = GNUNET_realloc (orig, i + len);
  1161. GNUNET_memcpy (orig + i, dup, len);
  1162. GNUNET_free (dup);
  1163. }
  1164. return orig;
  1165. }
  1166. enum GNUNET_GenericReturnValue
  1167. GNUNET_CONFIGURATION_get_value_filename (
  1168. const struct GNUNET_CONFIGURATION_Handle *cfg,
  1169. const char *section,
  1170. const char *option,
  1171. char **value)
  1172. {
  1173. char *tmp;
  1174. if (GNUNET_OK !=
  1175. GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &tmp))
  1176. {
  1177. LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to retrieve filename\n");
  1178. *value = NULL;
  1179. return GNUNET_SYSERR;
  1180. }
  1181. tmp = GNUNET_CONFIGURATION_expand_dollar (cfg, tmp);
  1182. *value = GNUNET_STRINGS_filename_expand (tmp);
  1183. GNUNET_free (tmp);
  1184. if (*value == NULL)
  1185. return GNUNET_SYSERR;
  1186. return GNUNET_OK;
  1187. }
  1188. enum GNUNET_GenericReturnValue
  1189. GNUNET_CONFIGURATION_get_value_yesno (
  1190. const struct GNUNET_CONFIGURATION_Handle *cfg,
  1191. const char *section,
  1192. const char *option)
  1193. {
  1194. static const char *yesno[] = { "YES", "NO", NULL };
  1195. const char *val;
  1196. int ret;
  1197. ret =
  1198. GNUNET_CONFIGURATION_get_value_choice (cfg, section, option, yesno, &val);
  1199. if (ret == GNUNET_SYSERR)
  1200. return ret;
  1201. if (val == yesno[0])
  1202. return GNUNET_YES;
  1203. return GNUNET_NO;
  1204. }
  1205. int
  1206. GNUNET_CONFIGURATION_iterate_value_filenames (
  1207. const struct GNUNET_CONFIGURATION_Handle *cfg,
  1208. const char *section,
  1209. const char *option,
  1210. GNUNET_FileNameCallback cb,
  1211. void *cb_cls)
  1212. {
  1213. char *list;
  1214. char *pos;
  1215. char *end;
  1216. char old;
  1217. int ret;
  1218. if (GNUNET_OK !=
  1219. GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list))
  1220. return 0;
  1221. GNUNET_assert (list != NULL);
  1222. ret = 0;
  1223. pos = list;
  1224. while (1)
  1225. {
  1226. while (pos[0] == ' ')
  1227. pos++;
  1228. if (strlen (pos) == 0)
  1229. break;
  1230. end = pos + 1;
  1231. while ((end[0] != ' ') && (end[0] != '\0'))
  1232. {
  1233. if (end[0] == '\\')
  1234. {
  1235. switch (end[1])
  1236. {
  1237. case '\\':
  1238. case ' ':
  1239. memmove (end, &end[1], strlen (&end[1]) + 1);
  1240. case '\0':
  1241. /* illegal, but just keep it */
  1242. break;
  1243. default:
  1244. /* illegal, but just ignore that there was a '/' */
  1245. break;
  1246. }
  1247. }
  1248. end++;
  1249. }
  1250. old = end[0];
  1251. end[0] = '\0';
  1252. if (strlen (pos) > 0)
  1253. {
  1254. ret++;
  1255. if ((cb != NULL) && (GNUNET_OK != cb (cb_cls, pos)))
  1256. {
  1257. ret = GNUNET_SYSERR;
  1258. break;
  1259. }
  1260. }
  1261. if (old == '\0')
  1262. break;
  1263. pos = end + 1;
  1264. }
  1265. GNUNET_free (list);
  1266. return ret;
  1267. }
  1268. /**
  1269. * FIXME.
  1270. *
  1271. * @param value FIXME
  1272. * @return FIXME
  1273. */
  1274. static char *
  1275. escape_name (const char *value)
  1276. {
  1277. char *escaped;
  1278. const char *rpos;
  1279. char *wpos;
  1280. escaped = GNUNET_malloc (strlen (value) * 2 + 1);
  1281. memset (escaped, 0, strlen (value) * 2 + 1);
  1282. rpos = value;
  1283. wpos = escaped;
  1284. while (rpos[0] != '\0')
  1285. {
  1286. switch (rpos[0])
  1287. {
  1288. case '\\':
  1289. case ' ':
  1290. wpos[0] = '\\';
  1291. wpos[1] = rpos[0];
  1292. wpos += 2;
  1293. break;
  1294. default:
  1295. wpos[0] = rpos[0];
  1296. wpos++;
  1297. }
  1298. rpos++;
  1299. }
  1300. return escaped;
  1301. }
  1302. /**
  1303. * FIXME.
  1304. *
  1305. * @param cls string we compare with (const char*)
  1306. * @param fn filename we are currently looking at
  1307. * @return #GNUNET_OK if the names do not match, #GNUNET_SYSERR if they do
  1308. */
  1309. static enum GNUNET_GenericReturnValue
  1310. test_match (void *cls, const char *fn)
  1311. {
  1312. const char *of = cls;
  1313. return (0 == strcmp (of, fn)) ? GNUNET_SYSERR : GNUNET_OK;
  1314. }
  1315. enum GNUNET_GenericReturnValue
  1316. GNUNET_CONFIGURATION_append_value_filename (
  1317. struct GNUNET_CONFIGURATION_Handle *cfg,
  1318. const char *section,
  1319. const char *option,
  1320. const char *value)
  1321. {
  1322. char *escaped;
  1323. char *old;
  1324. char *nw;
  1325. if (GNUNET_SYSERR ==
  1326. GNUNET_CONFIGURATION_iterate_value_filenames (cfg,
  1327. section,
  1328. option,
  1329. &test_match,
  1330. (void *) value))
  1331. return GNUNET_NO; /* already exists */
  1332. if (GNUNET_OK !=
  1333. GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &old))
  1334. old = GNUNET_strdup ("");
  1335. escaped = escape_name (value);
  1336. nw = GNUNET_malloc (strlen (old) + strlen (escaped) + 2);
  1337. strcpy (nw, old);
  1338. if (strlen (old) > 0)
  1339. strcat (nw, " ");
  1340. strcat (nw, escaped);
  1341. GNUNET_CONFIGURATION_set_value_string (cfg, section, option, nw);
  1342. GNUNET_free (old);
  1343. GNUNET_free (nw);
  1344. GNUNET_free (escaped);
  1345. return GNUNET_OK;
  1346. }
  1347. enum GNUNET_GenericReturnValue
  1348. GNUNET_CONFIGURATION_remove_value_filename (
  1349. struct GNUNET_CONFIGURATION_Handle *cfg,
  1350. const char *section,
  1351. const char *option,
  1352. const char *value)
  1353. {
  1354. char *list;
  1355. char *pos;
  1356. char *end;
  1357. char *match;
  1358. char old;
  1359. if (GNUNET_OK !=
  1360. GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list))
  1361. return GNUNET_NO;
  1362. match = escape_name (value);
  1363. pos = list;
  1364. while (1)
  1365. {
  1366. while (pos[0] == ' ')
  1367. pos++;
  1368. if (strlen (pos) == 0)
  1369. break;
  1370. end = pos + 1;
  1371. while ((end[0] != ' ') && (end[0] != '\0'))
  1372. {
  1373. if (end[0] == '\\')
  1374. {
  1375. switch (end[1])
  1376. {
  1377. case '\\':
  1378. case ' ':
  1379. end++;
  1380. break;
  1381. case '\0':
  1382. /* illegal, but just keep it */
  1383. break;
  1384. default:
  1385. /* illegal, but just ignore that there was a '/' */
  1386. break;
  1387. }
  1388. }
  1389. end++;
  1390. }
  1391. old = end[0];
  1392. end[0] = '\0';
  1393. if (0 == strcmp (pos, match))
  1394. {
  1395. if (old != '\0')
  1396. memmove (pos, &end[1], strlen (&end[1]) + 1);
  1397. else
  1398. {
  1399. if (pos != list)
  1400. pos[-1] = '\0';
  1401. else
  1402. pos[0] = '\0';
  1403. }
  1404. GNUNET_CONFIGURATION_set_value_string (cfg, section, option, list);
  1405. GNUNET_free (list);
  1406. GNUNET_free (match);
  1407. return GNUNET_OK;
  1408. }
  1409. if (old == '\0')
  1410. break;
  1411. end[0] = old;
  1412. pos = end + 1;
  1413. }
  1414. GNUNET_free (list);
  1415. GNUNET_free (match);
  1416. return GNUNET_NO;
  1417. }
  1418. /**
  1419. * Wrapper around #GNUNET_CONFIGURATION_parse. Called on each
  1420. * file in a directory, we trigger parsing on those files that
  1421. * end with ".conf".
  1422. *
  1423. * @param cls the cfg
  1424. * @param filename file to parse
  1425. * @return #GNUNET_OK on success
  1426. */
  1427. static enum GNUNET_GenericReturnValue
  1428. parse_configuration_file (void *cls, const char *filename)
  1429. {
  1430. struct GNUNET_CONFIGURATION_Handle *cfg = cls;
  1431. char *ext;
  1432. /* Examine file extension */
  1433. ext = strrchr (filename, '.');
  1434. if ((NULL == ext) || (0 != strcmp (ext, ".conf")))
  1435. {
  1436. GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Skipping file `%s'\n", filename);
  1437. return GNUNET_OK;
  1438. }
  1439. return GNUNET_CONFIGURATION_parse (cfg, filename);
  1440. }
  1441. enum GNUNET_GenericReturnValue
  1442. GNUNET_CONFIGURATION_load_from (struct GNUNET_CONFIGURATION_Handle *cfg,
  1443. const char *defaults_d)
  1444. {
  1445. if (GNUNET_SYSERR ==
  1446. GNUNET_DISK_directory_scan (defaults_d, &parse_configuration_file, cfg))
  1447. return GNUNET_SYSERR; /* no configuration at all found */
  1448. return GNUNET_OK;
  1449. }
  1450. struct GNUNET_CONFIGURATION_Handle *
  1451. GNUNET_CONFIGURATION_default (void)
  1452. {
  1453. const struct GNUNET_OS_ProjectData *pd = GNUNET_OS_project_data_get ();
  1454. const struct GNUNET_OS_ProjectData *dpd = GNUNET_OS_project_data_default ();
  1455. const char *xdg = getenv ("XDG_CONFIG_HOME");
  1456. char *cfgname = NULL;
  1457. struct GNUNET_CONFIGURATION_Handle *cfg;
  1458. GNUNET_OS_init (dpd);
  1459. cfg = GNUNET_CONFIGURATION_create ();
  1460. if (NULL != xdg)
  1461. GNUNET_asprintf (&cfgname, "%s/%s", xdg, pd->config_file);
  1462. else
  1463. cfgname = GNUNET_strdup (pd->user_config_file);
  1464. if (GNUNET_OK !=
  1465. GNUNET_CONFIGURATION_load (cfg, cfgname))
  1466. {
  1467. GNUNET_OS_init (pd);
  1468. GNUNET_CONFIGURATION_destroy (cfg);
  1469. GNUNET_free (cfgname);
  1470. return NULL;
  1471. }
  1472. GNUNET_free (cfgname);
  1473. GNUNET_OS_init (pd);
  1474. return cfg;
  1475. }
  1476. /* end of configuration.c */