gnunet-auto-share.c 21 KB

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