diff options
-rw-r--r-- | src/fs/gnunet-auto-share.c | 146 |
1 files changed, 134 insertions, 12 deletions
diff --git a/src/fs/gnunet-auto-share.c b/src/fs/gnunet-auto-share.c index c3b0411d0..ad3267d9a 100644 --- a/src/fs/gnunet-auto-share.c +++ b/src/fs/gnunet-auto-share.c | |||
@@ -21,6 +21,9 @@ | |||
21 | * @file fs/gnunet-auto-share.c | 21 | * @file fs/gnunet-auto-share.c |
22 | * @brief automatically publish files on GNUnet | 22 | * @brief automatically publish files on GNUnet |
23 | * @author Christian Grothoff | 23 | * @author Christian Grothoff |
24 | * | ||
25 | * TODO: | ||
26 | * - support loading meta data / keywords from resource file | ||
24 | */ | 27 | */ |
25 | #include "platform.h" | 28 | #include "platform.h" |
26 | #include "gnunet_util_lib.h" | 29 | #include "gnunet_util_lib.h" |
@@ -72,6 +75,11 @@ static int verbose; | |||
72 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | 75 | static const struct GNUNET_CONFIGURATION_Handle *cfg; |
73 | 76 | ||
74 | /** | 77 | /** |
78 | * Name of the configuration file. | ||
79 | */ | ||
80 | static char *cfg_filename; | ||
81 | |||
82 | /** | ||
75 | * Disable extractor option to use for publishing. | 83 | * Disable extractor option to use for publishing. |
76 | */ | 84 | */ |
77 | static int disable_extractor; | 85 | static int disable_extractor; |
@@ -139,6 +147,16 @@ static int do_shutdown; | |||
139 | */ | 147 | */ |
140 | static struct GNUNET_TIME_Absolute start_time; | 148 | static struct GNUNET_TIME_Absolute start_time; |
141 | 149 | ||
150 | /** | ||
151 | * Pipe used to communicate 'gnunet-publish' completion (SIGCHLD) via signal. | ||
152 | */ | ||
153 | static struct GNUNET_DISK_PipeHandle *sigpipe; | ||
154 | |||
155 | /** | ||
156 | * Handle to the 'gnunet-publish' process that we executed. | ||
157 | */ | ||
158 | static struct GNUNET_OS_Process *publish_proc; | ||
159 | |||
142 | 160 | ||
143 | /** | 161 | /** |
144 | * Compute the name of the state database file we will use. | 162 | * Compute the name of the state database file we will use. |
@@ -284,6 +302,11 @@ do_stop_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
284 | { | 302 | { |
285 | kill_task = GNUNET_SCHEDULER_NO_TASK; | 303 | kill_task = GNUNET_SCHEDULER_NO_TASK; |
286 | do_shutdown = GNUNET_YES; | 304 | do_shutdown = GNUNET_YES; |
305 | if (NULL != publish_proc) | ||
306 | { | ||
307 | GNUNET_OS_process_kill (publish_proc, SIGKILL); | ||
308 | return; | ||
309 | } | ||
287 | if (GNUNET_SCHEDULER_NO_TASK != run_task) | 310 | if (GNUNET_SCHEDULER_NO_TASK != run_task) |
288 | { | 311 | { |
289 | GNUNET_SCHEDULER_cancel (run_task); | 312 | GNUNET_SCHEDULER_cancel (run_task); |
@@ -300,25 +323,23 @@ schedule_next_task (void); | |||
300 | 323 | ||
301 | 324 | ||
302 | /** | 325 | /** |
303 | * Function called to process work items. | 326 | * Task triggered whenever we receive a SIGCHLD (child |
327 | * process died). | ||
304 | * | 328 | * |
305 | * @param cls closure, NULL | 329 | * @param cls the 'struct WorkItem' we were working on |
306 | * @param tc scheduler context (unused) | 330 | * @param tc context |
307 | */ | 331 | */ |
308 | static void | 332 | static void |
309 | work (void *cls, | 333 | maint_child_death (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) |
310 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
311 | { | 334 | { |
312 | struct WorkItem *wi; | 335 | struct WorkItem *wi = cls; |
313 | struct GNUNET_HashCode key; | 336 | struct GNUNET_HashCode key; |
314 | 337 | ||
315 | run_task = GNUNET_SCHEDULER_NO_TASK; | 338 | run_task = GNUNET_SCHEDULER_NO_TASK; |
316 | wi = work_head; | 339 | GNUNET_break (GNUNET_OK == |
317 | GNUNET_CONTAINER_DLL_remove (work_head, | 340 | GNUNET_OS_process_wait (publish_proc)); |
318 | work_tail, | 341 | GNUNET_OS_process_destroy (publish_proc); |
319 | wi); | 342 | publish_proc = NULL; |
320 | // FIXME: actually run 'publish' here! | ||
321 | |||
322 | GNUNET_CRYPTO_hash (wi->filename, | 343 | GNUNET_CRYPTO_hash (wi->filename, |
323 | strlen (wi->filename), | 344 | strlen (wi->filename), |
324 | &key); | 345 | &key); |
@@ -332,6 +353,95 @@ work (void *cls, | |||
332 | 353 | ||
333 | 354 | ||
334 | /** | 355 | /** |
356 | * Signal handler called for SIGCHLD. Triggers the | ||
357 | * respective handler by writing to the trigger pipe. | ||
358 | */ | ||
359 | static void | ||
360 | sighandler_child_death () | ||
361 | { | ||
362 | static char c; | ||
363 | int old_errno = errno; /* back-up errno */ | ||
364 | |||
365 | GNUNET_break (1 == | ||
366 | GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle | ||
367 | (sigpipe, GNUNET_DISK_PIPE_END_WRITE), | ||
368 | &c, sizeof (c))); | ||
369 | errno = old_errno; /* restore errno */ | ||
370 | } | ||
371 | |||
372 | |||
373 | /** | ||
374 | * Function called to process work items. | ||
375 | * | ||
376 | * @param cls closure, NULL | ||
377 | * @param tc scheduler context (unused) | ||
378 | */ | ||
379 | static void | ||
380 | work (void *cls, | ||
381 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
382 | { | ||
383 | static char *argv[14]; | ||
384 | static char anon_level[20]; | ||
385 | static char content_prio[20]; | ||
386 | static char repl_level[20]; | ||
387 | struct WorkItem *wi; | ||
388 | const struct GNUNET_DISK_FileHandle *pr; | ||
389 | int argc; | ||
390 | |||
391 | run_task = GNUNET_SCHEDULER_NO_TASK; | ||
392 | wi = work_head; | ||
393 | GNUNET_CONTAINER_DLL_remove (work_head, | ||
394 | work_tail, | ||
395 | wi); | ||
396 | argc = 0; | ||
397 | argv[argc++] = "gnunet-publish"; | ||
398 | if (verbose) | ||
399 | argv[argc++] = "-V"; | ||
400 | if (disable_extractor) | ||
401 | argv[argc++] = "-D"; | ||
402 | if (do_disable_creation_time) | ||
403 | argv[argc++] = "-d"; | ||
404 | argv[argc++] = "-c"; | ||
405 | argv[argc++] = cfg_filename; | ||
406 | GNUNET_snprintf (anon_level, sizeof (anon_level), | ||
407 | "%u", anonymity_level); | ||
408 | argv[argc++] = "-a"; | ||
409 | argv[argc++] = anon_level; | ||
410 | GNUNET_snprintf (content_prio, sizeof (content_prio), | ||
411 | "%u", content_priority); | ||
412 | argv[argc++] = "-p"; | ||
413 | argv[argc++] = content_prio; | ||
414 | GNUNET_snprintf (repl_level, sizeof (repl_level), | ||
415 | "%u", replication_level); | ||
416 | argv[argc++] = "-r"; | ||
417 | argv[argc++] = repl_level; | ||
418 | argv[argc++] = wi->filename; | ||
419 | argv[argc] = NULL; | ||
420 | publish_proc = GNUNET_OS_start_process_vap (GNUNET_YES, | ||
421 | NULL, NULL, | ||
422 | "gnunet-publish", | ||
423 | argv); | ||
424 | if (NULL == publish_proc) | ||
425 | { | ||
426 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
427 | _("Failed to run `%s'\n"), | ||
428 | "gnunet-publish"); | ||
429 | GNUNET_CONTAINER_DLL_insert (work_head, | ||
430 | work_tail, | ||
431 | wi); | ||
432 | run_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, | ||
433 | &work, | ||
434 | NULL); | ||
435 | return; | ||
436 | } | ||
437 | pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ); | ||
438 | run_task = | ||
439 | GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
440 | pr, &maint_child_death, wi); | ||
441 | } | ||
442 | |||
443 | |||
444 | /** | ||
335 | * Recursively scan the given file/directory structure to determine | 445 | * Recursively scan the given file/directory structure to determine |
336 | * a unique ID that represents the current state of the hierarchy. | 446 | * a unique ID that represents the current state of the hierarchy. |
337 | * | 447 | * |
@@ -502,6 +612,7 @@ run (void *cls, char *const *args, const char *cfgfile, | |||
502 | ret = -1; | 612 | ret = -1; |
503 | return; | 613 | return; |
504 | } | 614 | } |
615 | cfg_filename = GNUNET_strdup (cfgfile); | ||
505 | cfg = c; | 616 | cfg = c; |
506 | dir_name = args[0]; | 617 | dir_name = args[0]; |
507 | work_finished = GNUNET_CONTAINER_multihashmap_create (1024); | 618 | work_finished = GNUNET_CONTAINER_multihashmap_create (1024); |
@@ -569,9 +680,14 @@ main (int argc, char *const *argv) | |||
569 | }; | 680 | }; |
570 | struct WorkItem *wi; | 681 | struct WorkItem *wi; |
571 | int ok; | 682 | int ok; |
683 | struct GNUNET_SIGNAL_Context *shc_chld; | ||
572 | 684 | ||
573 | if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) | 685 | if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) |
574 | return 2; | 686 | return 2; |
687 | sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO); | ||
688 | GNUNET_assert (sigpipe != NULL); | ||
689 | shc_chld = | ||
690 | GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death); | ||
575 | ok = (GNUNET_OK == | 691 | ok = (GNUNET_OK == |
576 | GNUNET_PROGRAM_run (argc, argv, "gnunet-auto-share [OPTIONS] FILENAME", | 692 | GNUNET_PROGRAM_run (argc, argv, "gnunet-auto-share [OPTIONS] FILENAME", |
577 | gettext_noop | 693 | gettext_noop |
@@ -587,6 +703,12 @@ main (int argc, char *const *argv) | |||
587 | GNUNET_free (wi->filename); | 703 | GNUNET_free (wi->filename); |
588 | GNUNET_free (wi); | 704 | GNUNET_free (wi); |
589 | } | 705 | } |
706 | GNUNET_SIGNAL_handler_uninstall (shc_chld); | ||
707 | shc_chld = NULL; | ||
708 | GNUNET_DISK_pipe_close (sigpipe); | ||
709 | sigpipe = NULL; | ||
710 | GNUNET_free (cfg_filename); | ||
711 | cfg_filename = NULL; | ||
590 | return ok; | 712 | return ok; |
591 | } | 713 | } |
592 | 714 | ||