gnunet-auto-share.c 20 KB

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