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 const 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)
177 GNUNET_SCHEDULER_cancel (al_task);
182 GNUNET_ARM_operation_cancel (op);
187 GNUNET_ARM_disconnect (h);
192 GNUNET_ARM_monitor_stop (m);
195 if (NULL != timeout_task)
197 GNUNET_SCHEDULER_cancel (timeout_task);
200 if ((GNUNET_YES == end) && (GNUNET_YES == delete))
202 GNUNET_CONFIGURATION_destroy (cfg);
208 * Returns a string interpretation of 'rs'
210 * @param rs the request status from ARM
211 * @return a string interpretation of the request status
214 req_string (enum GNUNET_ARM_RequestStatus rs)
218 case GNUNET_ARM_REQUEST_SENT_OK:
219 return _("Message was sent successfully");
220 case GNUNET_ARM_REQUEST_DISCONNECTED:
221 return _("We disconnected from ARM before we could send a request");
223 return _("Unknown request status");
228 * Returns a string interpretation of the 'result'
230 * @param result the arm result
231 * @return a string interpretation
234 ret_string (enum GNUNET_ARM_Result result)
238 case GNUNET_ARM_RESULT_STOPPED:
239 return _("is stopped");
240 case GNUNET_ARM_RESULT_STARTING:
241 return _("is starting");
242 case GNUNET_ARM_RESULT_STOPPING:
243 return _("is stopping");
244 case GNUNET_ARM_RESULT_IS_STARTING_ALREADY:
245 return _("is starting already");
246 case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY:
247 return _("is stopping already");
248 case GNUNET_ARM_RESULT_IS_STARTED_ALREADY:
249 return _("is started already");
250 case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY:
251 return _("is stopped already");
252 case GNUNET_ARM_RESULT_IS_NOT_KNOWN:
253 return _("service is not known to ARM");
254 case GNUNET_ARM_RESULT_START_FAILED:
255 return _("service failed to start");
256 case GNUNET_ARM_RESULT_IN_SHUTDOWN:
257 return _("service cannot be manipulated because ARM is shutting down");
259 return _("Unknown result code.");
264 * Main task that runs our various operations in order.
269 action_loop (void *cls);
273 * Function called whenever we connect to or disconnect from ARM.
274 * Termiantes the process if we fail to connect to the service on
278 * @param connected #GNUNET_YES if connected, #GNUNET_NO if disconnected,
279 * #GNUNET_SYSERR on error.
282 conn_status (void *cls,
287 if ( (GNUNET_SYSERR == connected) &&
290 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
291 _("Fatal error initializing ARM API.\n"));
292 GNUNET_SCHEDULER_shutdown ();
300 * We have requested ARM to be started, this function
301 * is called with the result of the operation. Informs the
302 * use of the result; on success, we continue with the event
303 * loop, on failure we terminate the process.
305 * @param cls closure unused
306 * @param rs what happened to our request
307 * @param result if the request was processed, this is the result
311 start_callback (void *cls,
312 enum GNUNET_ARM_RequestStatus rs,
313 enum GNUNET_ARM_Result result)
316 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
319 _("Failed to start the ARM service: %s\n"),
321 GNUNET_SCHEDULER_shutdown ();
324 if ( (GNUNET_ARM_RESULT_STARTING != result) &&
325 (GNUNET_ARM_RESULT_IS_STARTED_ALREADY != result) )
328 _("Failed to start the ARM service: %s\n"),
329 ret_string (result));
330 GNUNET_SCHEDULER_shutdown ();
333 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
334 "ARM service [re]start successful\n");
336 al_task = GNUNET_SCHEDULER_add_now (&action_loop, NULL);
341 * We have requested ARM to be stopped, this function
342 * is called with the result of the operation. Informs the
343 * use of the result; on success, we continue with the event
344 * loop, on failure we terminate the process.
346 * @param cls closure unused
347 * @param rs what happened to our request
348 * @param result if the request was processed, this is the result
352 stop_callback (void *cls,
353 enum GNUNET_ARM_RequestStatus rs,
354 enum GNUNET_ARM_Result result)
359 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
361 GNUNET_asprintf (&msg, "%s",
362 _("Failed to send a stop request to the ARM service: %s\n"));
363 FPRINTF (stdout, msg, req_string (rs));
365 GNUNET_SCHEDULER_shutdown ();
368 if ((GNUNET_ARM_RESULT_STOPPING != result) &&
369 (GNUNET_ARM_RESULT_STOPPED != result) &&
370 (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY != result))
373 _("Failed to stop the ARM service: %s\n"),
374 ret_string (result));
375 GNUNET_SCHEDULER_shutdown ();
378 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
379 "ARM service shutdown successful\n");
385 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
386 "Initiating an ARM restart\n");
388 al_task = GNUNET_SCHEDULER_add_now (&action_loop, NULL);
393 * We have requested a service to be started, this function
394 * is called with the result of the operation. Informs the
395 * use of the result; on success, we continue with the event
396 * loop, on failure we terminate the process.
398 * @param cls closure unused
399 * @param rs what happened to our request
400 * @param result if the request was processed, this is the result
404 init_callback (void *cls,
405 enum GNUNET_ARM_RequestStatus rs,
406 enum GNUNET_ARM_Result result)
409 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
412 _("Failed to send a request to start the `%s' service: %s\n"),
415 GNUNET_SCHEDULER_shutdown ();
418 if ((GNUNET_ARM_RESULT_STARTING != result) &&
419 (GNUNET_ARM_RESULT_IS_STARTED_ALREADY != result))
422 _("Failed to start the `%s' service: %s\n"),
424 ret_string (result));
425 GNUNET_SCHEDULER_shutdown ();
428 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
429 "Service %s [re]started successfully\n",
433 al_task = GNUNET_SCHEDULER_add_now (&action_loop, NULL);
438 * We have requested a service to be stopped, this function
439 * is called with the result of the operation. Informs the
440 * use of the result; on success, we continue with the event
441 * loop, on failure we terminate the process.
443 * @param cls closure unused
444 * @param rs what happened to our request
445 * @param result if the request was processed, this is the result
449 term_callback (void *cls,
450 enum GNUNET_ARM_RequestStatus rs,
451 enum GNUNET_ARM_Result result)
456 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
458 GNUNET_asprintf (&msg,
459 _("Failed to send a request to kill the `%s' service: %%s\n"),
461 FPRINTF (stdout, msg, req_string (rs));
463 GNUNET_SCHEDULER_shutdown ();
466 if ((GNUNET_ARM_RESULT_STOPPED != result) &&
467 (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY != result))
470 _("Failed to kill the `%s' service: %s\n"),
472 ret_string (result));
473 GNUNET_SCHEDULER_shutdown ();
477 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
478 "Service %s stopped successfully\n",
482 al_task = GNUNET_SCHEDULER_add_now (&action_loop, NULL);
487 * Function called with the list of running services. Prints
488 * the list to stdout, then starts the event loop again.
489 * Prints an error message and terminates the process on errors.
491 * @param cls closure (unused)
492 * @param rs request status (success, failure, etc.)
493 * @param count number of services in the list
494 * @param list list of services that are running
497 list_callback (void *cls,
498 enum GNUNET_ARM_RequestStatus rs,
500 const char *const*list)
505 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
509 GNUNET_asprintf (&msg, "%s",
510 _("Failed to request a list of services: %s\n"));
511 FPRINTF (stdout, msg, req_string (rs));
514 GNUNET_SCHEDULER_shutdown ();
518 FPRINTF (stderr, "%s",
519 _("Error communicating with ARM. ARM not running?\n"));
520 GNUNET_SCHEDULER_shutdown ();
525 FPRINTF (stdout, "%s", _("Running services:\n"));
526 for (i = 0; i < count; i++)
527 FPRINTF (stdout, "%s\n", list[i]);
528 al_task = GNUNET_SCHEDULER_add_now (&action_loop, NULL);
533 * Main action loop. Runs the various jobs that we've been asked to
536 * @param cls closure, unused
539 action_loop (void *cls)
542 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
543 "Running requested actions\n");
551 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
552 "Termination action\n");
553 op = GNUNET_ARM_request_service_stop (h,
563 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
565 op = GNUNET_ARM_request_service_stop (h,
575 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
577 op = GNUNET_ARM_request_service_start (h, "arm",
578 (no_stdout ? 0 : GNUNET_OS_INHERIT_STD_OUT) |
579 (no_stderr ? 0 : GNUNET_OS_INHERIT_STD_ERR),
588 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
589 "Initialization action\n");
590 op = GNUNET_ARM_request_service_start (h, init,
591 GNUNET_OS_INHERIT_STD_NONE,
600 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
601 "Going to list all running services controlled by ARM.\n");
602 op = GNUNET_ARM_request_service_list (h,
613 _("Now only monitoring, press CTRL-C to stop.\n"));
614 quiet = 0; /* does not make sense to stay quiet in monitor mode at this time */
615 return; /* done with tasks, just monitor */
618 default: /* last phase */
619 GNUNET_SCHEDULER_shutdown ();
627 * Function called when a service starts or stops.
630 * @param service service name
631 * @param status status of the service
634 srv_status (void *cls,
636 enum GNUNET_ARM_ServiceStatus status)
642 case GNUNET_ARM_SERVICE_MONITORING_STARTED:
643 return; /* this should be done silently */
644 case GNUNET_ARM_SERVICE_STOPPED:
645 msg = _("Stopped %s.\n");
647 case GNUNET_ARM_SERVICE_STARTING:
648 msg = _("Starting %s...\n");
650 case GNUNET_ARM_SERVICE_STOPPING:
651 msg = _("Stopping %s...\n");
665 _("Unknown status %u for service %s.\n"),
669 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
670 "Got service %s status %d\n",
677 * Task run on timeout (if -T is given).
680 timeout_task_cb (void *cls)
684 GNUNET_SCHEDULER_shutdown ();
689 * Main function that will be run by the scheduler.
692 * @param args remaining command-line arguments
693 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
694 * @param c configuration
700 const struct GNUNET_CONFIGURATION_Handle *c)
704 cfg = GNUNET_CONFIGURATION_dup (c);
706 GNUNET_CONFIGURATION_get_value_string (cfg,
711 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
716 (void) GNUNET_CONFIGURATION_get_value_filename (cfg,
720 if (NULL == (h = GNUNET_ARM_connect (cfg,
725 m = GNUNET_ARM_monitor_start (cfg,
728 al_task = GNUNET_SCHEDULER_add_now (&action_loop,
730 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
732 if (0 != timeout.rel_value_us)
733 timeout_task = GNUNET_SCHEDULER_add_delayed (timeout,
740 * The main function to obtain arm from gnunetd.
742 * @param argc number of arguments from the command line
743 * @param argv command line arguments
744 * @return 0 ok, 1 on error, 2 on timeout
750 struct GNUNET_GETOPT_CommandLineOption options[] = {
751 GNUNET_GETOPT_option_flag ('e',
753 gettext_noop ("stop all GNUnet services"),
755 GNUNET_GETOPT_option_string ('i',
758 gettext_noop ("start a particular service"),
760 GNUNET_GETOPT_option_string ('k',
763 gettext_noop ("stop a particular service"),
765 GNUNET_GETOPT_option_flag ('s',
767 gettext_noop ("start all GNUnet default services"),
769 GNUNET_GETOPT_option_flag ('r',
771 gettext_noop ("stop and start all GNUnet default services"),
773 GNUNET_GETOPT_option_flag ('d',
775 gettext_noop ("delete config file and directory on exit"),
777 GNUNET_GETOPT_option_flag ('m',
779 gettext_noop ("monitor ARM activities"),
781 GNUNET_GETOPT_option_flag ('q',
783 gettext_noop ("don't print status messages"),
785 GNUNET_GETOPT_option_relative_time ('T',
788 gettext_noop ("exit with error status if operation does not finish after DELAY"),
790 GNUNET_GETOPT_option_flag ('I',
792 gettext_noop ("list currently running services"),
794 GNUNET_GETOPT_option_flag ('O',
796 gettext_noop ("don't let gnunet-service-arm inherit standard output"),
798 GNUNET_GETOPT_option_flag ('E',
800 gettext_noop ("don't let gnunet-service-arm inherit standard error"),
802 GNUNET_GETOPT_OPTION_END
806 GNUNET_STRINGS_get_utf8_args (argc, argv,
811 GNUNET_PROGRAM_run (argc,
815 ("Control services and the Automated Restart Manager (ARM)"),
819 GNUNET_free ((void *) argv);
822 GNUNET_free ((void*) argv);
826 /* end of gnunet-arm.c */