2 This file is part of GNUnet.
3 Copyright (C) 2009, 2012, 2013 GNUnet e.V.
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.
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.
17 * @file arm/gnunet-arm.c
18 * @brief arm for writing a tool
19 * @author Christian Grothoff
22 #include "gnunet_arm_service.h"
23 #include "gnunet_constants.h"
24 #include "gnunet_util_lib.h"
27 * Set if we are to shutdown all services (including ARM).
32 * Set if we are to start default services (including ARM).
37 * Set if we are to stop/start default services (including ARM).
42 * Set if we should delete configuration and temp directory on exit.
47 * Set if we should not print status messages.
52 * Monitor ARM activity.
57 * Set if we should print a list of currently running services.
62 * Set to the name of a service to start.
67 * Set to the name of a service to kill.
72 * Set to the name of the config file used.
74 static const char *config_file;
77 * Set to the directory where runtime files are stored.
87 * Connection with ARM.
89 static struct GNUNET_ARM_Handle *h;
92 * Monitor connection with ARM.
94 static struct GNUNET_ARM_MonitorHandle *m;
99 static struct GNUNET_CONFIGURATION_Handle *cfg;
102 * Processing stage that we are in. Simple counter.
104 static unsigned int phase;
107 * User defined timestamp for completing operations.
109 static struct GNUNET_TIME_Relative timeout;
112 * Task to be run on timeout.
114 static struct GNUNET_SCHEDULER_Task *timeout_task;
117 * Do we want to give our stdout to gnunet-service-arm?
119 static int no_stdout;
122 * Do we want to give our stderr to gnunet-service-arm?
124 static int no_stderr;
127 * Handle for the task running the #action_loop().
129 static struct GNUNET_SCHEDULER_Task *al_task;
134 static struct GNUNET_ARM_Operation *op;
137 * Attempts to delete configuration file and GNUNET_HOME
138 * on ARM shutdown provided the end and delete options
139 * were specified when gnunet-arm was run.
144 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
145 "Will attempt to remove configuration file %s and service directory %s\n",
148 if (0 != UNLINK (config_file))
150 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
151 _("Failed to remove configuration file %s\n"),
154 if (GNUNET_OK != GNUNET_DISK_directory_remove (dir))
156 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
157 _("Failed to remove servicehome directory %s\n"),
165 * Main continuation-passing-style loop. Runs the various
166 * jobs that we've been asked to do in order.
168 * @param cls closure, unused
171 shutdown_task (void *cls)
175 GNUNET_SCHEDULER_cancel (al_task);
180 GNUNET_ARM_operation_cancel (op);
185 GNUNET_ARM_disconnect (h);
190 GNUNET_ARM_monitor_stop (m);
193 if (NULL != timeout_task)
195 GNUNET_SCHEDULER_cancel (timeout_task);
198 if ((GNUNET_YES == end) && (GNUNET_YES == delete))
200 GNUNET_CONFIGURATION_destroy (cfg);
206 * Returns a string interpretation of 'rs'
208 * @param rs the request status from ARM
209 * @return a string interpretation of the request status
212 req_string (enum GNUNET_ARM_RequestStatus rs)
216 case GNUNET_ARM_REQUEST_SENT_OK:
217 return _("Message was sent successfully");
218 case GNUNET_ARM_REQUEST_DISCONNECTED:
219 return _("We disconnected from ARM before we could send a request");
221 return _("Unknown request status");
226 * Returns a string interpretation of the 'result'
228 * @param result the arm result
229 * @return a string interpretation
232 ret_string (enum GNUNET_ARM_Result result)
236 case GNUNET_ARM_RESULT_STOPPED:
237 return _("is stopped");
238 case GNUNET_ARM_RESULT_STARTING:
239 return _("is starting");
240 case GNUNET_ARM_RESULT_STOPPING:
241 return _("is stopping");
242 case GNUNET_ARM_RESULT_IS_STARTING_ALREADY:
243 return _("is starting already");
244 case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY:
245 return _("is stopping already");
246 case GNUNET_ARM_RESULT_IS_STARTED_ALREADY:
247 return _("is started already");
248 case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY:
249 return _("is stopped already");
250 case GNUNET_ARM_RESULT_IS_NOT_KNOWN:
251 return _("service is not known to ARM");
252 case GNUNET_ARM_RESULT_START_FAILED:
253 return _("service failed to start");
254 case GNUNET_ARM_RESULT_IN_SHUTDOWN:
255 return _("service cannot be manipulated because ARM is shutting down");
257 return _("Unknown result code.");
262 * Main task that runs our various operations in order.
267 action_loop (void *cls);
271 * Function called whenever we connect to or disconnect from ARM.
272 * Termiantes the process if we fail to connect to the service on
276 * @param connected #GNUNET_YES if connected, #GNUNET_NO if disconnected,
277 * #GNUNET_SYSERR on error.
280 conn_status (void *cls,
285 if ( (GNUNET_SYSERR == connected) &&
288 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
289 _("Fatal error initializing ARM API.\n"));
290 GNUNET_SCHEDULER_shutdown ();
298 * We have requested ARM to be started, this function
299 * is called with the result of the operation. Informs the
300 * use of the result; on success, we continue with the event
301 * loop, on failure we terminate the process.
303 * @param cls closure unused
304 * @param rs what happened to our request
305 * @param result if the request was processed, this is the result
309 start_callback (void *cls,
310 enum GNUNET_ARM_RequestStatus rs,
311 enum GNUNET_ARM_Result result)
314 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
317 _("Failed to start the ARM service: %s\n"),
319 GNUNET_SCHEDULER_shutdown ();
322 if ( (GNUNET_ARM_RESULT_STARTING != result) &&
323 (GNUNET_ARM_RESULT_IS_STARTED_ALREADY != result) )
326 _("Failed to start the ARM service: %s\n"),
327 ret_string (result));
328 GNUNET_SCHEDULER_shutdown ();
331 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
332 "ARM service [re]start successful\n");
334 al_task = GNUNET_SCHEDULER_add_now (&action_loop, NULL);
339 * We have requested ARM to be stopped, this function
340 * is called with the result of the operation. Informs the
341 * use of the result; on success, we continue with the event
342 * loop, on failure we terminate the process.
344 * @param cls closure unused
345 * @param rs what happened to our request
346 * @param result if the request was processed, this is the result
350 stop_callback (void *cls,
351 enum GNUNET_ARM_RequestStatus rs,
352 enum GNUNET_ARM_Result result)
357 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
359 GNUNET_asprintf (&msg, "%s",
360 _("Failed to send a stop request to the ARM service: %s\n"));
361 FPRINTF (stdout, msg, req_string (rs));
363 GNUNET_SCHEDULER_shutdown ();
366 if ((GNUNET_ARM_RESULT_STOPPING != result) &&
367 (GNUNET_ARM_RESULT_STOPPED != result) &&
368 (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY != result))
371 _("Failed to stop the ARM service: %s\n"),
372 ret_string (result));
373 GNUNET_SCHEDULER_shutdown ();
376 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
377 "ARM service shutdown successful\n");
383 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
384 "Initiating an ARM restart\n");
386 al_task = GNUNET_SCHEDULER_add_now (&action_loop, NULL);
391 * We have requested a service to be started, this function
392 * is called with the result of the operation. Informs the
393 * use of the result; on success, we continue with the event
394 * loop, on failure we terminate the process.
396 * @param cls closure unused
397 * @param rs what happened to our request
398 * @param result if the request was processed, this is the result
402 init_callback (void *cls,
403 enum GNUNET_ARM_RequestStatus rs,
404 enum GNUNET_ARM_Result result)
407 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
410 _("Failed to send a request to start the `%s' service: %s\n"),
413 GNUNET_SCHEDULER_shutdown ();
416 if ((GNUNET_ARM_RESULT_STARTING != result) &&
417 (GNUNET_ARM_RESULT_IS_STARTED_ALREADY != result))
420 _("Failed to start the `%s' service: %s\n"),
422 ret_string (result));
423 GNUNET_SCHEDULER_shutdown ();
426 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
427 "Service %s [re]started successfully\n",
431 al_task = GNUNET_SCHEDULER_add_now (&action_loop, NULL);
436 * We have requested a service to be stopped, this function
437 * is called with the result of the operation. Informs the
438 * use of the result; on success, we continue with the event
439 * loop, on failure we terminate the process.
441 * @param cls closure unused
442 * @param rs what happened to our request
443 * @param result if the request was processed, this is the result
447 term_callback (void *cls,
448 enum GNUNET_ARM_RequestStatus rs,
449 enum GNUNET_ARM_Result result)
454 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
456 GNUNET_asprintf (&msg,
457 _("Failed to send a request to kill the `%s' service: %%s\n"),
459 FPRINTF (stdout, msg, req_string (rs));
461 GNUNET_SCHEDULER_shutdown ();
464 if ((GNUNET_ARM_RESULT_STOPPED != result) &&
465 (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY != result))
468 _("Failed to kill the `%s' service: %s\n"),
470 ret_string (result));
471 GNUNET_SCHEDULER_shutdown ();
475 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
476 "Service %s stopped successfully\n",
480 al_task = GNUNET_SCHEDULER_add_now (&action_loop, NULL);
485 * Function called with the list of running services. Prints
486 * the list to stdout, then starts the event loop again.
487 * Prints an error message and terminates the process on errors.
489 * @param cls closure (unused)
490 * @param rs request status (success, failure, etc.)
491 * @param count number of services in the list
492 * @param list list of services that are running
495 list_callback (void *cls,
496 enum GNUNET_ARM_RequestStatus rs,
498 const char *const*list)
503 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
507 GNUNET_asprintf (&msg, "%s",
508 _("Failed to request a list of services: %s\n"));
509 FPRINTF (stdout, msg, req_string (rs));
512 GNUNET_SCHEDULER_shutdown ();
516 FPRINTF (stderr, "%s",
517 _("Error communicating with ARM. ARM not running?\n"));
518 GNUNET_SCHEDULER_shutdown ();
523 FPRINTF (stdout, "%s", _("Running services:\n"));
524 for (i = 0; i < count; i++)
525 FPRINTF (stdout, "%s\n", list[i]);
526 al_task = GNUNET_SCHEDULER_add_now (&action_loop, NULL);
531 * Main action loop. Runs the various jobs that we've been asked to
534 * @param cls closure, unused
537 action_loop (void *cls)
540 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
541 "Running requested actions\n");
549 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
550 "Termination action\n");
551 op = GNUNET_ARM_request_service_stop (h,
561 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
563 op = GNUNET_ARM_request_service_stop (h,
573 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
575 op = GNUNET_ARM_request_service_start (h, "arm",
576 (no_stdout ? 0 : GNUNET_OS_INHERIT_STD_OUT) |
577 (no_stderr ? 0 : GNUNET_OS_INHERIT_STD_ERR),
586 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
587 "Initialization action\n");
588 op = GNUNET_ARM_request_service_start (h, init,
589 GNUNET_OS_INHERIT_STD_NONE,
598 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
599 "Going to list all running services controlled by ARM.\n");
600 op = GNUNET_ARM_request_service_list (h,
611 _("Now only monitoring, press CTRL-C to stop.\n"));
612 quiet = 0; /* does not make sense to stay quiet in monitor mode at this time */
613 return; /* done with tasks, just monitor */
616 default: /* last phase */
617 GNUNET_SCHEDULER_shutdown ();
625 * Function called when a service starts or stops.
628 * @param service service name
629 * @param status status of the service
632 srv_status (void *cls,
634 enum GNUNET_ARM_ServiceStatus status)
640 case GNUNET_ARM_SERVICE_MONITORING_STARTED:
641 return; /* this should be done silently */
642 case GNUNET_ARM_SERVICE_STOPPED:
643 msg = _("Stopped %s.\n");
645 case GNUNET_ARM_SERVICE_STARTING:
646 msg = _("Starting %s...\n");
648 case GNUNET_ARM_SERVICE_STOPPING:
649 msg = _("Stopping %s...\n");
663 _("Unknown status %u for service %s.\n"),
667 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
668 "Got service %s status %d\n",
675 * Task run on timeout (if -T is given).
678 timeout_task_cb (void *cls)
682 GNUNET_SCHEDULER_shutdown ();
687 * Main function that will be run by the scheduler.
690 * @param args remaining command-line arguments
691 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
692 * @param c configuration
698 const struct GNUNET_CONFIGURATION_Handle *c)
702 cfg = GNUNET_CONFIGURATION_dup (c);
703 config_file = cfgfile;
705 GNUNET_CONFIGURATION_get_value_string (cfg,
710 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
718 GNUNET_CONFIGURATION_get_value_filename (cfg,
723 GNUNET_CONFIGURATION_set_value_string (cfg,
729 GNUNET_free (armconfig);
731 if (NULL == (h = GNUNET_ARM_connect (cfg,
736 m = GNUNET_ARM_monitor_start (cfg,
739 al_task = GNUNET_SCHEDULER_add_now (&action_loop,
741 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
743 if (0 != timeout.rel_value_us)
744 timeout_task = GNUNET_SCHEDULER_add_delayed (timeout,
751 * The main function to obtain arm from gnunetd.
753 * @param argc number of arguments from the command line
754 * @param argv command line arguments
755 * @return 0 ok, 1 on error, 2 on timeout
758 main (int argc, char *const *argv)
760 struct GNUNET_GETOPT_CommandLineOption options[] = {
762 GNUNET_GETOPT_option_flag ('e',
764 gettext_noop ("stop all GNUnet services"),
767 GNUNET_GETOPT_option_string ('i',
770 gettext_noop ("start a particular service"),
773 GNUNET_GETOPT_option_string ('k',
776 gettext_noop ("stop a particular service"),
779 GNUNET_GETOPT_option_flag ('s',
781 gettext_noop ("start all GNUnet default services"),
784 GNUNET_GETOPT_option_flag ('r',
786 gettext_noop ("stop and start all GNUnet default services"),
788 GNUNET_GETOPT_option_flag ('d',
790 gettext_noop ("delete config file and directory on exit"),
793 GNUNET_GETOPT_option_flag ('m',
795 gettext_noop ("monitor ARM activities"),
798 GNUNET_GETOPT_option_flag ('q',
800 gettext_noop ("don't print status messages"),
803 GNUNET_GETOPT_option_relative_time ('T',
806 gettext_noop ("exit with error status if operation does not finish after DELAY"),
809 GNUNET_GETOPT_option_flag ('I',
811 gettext_noop ("list currently running services"),
814 GNUNET_GETOPT_option_flag ('O',
816 gettext_noop ("don't let gnunet-service-arm inherit standard output"),
819 GNUNET_GETOPT_option_flag ('E',
821 gettext_noop ("don't let gnunet-service-arm inherit standard error"),
824 GNUNET_GETOPT_OPTION_END
827 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv,
832 GNUNET_PROGRAM_run (argc, argv, "gnunet-arm",
834 ("Control services and the Automated Restart Manager (ARM)"),
835 options, &run, NULL))
837 GNUNET_free ((void *) argv);
840 GNUNET_free ((void*) argv);
844 /* end of gnunet-arm.c */