aboutsummaryrefslogtreecommitdiff
path: root/src/util/configuration.c
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2021-07-28 14:31:38 +0200
committerFlorian Dold <florian@dold.me>2021-07-28 15:27:39 +0200
commit7615d46b09275383bd244a0ef1d94b3a77559b88 (patch)
treef6452173470ae80b186a4ee6da24d1d88d5033f2 /src/util/configuration.c
parent391794a460140192b3466765ebc63797cea44000 (diff)
downloadgnunet-7615d46b09275383bd244a0ef1d94b3a77559b88.tar.gz
gnunet-7615d46b09275383bd244a0ef1d94b3a77559b88.zip
implement config inline globbing
Diffstat (limited to 'src/util/configuration.c')
-rw-r--r--src/util/configuration.c259
1 files changed, 209 insertions, 50 deletions
diff --git a/src/util/configuration.c b/src/util/configuration.c
index 4a1af10d3..da9cdb924 100644
--- a/src/util/configuration.c
+++ b/src/util/configuration.c
@@ -230,6 +230,120 @@ GNUNET_CONFIGURATION_parse_and_run (const char *filename,
230 return ret; 230 return ret;
231} 231}
232 232
233struct InlineGlobClosure
234{
235 struct GNUNET_CONFIGURATION_Handle *cfg;
236};
237
238/**
239 * Function called with a filename.
240 *
241 * @param cls closure
242 * @param filename complete filename (absolute path)
243 * @return #GNUNET_OK to continue to iterate,
244 * #GNUNET_NO to stop iteration with no error,
245 * #GNUNET_SYSERR to abort iteration with error!
246 */
247static int
248inline_glob_cb (void *cls,
249 const char *filename)
250{
251 struct InlineGlobClosure *igc = cls;
252
253 LOG (GNUNET_ERROR_TYPE_DEBUG,
254 "Reading globbed config file '%s'\n",
255 filename);
256
257 if (GNUNET_OK !=
258 GNUNET_CONFIGURATION_parse (igc->cfg,
259 filename))
260 {
261 return GNUNET_SYSERR;
262 }
263 return GNUNET_OK;
264}
265
266/**
267 * Handle an inline directive.
268 *
269 * @returns #GNUNET_SYSERR on error, #GNUNET_OK otherwise
270 */
271enum GNUNET_GenericReturnValue
272handle_inline (struct GNUNET_CONFIGURATION_Handle *cfg,
273 const char *path_or_glob,
274 bool path_is_glob,
275 const char *restrict_section,
276 const char *source_filename)
277{
278 char *inline_path;
279
280 /* We support the section restriction only for non-globs */
281 GNUNET_assert (! (path_is_glob && (NULL != restrict_section)));
282
283 if (NULL == source_filename)
284 {
285 LOG (GNUNET_ERROR_TYPE_DEBUG,
286 "Refusing to parse inline configurations, "
287 "not allowed without source filename!\n");
288 return GNUNET_SYSERR;
289 }
290 if ('/' == *path_or_glob)
291 inline_path = GNUNET_strdup (path_or_glob);
292 else
293 {
294 /* We compute the canonical, absolute path first,
295 so that relative imports resolve properly with symlinked
296 config files. */
297 char *source_realpath;
298 char *endsep;
299
300 source_realpath = realpath (source_filename,
301 NULL);
302 if (NULL == source_realpath)
303 {
304 /* Couldn't even resolve path of base dir. */
305 GNUNET_break (0);
306 /* failed to parse included config */
307 return GNUNET_SYSERR;
308 }
309 endsep = strrchr (source_realpath, '/');
310 GNUNET_assert (NULL != endsep);
311 *endsep = '\0';
312 GNUNET_asprintf (&inline_path,
313 "%s/%s",
314 source_realpath,
315 path_or_glob);
316 free (source_realpath);
317 }
318 if (path_is_glob)
319 {
320 int nret;
321 struct InlineGlobClosure igc = {
322 .cfg = cfg,
323 };
324
325 LOG (GNUNET_ERROR_TYPE_DEBUG,
326 "processing config glob '%s'\n",
327 inline_path);
328
329 nret = GNUNET_DISK_glob (inline_path, inline_glob_cb, &igc);
330 if (-1 == nret)
331 {
332 GNUNET_free (inline_path);
333 return GNUNET_SYSERR;
334 }
335 }
336 else if (GNUNET_OK !=
337 GNUNET_CONFIGURATION_parse (cfg,
338 inline_path))
339 {
340 GNUNET_free (inline_path);
341 return GNUNET_SYSERR;
342 }
343 GNUNET_free (inline_path);
344 return GNUNET_OK;
345}
346
233 347
234enum GNUNET_GenericReturnValue 348enum GNUNET_GenericReturnValue
235GNUNET_CONFIGURATION_deserialize (struct GNUNET_CONFIGURATION_Handle *cfg, 349GNUNET_CONFIGURATION_deserialize (struct GNUNET_CONFIGURATION_Handle *cfg,
@@ -237,28 +351,27 @@ GNUNET_CONFIGURATION_deserialize (struct GNUNET_CONFIGURATION_Handle *cfg,
237 size_t size, 351 size_t size,
238 const char *source_filename) 352 const char *source_filename)
239{ 353{
240 char *line;
241 char *line_orig;
242 size_t line_size; 354 size_t line_size;
243 char *pos;
244 unsigned int nr; 355 unsigned int nr;
245 size_t r_bytes; 356 size_t r_bytes;
246 size_t to_read; 357 size_t to_read;
247 size_t i;
248 int emptyline;
249 enum GNUNET_GenericReturnValue ret; 358 enum GNUNET_GenericReturnValue ret;
250 char *section; 359 char *section;
251 char *eq; 360 char *eq;
252 char *tag; 361 char *tag;
253 char *value; 362 char *value;
363 char *line_orig = NULL;
254 364
255 ret = GNUNET_OK; 365 ret = GNUNET_OK;
256 section = GNUNET_strdup (""); 366 section = NULL;
257 nr = 0; 367 nr = 0;
258 r_bytes = 0; 368 r_bytes = 0;
259 line_orig = NULL;
260 while (r_bytes < size) 369 while (r_bytes < size)
261 { 370 {
371 char *pos;
372 char *line;
373 bool emptyline;
374
262 GNUNET_free (line_orig); 375 GNUNET_free (line_orig);
263 /* fgets-like behaviour on buffer */ 376 /* fgets-like behaviour on buffer */
264 to_read = size - r_bytes; 377 to_read = size - r_bytes;
@@ -280,7 +393,7 @@ GNUNET_CONFIGURATION_deserialize (struct GNUNET_CONFIGURATION_Handle *cfg,
280 nr++; 393 nr++;
281 /* tabs and '\r' are whitespace */ 394 /* tabs and '\r' are whitespace */
282 emptyline = GNUNET_YES; 395 emptyline = GNUNET_YES;
283 for (i = 0; i < line_size; i++) 396 for (size_t i = 0; i < line_size; i++)
284 { 397 {
285 if (line[i] == '\t') 398 if (line[i] == '\t')
286 line[i] = ' '; 399 line[i] = ' ';
@@ -294,7 +407,7 @@ GNUNET_CONFIGURATION_deserialize (struct GNUNET_CONFIGURATION_Handle *cfg,
294 continue; 407 continue;
295 408
296 /* remove tailing whitespace */ 409 /* remove tailing whitespace */
297 for (i = line_size - 1; 410 for (size_t i = line_size - 1;
298 (i >= 1) && (isspace ((unsigned char) line[i])); 411 (i >= 1) && (isspace ((unsigned char) line[i]));
299 i--) 412 i--)
300 line[i] = '\0'; 413 line[i] = '\0';
@@ -308,60 +421,103 @@ GNUNET_CONFIGURATION_deserialize (struct GNUNET_CONFIGURATION_Handle *cfg,
308 ('%' == line[0]) ) 421 ('%' == line[0]) )
309 continue; 422 continue;
310 423
311 /* handle special "@INLINE@" directive */ 424 /* Handle special directives. */
312 if (0 == strncasecmp (line, 425 if ('@' == line[0])
313 "@INLINE@ ",
314 strlen ("@INLINE@ ")))
315 { 426 {
316 char *inline_path; 427 char *end = strchr (line + 1, '@');
428 char *directive;
429 enum GNUNET_GenericReturnValue directive_ret;
317 430
318 if (NULL == source_filename) 431 if (NULL == end)
319 { 432 {
320 LOG (GNUNET_ERROR_TYPE_DEBUG, 433 LOG (GNUNET_ERROR_TYPE_WARNING,
321 "Refusing to parse @INLINE@ configurations, " 434 _ ("Bad directive in line %u\n"),
322 "not allowed without source filename!\n"); 435 nr);
323 ret = GNUNET_SYSERR; 436 ret = GNUNET_SYSERR;
324 break; 437 break;
325 } 438 }
326 /* FIXME: also trim space and end of line comment? */ 439 *end = '\0';
327 value = &line[strlen ("@INLINE@ ")]; 440 directive = line + 1;
328 if ('/' == *value) 441
329 inline_path = GNUNET_strdup (value); 442 if (0 == strcasecmp (directive, "INLINE"))
330 else
331 { 443 {
332 /* We compute the canonical, absolute path first, 444 const char *path = end + 1;
333 so that relative imports resolve properly with symlinked 445
334 config files. */ 446 /* Skip space before path */
335 char *source_realpath; 447 for (; isspace (*path); path++)
336 char *endsep; 448 ;
337 449
338 source_realpath = realpath (source_filename, 450 directive_ret = handle_inline (cfg,
339 NULL); 451 path,
340 if (NULL == source_realpath) 452 false,
453 NULL,
454 source_filename);
455 }
456 else if (0 == strcasecmp (directive, "INLINE-MATCHING"))
457 {
458 const char *path = end + 1;
459
460 /* Skip space before path */
461 for (; isspace (*path); path++)
462 ;
463
464 directive_ret = handle_inline (cfg,
465 path,
466 true,
467 NULL,
468 source_filename);
469 }
470 else if (0 == strcasecmp (directive, "INLINE-SECRET"))
471 {
472 const char *secname = end + 1;
473 const char *path;
474 const char *secname_end;
475
476 /* Skip space before secname */
477 for (; isspace (*secname); secname++)
478 ;
479
480 secname_end = strchr (secname, ' ');
481
482 if (NULL == secname_end)
341 { 483 {
342 /* Couldn't even resolve path of base dir. */ 484 LOG (GNUNET_ERROR_TYPE_WARNING,
343 GNUNET_break (0); 485 _ ("Bad inline-secret directive in line %u\n"),
344 ret = GNUNET_SYSERR; /* failed to parse included config */ 486 nr);
487 ret = GNUNET_SYSERR;
345 break; 488 break;
346 } 489 }
347 endsep = strrchr (source_realpath, '/'); 490 secname_end = '\0';
348 GNUNET_assert (NULL != endsep); 491 path = secname_end + 1;
349 *endsep = '\0'; 492
350 GNUNET_asprintf (&inline_path, 493 /* Skip space before path */
351 "%s/%s", 494 for (; isspace (*path); path++)
352 source_realpath, 495 ;
353 value); 496
354 free (source_realpath); 497 directive_ret = handle_inline (cfg,
498 path,
499 false,
500 secname,
501 source_filename);
502 }
503 else
504 {
505 LOG (GNUNET_ERROR_TYPE_WARNING,
506 _ ("Unknown or malformed directive '%s' in line %u\n"),
507 directive,
508 nr);
509 ret = GNUNET_SYSERR;
510 break;
355 } 511 }
356 if (GNUNET_OK != 512 if (GNUNET_OK != directive_ret)
357 GNUNET_CONFIGURATION_parse (cfg,
358 inline_path))
359 { 513 {
360 GNUNET_free (inline_path); 514 LOG (GNUNET_ERROR_TYPE_WARNING,
361 ret = GNUNET_SYSERR; /* failed to parse included config */ 515 _ ("Bad directive '%s' in line %u\n"),
516 directive,
517 nr);
518 ret = GNUNET_SYSERR;
362 break; 519 break;
363 } 520 }
364 GNUNET_free (inline_path);
365 continue; 521 continue;
366 } 522 }
367 if (('[' == line[0]) && (']' == line[line_size - 1])) 523 if (('[' == line[0]) && (']' == line[line_size - 1]))
@@ -375,10 +531,13 @@ GNUNET_CONFIGURATION_deserialize (struct GNUNET_CONFIGURATION_Handle *cfg,
375 } 531 }
376 if (NULL != (eq = strchr (line, '='))) 532 if (NULL != (eq = strchr (line, '=')))
377 { 533 {
534 size_t i;
535
378 /* tag = value */ 536 /* tag = value */
379 tag = GNUNET_strndup (line, eq - line); 537 tag = GNUNET_strndup (line, eq - line);
380 /* remove tailing whitespace */ 538 /* remove tailing whitespace */
381 for (i = strlen (tag) - 1; (i >= 1) && (isspace ((unsigned char) tag[i])); 539 for (i = strlen (tag) - 1;
540 (i >= 1) && (isspace ((unsigned char) tag[i]));
382 i--) 541 i--)
383 tag[i] = '\0'; 542 tag[i] = '\0';
384 543