gnunet-arm.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. /*
  2. This file is part of GNUnet.
  3. (C) 2009 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 arm/gnunet-arm.c
  19. * @brief arm for writing a tool
  20. * @author Christian Grothoff
  21. */
  22. #include "platform.h"
  23. #include "gnunet_arm_service.h"
  24. #include "gnunet_client_lib.h"
  25. #include "gnunet_constants.h"
  26. #include "gnunet_getopt_lib.h"
  27. #include "gnunet_program_lib.h"
  28. #include "gnunet_time_lib.h"
  29. /**
  30. * Timeout for stopping services. Long to give some services a real chance.
  31. */
  32. #define STOP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
  33. /**
  34. * Timeout for stopping ARM. Extra-long since ARM needs to stop everyone else.
  35. */
  36. #define STOP_TIMEOUT_ARM GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)
  37. /**
  38. * Timeout for starting services, very short because of the strange way start works
  39. * (by checking if running before starting, so really this time is always waited on
  40. * startup (annoying)).
  41. */
  42. #define START_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 1000)
  43. /**
  44. * Timeout for starting services, very short because of the strange way start works
  45. * (by checking if running before starting, so really this time is always waited on
  46. * startup (annoying)).
  47. */
  48. #define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2)
  49. /**
  50. * Set if we are to shutdown all services (including ARM).
  51. */
  52. static int end;
  53. /**
  54. * Set if we are to start default services (including ARM).
  55. */
  56. static int start;
  57. /**
  58. * Set if we are to stop/start default services (including ARM).
  59. */
  60. static int restart;
  61. /**
  62. * Set if we should delete configuration and temp directory on exit.
  63. */
  64. static int delete;
  65. /**
  66. * Set if we should not print status messages.
  67. */
  68. static int quiet;
  69. /**
  70. * Set to the name of a service to start.
  71. */
  72. static char *init;
  73. /**
  74. * Set to the name of a service to kill.
  75. */
  76. static char *term;
  77. /**
  78. * Set to the name of a service to test.
  79. */
  80. static char *test;
  81. /**
  82. * Set to the name of the config file used.
  83. */
  84. static const char *config_file;
  85. /**
  86. * Set to the directory where runtime files are stored.
  87. */
  88. static char *dir;
  89. /**
  90. * Final status code.
  91. */
  92. static int ret;
  93. /**
  94. * Connection with ARM.
  95. */
  96. static struct GNUNET_ARM_Handle *h;
  97. /**
  98. * Our configuration.
  99. */
  100. const struct GNUNET_CONFIGURATION_Handle *cfg;
  101. /**
  102. * Processing stage that we are in. Simple counter.
  103. */
  104. static unsigned int phase;
  105. /**
  106. * User defined timestamp for completing operations.
  107. */
  108. static struct GNUNET_TIME_Relative timeout;
  109. /**
  110. * Main continuation-passing-style loop. Runs the various
  111. * jobs that we've been asked to do in order.
  112. *
  113. * @param cls closure, unused
  114. * @param tc context, unused
  115. */
  116. static void
  117. cps_loop (void *cls,
  118. const struct GNUNET_SCHEDULER_TaskContext *tc);
  119. /**
  120. * Callback invoked with the status of the last operation. Reports to the
  121. * user and then runs the next phase in the FSM.
  122. *
  123. * @param cls pointer to "const char*" identifying service that was manipulated
  124. * @param success GNUNET_OK if service is now running, GNUNET_NO if not, GNUNET_SYSERR on error
  125. */
  126. static void
  127. confirm_cb (void *cls, int success)
  128. {
  129. const char *service = cls;
  130. switch (success)
  131. {
  132. case GNUNET_OK:
  133. if (quiet != GNUNET_YES)
  134. fprintf(stdout, _("Service `%s' has been started.\n"), service);
  135. if ((phase - 1 != 2) && (phase - 1 != 3))
  136. {
  137. if (quiet != GNUNET_YES)
  138. fprintf(stdout, _("Failed to stop service `%s'!\n"), service);
  139. ret = 1;
  140. }
  141. break;
  142. case GNUNET_NO:
  143. if (quiet != GNUNET_YES)
  144. fprintf(stdout, _("Service `%s' has been stopped.\n"), service);
  145. if ((phase - 1 != 0) && (phase - 1 != 1))
  146. {
  147. if (quiet != GNUNET_YES)
  148. fprintf(stdout, _("Failed to start service `%s'!\n"), service);
  149. ret = 1;
  150. }
  151. break;
  152. case GNUNET_SYSERR:
  153. if (quiet != GNUNET_YES)
  154. fprintf(stdout,
  155. _("Some error communicating with service `%s'.\n"), service);
  156. ret = 1;
  157. break;
  158. }
  159. GNUNET_SCHEDULER_add_continuation (&cps_loop,
  160. NULL,
  161. GNUNET_SCHEDULER_REASON_PREREQ_DONE);
  162. }
  163. /**
  164. * Function called to confirm that a service is running (or that
  165. * it is not running).
  166. *
  167. * @param cls pointer to "const char*" identifying service that was manipulated
  168. * @param tc reason determines if service is now running
  169. */
  170. static void
  171. confirm_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  172. {
  173. const char *service = cls;
  174. if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE))
  175. {
  176. if (quiet != GNUNET_YES)
  177. fprintf(stdout, _("Service `%s' is running.\n"), service);
  178. }
  179. else
  180. {
  181. if (quiet != GNUNET_YES)
  182. fprintf(stdout, _("Service `%s' is not running.\n"), service);
  183. }
  184. GNUNET_SCHEDULER_add_continuation (&cps_loop,
  185. NULL,
  186. GNUNET_SCHEDULER_REASON_PREREQ_DONE);
  187. }
  188. /**
  189. * Main function that will be run by the scheduler.
  190. *
  191. * @param cls closure
  192. * @param args remaining command-line arguments
  193. * @param cfgfile name of the configuration file used (for saving, can be NULL!)
  194. * @param c configuration
  195. */
  196. static void
  197. run (void *cls,
  198. char *const *args,
  199. const char *cfgfile,
  200. const struct GNUNET_CONFIGURATION_Handle *c)
  201. {
  202. cfg = c;
  203. config_file = cfgfile;
  204. if (GNUNET_CONFIGURATION_get_value_string(cfg, "PATHS", "SERVICEHOME", &dir) != GNUNET_OK)
  205. {
  206. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  207. _("Fatal configuration error: `%s' option in section `%s' missing.\n"),
  208. "SERVICEHOME",
  209. "PATHS");
  210. return;
  211. }
  212. h = GNUNET_ARM_connect (cfg, NULL);
  213. if (h == NULL)
  214. {
  215. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  216. _("Fatal error initializing ARM API.\n"));
  217. ret = 1;
  218. return;
  219. }
  220. GNUNET_SCHEDULER_add_continuation (&cps_loop,
  221. NULL,
  222. GNUNET_SCHEDULER_REASON_PREREQ_DONE);
  223. }
  224. /**
  225. * Attempts to delete configuration file and SERVICEHOME
  226. * on arm shutdown provided the end and delete options
  227. * were specified when gnunet-arm was run.
  228. */
  229. static void delete_files()
  230. {
  231. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Will attempt to remove configuration file %s and service directory %s\n", config_file, dir);
  232. if (UNLINK(config_file) != 0)
  233. {
  234. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  235. _("Failed to remove configuration file %s\n"), config_file);
  236. }
  237. if (GNUNET_DISK_directory_remove(dir) != GNUNET_OK)
  238. {
  239. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  240. _("Failed to remove servicehome directory %s\n"), dir);
  241. }
  242. }
  243. /**
  244. * Main continuation-passing-style loop. Runs the various
  245. * jobs that we've been asked to do in order.
  246. *
  247. * @param cls closure, unused
  248. * @param tc context, unused
  249. */
  250. static void
  251. cps_loop (void *cls,
  252. const struct GNUNET_SCHEDULER_TaskContext *tc)
  253. {
  254. while (1)
  255. {
  256. switch (phase++)
  257. {
  258. case 0:
  259. if (term != NULL)
  260. {
  261. GNUNET_ARM_stop_service (h, term, (0 == timeout.rel_value) ? STOP_TIMEOUT : timeout, &confirm_cb, term);
  262. return;
  263. }
  264. break;
  265. case 1:
  266. if ((end) || (restart))
  267. {
  268. GNUNET_ARM_stop_service (h, "arm", (0 == timeout.rel_value) ? STOP_TIMEOUT_ARM : timeout, &confirm_cb, "arm");
  269. return;
  270. }
  271. break;
  272. case 2:
  273. if (start)
  274. {
  275. GNUNET_ARM_start_service (h, "arm", (0 == timeout.rel_value) ? START_TIMEOUT : timeout, &confirm_cb, "arm");
  276. return;
  277. }
  278. break;
  279. case 3:
  280. if (init != NULL)
  281. {
  282. GNUNET_ARM_start_service (h, init, (0 == timeout.rel_value) ? START_TIMEOUT : timeout, &confirm_cb, init);
  283. return;
  284. }
  285. break;
  286. case 4:
  287. if (test != NULL)
  288. {
  289. GNUNET_CLIENT_service_test (test, cfg, (0 == timeout.rel_value) ? TEST_TIMEOUT : timeout, &confirm_task, test);
  290. return;
  291. }
  292. break;
  293. case 5:
  294. if (restart)
  295. {
  296. GNUNET_ARM_disconnect (h);
  297. phase = 0;
  298. end = 0;
  299. start = 1;
  300. restart = 0;
  301. h = GNUNET_ARM_connect (cfg, NULL);
  302. if (h == NULL)
  303. {
  304. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  305. _("Fatal error initializing ARM API.\n"));
  306. ret = 1;
  307. return;
  308. }
  309. GNUNET_SCHEDULER_add_now(&cps_loop, NULL);
  310. return;
  311. }
  312. /* Fall through */
  313. default: /* last phase */
  314. GNUNET_ARM_disconnect (h);
  315. if ((end == GNUNET_YES) && (delete == GNUNET_YES))
  316. delete_files();
  317. return;
  318. }
  319. }
  320. }
  321. /**
  322. * The main function to obtain arm from gnunetd.
  323. *
  324. * @param argc number of arguments from the command line
  325. * @param argv command line arguments
  326. * @return 0 ok, 1 on error
  327. */
  328. int
  329. main (int argc, char *const *argv)
  330. {
  331. static unsigned long long temp_timeout_ms;
  332. static const struct GNUNET_GETOPT_CommandLineOption options[] = {
  333. {'e', "end", NULL, gettext_noop ("stop all GNUnet services"),
  334. GNUNET_NO, &GNUNET_GETOPT_set_one, &end},
  335. {'i', "init", "SERVICE", gettext_noop ("start a particular service"),
  336. GNUNET_YES, &GNUNET_GETOPT_set_string, &init},
  337. {'k', "kill", "SERVICE", gettext_noop ("stop a particular service"),
  338. GNUNET_YES, &GNUNET_GETOPT_set_string, &term},
  339. {'s', "start", NULL, gettext_noop ("start all GNUnet default services"),
  340. GNUNET_NO, &GNUNET_GETOPT_set_one, &start},
  341. {'r', "restart", NULL, gettext_noop ("stop and start all GNUnet default services"),
  342. GNUNET_NO, &GNUNET_GETOPT_set_one, &restart},
  343. {'t', "test", "SERVICE",
  344. gettext_noop ("test if a particular service is running"),
  345. GNUNET_YES, &GNUNET_GETOPT_set_string, &test},
  346. {'d', "delete", NULL, gettext_noop ("delete config file and directory on exit"),
  347. GNUNET_NO, &GNUNET_GETOPT_set_one, &delete},
  348. {'q', "quiet", NULL, gettext_noop ("don't print status messages"),
  349. GNUNET_NO, &GNUNET_GETOPT_set_one, &quiet},
  350. {'T', "timeout", NULL, gettext_noop ("timeout for completing current operation"),
  351. GNUNET_YES, &GNUNET_GETOPT_set_ulong, &temp_timeout_ms},
  352. GNUNET_GETOPT_OPTION_END
  353. };
  354. if (temp_timeout_ms > 0)
  355. timeout.rel_value = temp_timeout_ms;
  356. if (GNUNET_OK == GNUNET_PROGRAM_run (argc,
  357. argv,
  358. "gnunet-arm",
  359. gettext_noop
  360. ("Control services and the Automated Restart Manager (ARM)"),
  361. options, &run, NULL))
  362. {
  363. return ret;
  364. }
  365. return 1;
  366. }
  367. /* end of gnunet-arm.c */