aboutsummaryrefslogtreecommitdiff
path: root/src/fs/gnunet-auto-share.c
diff options
context:
space:
mode:
authorMartin Schanzenbach <schanzen@gnunet.org>2023-10-19 11:55:21 +0200
committerMartin Schanzenbach <schanzen@gnunet.org>2023-10-19 11:55:21 +0200
commit579d9473bb75072303789599b23be9b0203336fc (patch)
tree687506d1968bd2a391b71b8832d1e97905db3ca8 /src/fs/gnunet-auto-share.c
parentb56e4e05ad919c7191260fcf1d78b1f8d739871a (diff)
downloadgnunet-579d9473bb75072303789599b23be9b0203336fc.tar.gz
gnunet-579d9473bb75072303789599b23be9b0203336fc.zip
BUILD: Move fs to contrib/service
Diffstat (limited to 'src/fs/gnunet-auto-share.c')
-rw-r--r--src/fs/gnunet-auto-share.c791
1 files changed, 0 insertions, 791 deletions
diff --git a/src/fs/gnunet-auto-share.c b/src/fs/gnunet-auto-share.c
deleted file mode 100644
index f91e9d00d..000000000
--- a/src/fs/gnunet-auto-share.c
+++ /dev/null
@@ -1,791 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001--2012 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file fs/gnunet-auto-share.c
22 * @brief automatically publish files on GNUnet
23 * @author Christian Grothoff
24 *
25 * TODO:
26 * - support loading meta data / keywords from resource file
27 * - add stability timer (a la buildbot)
28 */
29#include "platform.h"
30#include "gnunet_util_lib.h"
31
32#define MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
33
34#define MIN_DELAY GNUNET_TIME_UNIT_MINUTES
35
36
37/**
38 * Item in our work queue (or in the set of files/directories
39 * we have successfully published).
40 */
41struct WorkItem
42{
43 /**
44 * PENDING Work is kept in a linked list.
45 */
46 struct WorkItem *prev;
47
48 /**
49 * PENDING Work is kept in a linked list.
50 */
51 struct WorkItem *next;
52
53 /**
54 * Filename of the work item.
55 */
56 char *filename;
57
58 /**
59 * Unique identity for this work item (used to detect
60 * if we need to do the work again).
61 */
62 struct GNUNET_HashCode id;
63};
64
65
66/**
67 * Global return value from 'main'.
68 */
69static int ret;
70
71/**
72 * Are we running 'verbosely'?
73 */
74static unsigned int verbose;
75
76/**
77 * Configuration to use.
78 */
79static const struct GNUNET_CONFIGURATION_Handle *cfg;
80
81/**
82 * Name of the configuration file.
83 */
84static char *cfg_filename;
85
86/**
87 * Disable extractor option to use for publishing.
88 */
89static int disable_extractor;
90
91/**
92 * Disable creation time option to use for publishing.
93 */
94static int do_disable_creation_time;
95
96/**
97 * Handle for the main task that does scanning and working.
98 */
99static struct GNUNET_SCHEDULER_Task *run_task;
100
101/**
102 * Anonymity level option to use for publishing.
103 */
104static unsigned int anonymity_level = 1;
105
106/**
107 * Content priority option to use for publishing.
108 */
109static unsigned int content_priority = 365;
110
111/**
112 * Replication level option to use for publishing.
113 */
114static unsigned int replication_level = 1;
115
116/**
117 * Top-level directory we monitor to auto-publish.
118 */
119static const char *dir_name;
120
121/**
122 * Head of linked list of files still to publish.
123 */
124static struct WorkItem *work_head;
125
126/**
127 * Tail of linked list of files still to publish.
128 */
129static struct WorkItem *work_tail;
130
131/**
132 * Map from the hash of the filename (!) to a `struct WorkItem`
133 * that was finished.
134 */
135static struct GNUNET_CONTAINER_MultiHashMap *work_finished;
136
137/**
138 * Set to #GNUNET_YES if we are shutting down.
139 */
140static int do_shutdown;
141
142/**
143 * Start time of the current round; used to determine how long
144 * one iteration takes (which influences how fast we schedule
145 * the next one).
146 */
147static struct GNUNET_TIME_Absolute start_time;
148
149/**
150 * Pipe used to communicate 'gnunet-publish' completion (SIGCHLD) via signal.
151 */
152static struct GNUNET_DISK_PipeHandle *sigpipe;
153
154/**
155 * Handle to the 'gnunet-publish' process that we executed.
156 */
157static struct GNUNET_OS_Process *publish_proc;
158
159
160/**
161 * Compute the name of the state database file we will use.
162 */
163static char *
164get_state_file ()
165{
166 char *ret;
167
168 GNUNET_asprintf (&ret,
169 "%s%s.auto-share",
170 dir_name,
171 (DIR_SEPARATOR == dir_name[strlen (dir_name) - 1])
172 ? ""
173 : DIR_SEPARATOR_STR);
174 return ret;
175}
176
177
178/**
179 * Load the set of #work_finished items from disk.
180 */
181static void
182load_state ()
183{
184 char *fn;
185 struct GNUNET_BIO_ReadHandle *rh;
186 uint32_t n;
187 struct GNUNET_HashCode id;
188 struct WorkItem *wi;
189 char *emsg;
190
191 emsg = NULL;
192 fn = get_state_file ();
193 rh = GNUNET_BIO_read_open_file (fn);
194 GNUNET_free (fn);
195 if (NULL == rh)
196 return;
197 fn = NULL;
198 if (GNUNET_OK != GNUNET_BIO_read_int32 (rh, "number of files",
199 (int32_t *) &n))
200 goto error;
201 while (n-- > 0)
202 {
203 struct GNUNET_BIO_ReadSpec rs[] = {
204 GNUNET_BIO_read_spec_string ("filename", &fn, 1024),
205 GNUNET_BIO_read_spec_object ("id", &id, sizeof(struct GNUNET_HashCode)),
206 GNUNET_BIO_read_spec_end (),
207 };
208 if (GNUNET_OK != GNUNET_BIO_read_spec_commit (rh, rs))
209 goto error;
210 wi = GNUNET_new (struct WorkItem);
211 wi->id = id;
212 wi->filename = fn;
213 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
214 "Loaded serialization ID for `%s' is `%s'\n",
215 wi->filename,
216 GNUNET_h2s (&id));
217 fn = NULL;
218 GNUNET_CRYPTO_hash (wi->filename, strlen (wi->filename), &id);
219 GNUNET_break (GNUNET_OK ==
220 GNUNET_CONTAINER_multihashmap_put (
221 work_finished,
222 &id,
223 wi,
224 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
225 }
226 if (GNUNET_OK == GNUNET_BIO_read_close (rh, &emsg))
227 return;
228 rh = NULL;
229error:
230 GNUNET_free (fn);
231 if (NULL != rh)
232 (void) GNUNET_BIO_read_close (rh, &emsg);
233 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
234 _ ("Failed to load state: %s\n"),
235 emsg);
236 GNUNET_free (emsg);
237}
238
239
240/**
241 * Write work item from the #work_finished map to the given write handle.
242 *
243 * @param cls the `struct GNUNET_BIO_WriteHandle *`
244 * @param key key of the item in the map (unused)
245 * @param value the `struct WorkItem` to write
246 * @return #GNUNET_OK to continue to iterate (if write worked)
247 */
248static int
249write_item (void *cls, const struct GNUNET_HashCode *key, void *value)
250{
251 struct GNUNET_BIO_WriteHandle *wh = cls;
252 struct WorkItem *wi = value;
253
254 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
255 "Saving serialization ID of file `%s' with value `%s'\n",
256 wi->filename,
257 GNUNET_h2s (&wi->id));
258 struct GNUNET_BIO_WriteSpec ws[] = {
259 GNUNET_BIO_write_spec_string ("auto-share-write-item-filename",
260 wi->filename),
261 GNUNET_BIO_write_spec_object ("id", &wi->id, sizeof(struct
262 GNUNET_HashCode)),
263 GNUNET_BIO_write_spec_end (),
264 };
265 if (GNUNET_OK != GNUNET_BIO_write_spec_commit (wh, ws))
266 return GNUNET_SYSERR; /* write error, abort iteration */
267 return GNUNET_OK;
268}
269
270
271/**
272 * Save the set of #work_finished items on disk.
273 */
274static void
275save_state ()
276{
277 uint32_t n;
278 struct GNUNET_BIO_WriteHandle *wh;
279 char *fn;
280
281 n = GNUNET_CONTAINER_multihashmap_size (work_finished);
282 fn = get_state_file ();
283 wh = GNUNET_BIO_write_open_file (fn);
284 if (NULL == wh)
285 {
286 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
287 _ ("Failed to save state to file %s\n"),
288 fn);
289 GNUNET_free (fn);
290 return;
291 }
292 if (GNUNET_OK != GNUNET_BIO_write_int32 (wh, "size of state", n))
293 {
294 (void) GNUNET_BIO_write_close (wh, NULL);
295 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
296 _ ("Failed to save state to file %s\n"),
297 fn);
298 GNUNET_free (fn);
299 return;
300 }
301 (void) GNUNET_CONTAINER_multihashmap_iterate (work_finished, &write_item, wh);
302 if (GNUNET_OK != GNUNET_BIO_write_close (wh, NULL))
303 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
304 _ ("Failed to save state to file %s\n"),
305 fn);
306 GNUNET_free (fn);
307}
308
309
310/**
311 * Task run on shutdown. Serializes our current state to disk.
312 *
313 * @param cls closure, unused
314 */
315static void
316do_stop_task (void *cls)
317{
318 do_shutdown = GNUNET_YES;
319 if (NULL != publish_proc)
320 {
321 GNUNET_OS_process_kill (publish_proc, SIGKILL);
322 return;
323 }
324 if (NULL != run_task)
325 {
326 GNUNET_SCHEDULER_cancel (run_task);
327 run_task = NULL;
328 }
329}
330
331
332/**
333 * Decide what the next task is (working or scanning) and schedule it.
334 */
335static void
336schedule_next_task (void);
337
338
339/**
340 * Task triggered whenever we receive a SIGCHLD (child
341 * process died).
342 *
343 * @param cls the `struct WorkItem` we were working on
344 */
345static void
346maint_child_death (void *cls)
347{
348 struct WorkItem *wi = cls;
349 struct GNUNET_HashCode key;
350 enum GNUNET_OS_ProcessStatusType type;
351 unsigned long code;
352 int ret;
353 char c;
354 const struct GNUNET_DISK_FileHandle *pr;
355 const struct GNUNET_SCHEDULER_TaskContext *tc;
356
357 run_task = NULL;
358 pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
359 tc = GNUNET_SCHEDULER_get_task_context ();
360 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
361 {
362 /* shutdown scheduled us, someone else will kill child,
363 we should just try again */
364 run_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
365 pr,
366 &maint_child_death,
367 wi);
368 return;
369 }
370 /* consume the signal */
371 GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof(c)));
372
373 ret = GNUNET_OS_process_status (publish_proc, &type, &code);
374 GNUNET_assert (GNUNET_SYSERR != ret);
375 if (GNUNET_NO == ret)
376 {
377 /* process still running? Then where did the SIGCHLD come from?
378 Well, let's declare it spurious (kernel bug?) and keep rolling.
379 */
380 GNUNET_break (0);
381 run_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
382 pr,
383 &maint_child_death,
384 wi);
385 return;
386 }
387 GNUNET_assert (GNUNET_OK == ret);
388
389 GNUNET_OS_process_destroy (publish_proc);
390 publish_proc = NULL;
391
392 if (GNUNET_YES == do_shutdown)
393 {
394 GNUNET_free (wi->filename);
395 GNUNET_free (wi);
396 return;
397 }
398 if ((GNUNET_OS_PROCESS_EXITED == type) && (0 == code))
399 {
400 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
401 _ ("Publication of `%s' done\n"),
402 wi->filename);
403 GNUNET_CRYPTO_hash (wi->filename, strlen (wi->filename), &key);
404 GNUNET_break (GNUNET_OK ==
405 GNUNET_CONTAINER_multihashmap_put (
406 work_finished,
407 &key,
408 wi,
409 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
410 }
411 else
412 {
413 GNUNET_CONTAINER_DLL_insert_tail (work_head, work_tail, wi);
414 }
415 save_state ();
416 schedule_next_task ();
417}
418
419
420/**
421 * Signal handler called for SIGCHLD. Triggers the
422 * respective handler by writing to the trigger pipe.
423 */
424static void
425sighandler_child_death ()
426{
427 static char c;
428 int old_errno = errno; /* back-up errno */
429
430 GNUNET_break (
431 1 ==
432 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle (sigpipe,
433 GNUNET_DISK_PIPE_END_WRITE),
434 &c,
435 sizeof(c)));
436 errno = old_errno; /* restore errno */
437}
438
439
440/**
441 * Function called to process work items.
442 *
443 * @param cls closure, NULL
444 */
445static void
446work (void *cls)
447{
448 static char *argv[14];
449 static char anon_level[20];
450 static char content_prio[20];
451 static char repl_level[20];
452 struct WorkItem *wi;
453 const struct GNUNET_DISK_FileHandle *pr;
454 int argc;
455
456 run_task = NULL;
457 wi = work_head;
458 GNUNET_CONTAINER_DLL_remove (work_head, work_tail, wi);
459 argc = 0;
460 argv[argc++] = "gnunet-publish";
461 if (verbose)
462 argv[argc++] = "-V";
463 if (disable_extractor)
464 argv[argc++] = "-D";
465 if (do_disable_creation_time)
466 argv[argc++] = "-d";
467 argv[argc++] = "-c";
468 argv[argc++] = cfg_filename;
469 GNUNET_snprintf (anon_level, sizeof(anon_level), "%u", anonymity_level);
470 argv[argc++] = "-a";
471 argv[argc++] = anon_level;
472 GNUNET_snprintf (content_prio, sizeof(content_prio), "%u", content_priority);
473 argv[argc++] = "-p";
474 argv[argc++] = content_prio;
475 GNUNET_snprintf (repl_level, sizeof(repl_level), "%u", replication_level);
476 argv[argc++] = "-r";
477 argv[argc++] = repl_level;
478 argv[argc++] = wi->filename;
479 argv[argc] = NULL;
480 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Publishing `%s'\n"), wi->filename);
481 GNUNET_assert (NULL == publish_proc);
482 publish_proc = GNUNET_OS_start_process_vap (GNUNET_OS_USE_PIPE_CONTROL,
483 NULL,
484 NULL,
485 NULL,
486 "gnunet-publish",
487 argv);
488 if (NULL == publish_proc)
489 {
490 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
491 _ ("Failed to run `%s'\n"),
492 "gnunet-publish");
493 GNUNET_CONTAINER_DLL_insert (work_head, work_tail, wi);
494 run_task =
495 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &work, NULL);
496 return;
497 }
498 pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
499 run_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
500 pr,
501 &maint_child_death,
502 wi);
503}
504
505
506/**
507 * Recursively scan the given file/directory structure to determine
508 * a unique ID that represents the current state of the hierarchy.
509 *
510 * @param cls where to store the unique ID we are computing
511 * @param filename file to scan
512 * @return #GNUNET_OK (always)
513 */
514static int
515determine_id (void *cls, const char *filename)
516{
517 struct GNUNET_HashCode *id = cls;
518 struct stat sbuf;
519 struct GNUNET_HashCode fx[2];
520 struct GNUNET_HashCode ft;
521
522 if (0 != stat (filename, &sbuf))
523 {
524 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "stat", filename);
525 return GNUNET_OK;
526 }
527 GNUNET_CRYPTO_hash (filename, strlen (filename), &fx[0]);
528 if (! S_ISDIR (sbuf.st_mode))
529 {
530 uint64_t fattr[2];
531
532 fattr[0] = GNUNET_htonll (sbuf.st_size);
533 fattr[0] = GNUNET_htonll (sbuf.st_mtime);
534
535 GNUNET_CRYPTO_hash (fattr, sizeof(fattr), &fx[1]);
536 }
537 else
538 {
539 memset (&fx[1], 1, sizeof(struct GNUNET_HashCode));
540 GNUNET_DISK_directory_scan (filename, &determine_id, &fx[1]);
541 }
542 /* use hash here to make hierarchical structure distinct from
543 all files on the same level */
544 GNUNET_CRYPTO_hash (fx, sizeof(fx), &ft);
545 /* use XOR here so that order of the files in the directory
546 does not matter! */
547 GNUNET_CRYPTO_hash_xor (&ft, id, id);
548 return GNUNET_OK;
549}
550
551
552/**
553 * Function called with a filename (or directory name) to publish
554 * (if it has changed since the last time we published it). This function
555 * is called for the top-level files only.
556 *
557 * @param cls closure, NULL
558 * @param filename complete filename (absolute path)
559 * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR during shutdown
560 */
561static int
562add_file (void *cls, const char *filename)
563{
564 struct WorkItem *wi;
565 struct GNUNET_HashCode key;
566 struct GNUNET_HashCode id;
567
568 if (GNUNET_YES == do_shutdown)
569 return GNUNET_SYSERR;
570 if ((NULL != strstr (filename, "/.auto-share")) ||
571 (NULL != strstr (filename, "\\.auto-share")))
572 return GNUNET_OK; /* skip internal file */
573 GNUNET_CRYPTO_hash (filename, strlen (filename), &key);
574 wi = GNUNET_CONTAINER_multihashmap_get (work_finished, &key);
575 memset (&id, 0, sizeof(struct GNUNET_HashCode));
576 determine_id (&id, filename);
577 if (NULL != wi)
578 {
579 if (0 == memcmp (&id, &wi->id, sizeof(struct GNUNET_HashCode)))
580 return GNUNET_OK; /* skip: we did this one already */
581 /* contents changed, need to re-do the directory... */
582 GNUNET_assert (
583 GNUNET_YES ==
584 GNUNET_CONTAINER_multihashmap_remove (work_finished, &key, wi));
585 }
586 else
587 {
588 wi = GNUNET_new (struct WorkItem);
589 wi->filename = GNUNET_strdup (filename);
590 }
591 wi->id = id;
592 GNUNET_CONTAINER_DLL_insert (work_head, work_tail, wi);
593 if (GNUNET_YES == do_shutdown)
594 return GNUNET_SYSERR;
595 return GNUNET_OK;
596}
597
598
599/**
600 * Periodically run task to update our view of the directory to share.
601 *
602 * @param cls NULL
603 */
604static void
605scan (void *cls)
606{
607 run_task = NULL;
608 start_time = GNUNET_TIME_absolute_get ();
609 (void) GNUNET_DISK_directory_scan (dir_name, &add_file, NULL);
610 schedule_next_task ();
611}
612
613
614/**
615 * Decide what the next task is (working or scanning) and schedule it.
616 */
617static void
618schedule_next_task ()
619{
620 struct GNUNET_TIME_Relative delay;
621
622 if (GNUNET_YES == do_shutdown)
623 return;
624 GNUNET_assert (NULL == run_task);
625 if (NULL == work_head)
626 {
627 /* delay by at most 4h, at least 1s, and otherwise in between depending
628 on how long it took to scan */
629 delay = GNUNET_TIME_absolute_get_duration (start_time);
630 delay = GNUNET_TIME_relative_saturating_multiply (delay, 100);
631 delay = GNUNET_TIME_relative_min (delay, MAX_DELAY);
632 delay = GNUNET_TIME_relative_max (delay, MIN_DELAY);
633 run_task = GNUNET_SCHEDULER_add_delayed (delay, &scan, NULL);
634 }
635 else
636 {
637 run_task = GNUNET_SCHEDULER_add_now (&work, NULL);
638 }
639}
640
641
642/**
643 * Main function that will be run by the scheduler.
644 *
645 * @param cls closure
646 * @param args remaining command-line arguments
647 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
648 * @param c configuration
649 */
650static void
651run (void *cls,
652 char *const *args,
653 const char *cfgfile,
654 const struct GNUNET_CONFIGURATION_Handle *c)
655{
656 /* check arguments */
657 if ((NULL == args[0]) || (NULL != args[1]) ||
658 (GNUNET_YES != GNUNET_DISK_directory_test (args[0], GNUNET_YES)))
659 {
660 printf (_ (
661 "You must specify one and only one directory name for automatic publication.\n"));
662 ret = -1;
663 return;
664 }
665 cfg_filename = GNUNET_strdup (cfgfile);
666 cfg = c;
667 dir_name = args[0];
668 work_finished = GNUNET_CONTAINER_multihashmap_create (1024, GNUNET_NO);
669 load_state ();
670 run_task = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
671 &scan,
672 NULL);
673 GNUNET_SCHEDULER_add_shutdown (&do_stop_task, NULL);
674}
675
676
677/**
678 * Free memory associated with the work item from the work_finished map.
679 *
680 * @param cls NULL (unused)
681 * @param key key of the item in the map (unused)
682 * @param value the `struct WorkItem` to free
683 * @return #GNUNET_OK to continue to iterate
684 */
685static int
686free_item (void *cls, const struct GNUNET_HashCode *key, void *value)
687{
688 struct WorkItem *wi = value;
689
690 GNUNET_free (wi->filename);
691 GNUNET_free (wi);
692 return GNUNET_OK;
693}
694
695
696/**
697 * The main function to automatically publish content to GNUnet.
698 *
699 * @param argc number of arguments from the command line
700 * @param argv command line arguments
701 * @return 0 ok, 1 on error
702 */
703int
704main (int argc, char *const *argv)
705{
706 struct GNUNET_GETOPT_CommandLineOption options[] = {
707 GNUNET_GETOPT_option_uint ('a',
708 "anonymity",
709 "LEVEL",
710 gettext_noop (
711 "set the desired LEVEL of sender-anonymity"),
712 &anonymity_level),
713
714 GNUNET_GETOPT_option_flag (
715 'd',
716 "disable-creation-time",
717 gettext_noop (
718 "disable adding the creation time to the metadata of the uploaded file"),
719 &do_disable_creation_time),
720
721 GNUNET_GETOPT_option_flag (
722 'D',
723 "disable-extractor",
724 gettext_noop ("do not use libextractor to add keywords or metadata"),
725 &disable_extractor),
726
727 GNUNET_GETOPT_option_uint ('p',
728 "priority",
729 "PRIORITY",
730 gettext_noop (
731 "specify the priority of the content"),
732 &content_priority),
733
734 GNUNET_GETOPT_option_uint ('r',
735 "replication",
736 "LEVEL",
737 gettext_noop (
738 "set the desired replication LEVEL"),
739 &replication_level),
740
741 GNUNET_GETOPT_option_verbose (&verbose),
742
743 GNUNET_GETOPT_OPTION_END
744 };
745 struct WorkItem *wi;
746 int ok;
747 struct GNUNET_SIGNAL_Context *shc_chld;
748
749 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
750 return 2;
751 sigpipe = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE);
752 GNUNET_assert (NULL != sigpipe);
753 shc_chld =
754 GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death);
755 ok =
756 (GNUNET_OK ==
757 GNUNET_PROGRAM_run (
758 argc,
759 argv,
760 "gnunet-auto-share [OPTIONS] FILENAME",
761 gettext_noop ("Automatically publish files from a directory on GNUnet"),
762 options,
763 &run,
764 NULL))
765 ? ret
766 : 1;
767 if (NULL != work_finished)
768 {
769 (void) GNUNET_CONTAINER_multihashmap_iterate (work_finished,
770 &free_item,
771 NULL);
772 GNUNET_CONTAINER_multihashmap_destroy (work_finished);
773 }
774 while (NULL != (wi = work_head))
775 {
776 GNUNET_CONTAINER_DLL_remove (work_head, work_tail, wi);
777 GNUNET_free (wi->filename);
778 GNUNET_free (wi);
779 }
780 GNUNET_SIGNAL_handler_uninstall (shc_chld);
781 shc_chld = NULL;
782 GNUNET_DISK_pipe_close (sigpipe);
783 sigpipe = NULL;
784 GNUNET_free (cfg_filename);
785 cfg_filename = NULL;
786 GNUNET_free_nz ((void *) argv);
787 return ok;
788}
789
790
791/* end of gnunet-auto-share.c */