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.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * @file arm/gnunet-arm.c
21 * @brief arm for writing a tool
22 * @author Christian Grothoff
25 #include "gnunet_arm_service.h"
26 #include "gnunet_constants.h"
27 #include "gnunet_util_lib.h"
30 * Set if we are to shutdown all services (including ARM).
35 * Set if we are to start default services (including ARM).
40 * Set if we are to stop/start default services (including ARM).
45 * Set if we should delete configuration and temp directory on exit.
50 * Set if we should not print status messages.
55 * Monitor ARM activity.
60 * Set if we should print a list of currently running services.
65 * Set to the name of a service to start.
70 * Set to the name of a service to kill.
75 * Set to the name of the config file used.
77 static char *config_file;
80 * Set to the directory where runtime files are stored.
90 * Connection with ARM.
92 static struct GNUNET_ARM_Handle *h;
95 * Monitor connection with ARM.
97 static struct GNUNET_ARM_MonitorHandle *m;
102 static struct GNUNET_CONFIGURATION_Handle *cfg;
105 * Processing stage that we are in. Simple counter.
107 static unsigned int phase;
110 * User defined timestamp for completing operations.
112 static struct GNUNET_TIME_Relative timeout;
115 * Task to be run on timeout.
117 static struct GNUNET_SCHEDULER_Task *timeout_task;
120 * Do we want to give our stdout to gnunet-service-arm?
122 static int no_stdout;
125 * Do we want to give our stderr to gnunet-service-arm?
127 static int no_stderr;
130 * Handle for the task running the #action_loop().
132 static struct GNUNET_SCHEDULER_Task *al_task;
137 static struct GNUNET_ARM_Operation *op;
140 * Attempts to delete configuration file and GNUNET_HOME
141 * on ARM shutdown provided the end and delete options
142 * were specified when gnunet-arm was run.
147 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
148 "Will attempt to remove configuration file %s and service directory %s\n",
151 if (0 != UNLINK (config_file))
153 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
154 _("Failed to remove configuration file %s\n"),
157 if (GNUNET_OK != GNUNET_DISK_directory_remove (dir))
159 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
160 _("Failed to remove servicehome directory %s\n"),
167 * Main continuation-passing-style loop. Runs the various
168 * jobs that we've been asked to do in order.
170 * @param cls closure, unused
173 shutdown_task (void *cls)
178 GNUNET_SCHEDULER_cancel (al_task);
183 GNUNET_ARM_operation_cancel (op);
188 GNUNET_ARM_disconnect (h);
193 GNUNET_ARM_monitor_stop (m);
196 if (NULL != timeout_task)
198 GNUNET_SCHEDULER_cancel (timeout_task);
201 if ((GNUNET_YES == end) && (GNUNET_YES == delete))
203 GNUNET_CONFIGURATION_destroy (cfg);
209 * Returns a string interpretation of 'rs'
211 * @param rs the request status from ARM
212 * @return a string interpretation of the request status
215 req_string (enum GNUNET_ARM_RequestStatus rs)
219 case GNUNET_ARM_REQUEST_SENT_OK:
220 return _("Message was sent successfully");
221 case GNUNET_ARM_REQUEST_DISCONNECTED:
222 return _("We disconnected from ARM before we could send a request");
224 return _("Unknown request status");
229 * Returns a string interpretation of the 'result'
231 * @param result the arm result
232 * @return a string interpretation
235 ret_string (enum GNUNET_ARM_Result result)
239 case GNUNET_ARM_RESULT_STOPPED:
240 return _("is stopped");
241 case GNUNET_ARM_RESULT_STARTING:
242 return _("is starting");
243 case GNUNET_ARM_RESULT_STOPPING:
244 return _("is stopping");
245 case GNUNET_ARM_RESULT_IS_STARTING_ALREADY:
246 return _("is starting already");
247 case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY:
248 return _("is stopping already");
249 case GNUNET_ARM_RESULT_IS_STARTED_ALREADY:
250 return _("is started already");
251 case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY:
252 return _("is stopped already");
253 case GNUNET_ARM_RESULT_IS_NOT_KNOWN:
254 return _("service is not known to ARM");
255 case GNUNET_ARM_RESULT_START_FAILED:
256 return _("service failed to start");
257 case GNUNET_ARM_RESULT_IN_SHUTDOWN:
258 return _("service cannot be manipulated because ARM is shutting down");
260 return _("Unknown result code.");
265 * Main task that runs our various operations in order.
270 action_loop (void *cls);
274 * Function called whenever we connect to or disconnect from ARM.
275 * Termiantes the process if we fail to connect to the service on
279 * @param connected #GNUNET_YES if connected, #GNUNET_NO if disconnected,
280 * #GNUNET_SYSERR on error.
283 conn_status (void *cls,
289 if ( (GNUNET_SYSERR == connected) &&
292 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
293 _("Fatal error initializing ARM API.\n"));
294 GNUNET_SCHEDULER_shutdown ();
302 * We have requested ARM to be started, this function
303 * is called with the result of the operation. Informs the
304 * use of the result; on success, we continue with the event
305 * loop, on failure we terminate the process.
307 * @param cls closure unused
308 * @param rs what happened to our request
309 * @param result if the request was processed, this is the result
313 start_callback (void *cls,
314 enum GNUNET_ARM_RequestStatus rs,
315 enum GNUNET_ARM_Result result)
319 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
322 _("Failed to start the ARM service: %s\n"),
324 GNUNET_SCHEDULER_shutdown ();
327 if ( (GNUNET_ARM_RESULT_STARTING != result) &&
328 (GNUNET_ARM_RESULT_IS_STARTED_ALREADY != result) )
331 _("Failed to start the ARM service: %s\n"),
332 ret_string (result));
333 GNUNET_SCHEDULER_shutdown ();
336 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
337 "ARM service [re]start successful\n");
339 al_task = GNUNET_SCHEDULER_add_now (&action_loop, NULL);
344 * We have requested ARM to be stopped, this function
345 * is called with the result of the operation. Informs the
346 * use of the result; on success, we continue with the event
347 * loop, on failure we terminate the process.
349 * @param cls closure unused
350 * @param rs what happened to our request
351 * @param result if the request was processed, this is the result
355 stop_callback (void *cls,
356 enum GNUNET_ARM_RequestStatus rs,
357 enum GNUNET_ARM_Result result)
363 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
365 GNUNET_asprintf (&msg, "%s",
366 _("Failed to send a stop request to the ARM service: %s\n"));
367 FPRINTF (stdout, msg, req_string (rs));
369 GNUNET_SCHEDULER_shutdown ();
372 if ((GNUNET_ARM_RESULT_STOPPING != result) &&
373 (GNUNET_ARM_RESULT_STOPPED != result) &&
374 (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY != result))
377 _("Failed to stop the ARM service: %s\n"),
378 ret_string (result));
379 GNUNET_SCHEDULER_shutdown ();
382 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
383 "ARM service shutdown successful\n");
389 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
390 "Initiating an ARM restart\n");
392 al_task = GNUNET_SCHEDULER_add_now (&action_loop, NULL);
397 * We have requested a service to be started, this function
398 * is called with the result of the operation. Informs the
399 * use of the result; on success, we continue with the event
400 * loop, on failure we terminate the process.
402 * @param cls closure unused
403 * @param rs what happened to our request
404 * @param result if the request was processed, this is the result
408 init_callback (void *cls,
409 enum GNUNET_ARM_RequestStatus rs,
410 enum GNUNET_ARM_Result result)
414 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
417 _("Failed to send a request to start the `%s' service: %s\n"),
420 GNUNET_SCHEDULER_shutdown ();
423 if ((GNUNET_ARM_RESULT_STARTING != result) &&
424 (GNUNET_ARM_RESULT_IS_STARTED_ALREADY != result))
427 _("Failed to start the `%s' service: %s\n"),
429 ret_string (result));
430 GNUNET_SCHEDULER_shutdown ();
433 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
434 "Service %s [re]started successfully\n",
438 al_task = GNUNET_SCHEDULER_add_now (&action_loop, NULL);
443 * We have requested a service to be stopped, this function
444 * is called with the result of the operation. Informs the
445 * use of the result; on success, we continue with the event
446 * loop, on failure we terminate the process.
448 * @param cls closure unused
449 * @param rs what happened to our request
450 * @param result if the request was processed, this is the result
454 term_callback (void *cls,
455 enum GNUNET_ARM_RequestStatus rs,
456 enum GNUNET_ARM_Result result)
462 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
464 GNUNET_asprintf (&msg,
465 _("Failed to send a request to kill the `%s' service: %%s\n"),
467 FPRINTF (stdout, msg, req_string (rs));
469 GNUNET_SCHEDULER_shutdown ();
472 if ((GNUNET_ARM_RESULT_STOPPED != result) &&
473 (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY != result))
476 _("Failed to kill the `%s' service: %s\n"),
478 ret_string (result));
479 GNUNET_SCHEDULER_shutdown ();
483 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
484 "Service %s stopped successfully\n",
488 al_task = GNUNET_SCHEDULER_add_now (&action_loop, NULL);
493 * Function called with the list of running services. Prints
494 * the list to stdout, then starts the event loop again.
495 * Prints an error message and terminates the process on errors.
497 * @param cls closure (unused)
498 * @param rs request status (success, failure, etc.)
499 * @param count number of services in the list
500 * @param list list of services that are running
503 list_callback (void *cls,
504 enum GNUNET_ARM_RequestStatus rs,
506 const char *const*list)
512 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
516 GNUNET_asprintf (&msg, "%s",
517 _("Failed to request a list of services: %s\n"));
518 FPRINTF (stdout, msg, req_string (rs));
521 GNUNET_SCHEDULER_shutdown ();
525 FPRINTF (stderr, "%s",
526 _("Error communicating with ARM. ARM not running?\n"));
527 GNUNET_SCHEDULER_shutdown ();
532 FPRINTF (stdout, "%s", _("Running services:\n"));
533 for (i = 0; i < count; i++)
534 FPRINTF (stdout, "%s\n", list[i]);
535 al_task = GNUNET_SCHEDULER_add_now (&action_loop, NULL);
540 * Main action loop. Runs the various jobs that we've been asked to
543 * @param cls closure, unused
546 action_loop (void *cls)
550 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
551 "Running requested actions\n");
559 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
560 "Termination action\n");
561 op = GNUNET_ARM_request_service_stop (h,
571 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
573 op = GNUNET_ARM_request_service_stop (h,
583 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
585 op = GNUNET_ARM_request_service_start (h, "arm",
586 (no_stdout ? 0 : GNUNET_OS_INHERIT_STD_OUT) |
587 (no_stderr ? 0 : GNUNET_OS_INHERIT_STD_ERR),
596 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
597 "Initialization action\n");
598 op = GNUNET_ARM_request_service_start (h, init,
599 GNUNET_OS_INHERIT_STD_NONE,
608 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
609 "Going to list all running services controlled by ARM.\n");
610 op = GNUNET_ARM_request_service_list (h,
621 _("Now only monitoring, press CTRL-C to stop.\n"));
622 quiet = 0; /* does not make sense to stay quiet in monitor mode at this time */
623 return; /* done with tasks, just monitor */
626 default: /* last phase */
627 GNUNET_SCHEDULER_shutdown ();
635 * Function called when a service starts or stops.
638 * @param service service name
639 * @param status status of the service
642 srv_status (void *cls,
644 enum GNUNET_ARM_ServiceStatus status)
651 case GNUNET_ARM_SERVICE_MONITORING_STARTED:
652 return; /* this should be done silently */
653 case GNUNET_ARM_SERVICE_STOPPED:
654 msg = _("Stopped %s.\n");
656 case GNUNET_ARM_SERVICE_STARTING:
657 msg = _("Starting %s...\n");
659 case GNUNET_ARM_SERVICE_STOPPING:
660 msg = _("Stopping %s...\n");
674 _("Unknown status %u for service %s.\n"),
678 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
679 "Got service %s status %d\n",
686 * Task run on timeout (if -T is given).
689 timeout_task_cb (void *cls)
694 GNUNET_SCHEDULER_shutdown ();
699 * Main function that will be run by the scheduler.
702 * @param args remaining command-line arguments
703 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
704 * @param c configuration
710 const struct GNUNET_CONFIGURATION_Handle *c)
715 cfg = GNUNET_CONFIGURATION_dup (c);
717 GNUNET_CONFIGURATION_get_value_string (cfg,
722 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
727 (void) GNUNET_CONFIGURATION_get_value_filename (cfg,
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
761 struct GNUNET_GETOPT_CommandLineOption options[] = {
762 GNUNET_GETOPT_option_flag ('e',
764 gettext_noop ("stop all GNUnet services"),
766 GNUNET_GETOPT_option_string ('i',
769 gettext_noop ("start a particular service"),
771 GNUNET_GETOPT_option_string ('k',
774 gettext_noop ("stop a particular service"),
776 GNUNET_GETOPT_option_flag ('s',
778 gettext_noop ("start all GNUnet default services"),
780 GNUNET_GETOPT_option_flag ('r',
782 gettext_noop ("stop and start all GNUnet default services"),
784 GNUNET_GETOPT_option_flag ('d',
786 gettext_noop ("delete config file and directory on exit"),
788 GNUNET_GETOPT_option_flag ('m',
790 gettext_noop ("monitor ARM activities"),
792 GNUNET_GETOPT_option_flag ('q',
794 gettext_noop ("don't print status messages"),
796 GNUNET_GETOPT_option_relative_time ('T',
799 gettext_noop ("exit with error status if operation does not finish after DELAY"),
801 GNUNET_GETOPT_option_flag ('I',
803 gettext_noop ("list currently running services"),
805 GNUNET_GETOPT_option_flag ('O',
807 gettext_noop ("don't let gnunet-service-arm inherit standard output"),
809 GNUNET_GETOPT_option_flag ('E',
811 gettext_noop ("don't let gnunet-service-arm inherit standard error"),
813 GNUNET_GETOPT_OPTION_END
817 GNUNET_STRINGS_get_utf8_args (argc, argv,
822 GNUNET_PROGRAM_run (argc,
826 ("Control services and the Automated Restart Manager (ARM)"),
830 GNUNET_free ((void *) argv);
833 GNUNET_free ((void*) argv);
837 /* end of gnunet-arm.c */