gnunet-auto-share.c 20 KB

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