reindenting with clang
[oweals/gnunet.git] / src / arm / gnunet-arm.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009, 2012, 2013 GNUnet e.V.
4
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.
9
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.
14
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/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21 /**
22  * @file arm/gnunet-arm.c
23  * @brief arm for writing a tool
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_arm_service.h"
28 #include "gnunet_constants.h"
29 #include "gnunet_util_lib.h"
30
31 /**
32  * Set if we are to shutdown all services (including ARM).
33  */
34 static int end;
35
36 /**
37  * Set if we are to start default services (including ARM).
38  */
39 static int start;
40
41 /**
42  * Set if we are to stop/start default services (including ARM).
43  */
44 static int restart;
45
46 /**
47  * Set if we should delete configuration and temp directory on exit.
48  */
49 static int delete;
50
51 /**
52  * Set if we should not print status messages.
53  */
54 static int quiet;
55
56 /**
57  * Monitor ARM activity.
58  */
59 static int monitor;
60
61 /**
62  * Set if we should print a list of currently running services.
63  */
64 static int list;
65
66 /**
67  * Set to the name of a service to start.
68  */
69 static char *init;
70
71 /**
72  * Set to the name of a service to kill.
73  */
74 static char *term;
75
76 /**
77  * Set to the name of the config file used.
78  */
79 static char *config_file;
80
81 /**
82  * Set to the directory where runtime files are stored.
83  */
84 static char *dir;
85
86 /**
87  * Final status code.
88  */
89 static int ret;
90
91 /**
92  * Connection with ARM.
93  */
94 static struct GNUNET_ARM_Handle *h;
95
96 /**
97  * Monitor connection with ARM.
98  */
99 static struct GNUNET_ARM_MonitorHandle *m;
100
101 /**
102  * Our configuration.
103  */
104 static struct GNUNET_CONFIGURATION_Handle *cfg;
105
106 /**
107  * Processing stage that we are in.  Simple counter.
108  */
109 static unsigned int phase;
110
111 /**
112  * User defined timestamp for completing operations.
113  */
114 static struct GNUNET_TIME_Relative timeout;
115
116 /**
117  * Task to be run on timeout.
118  */
119 static struct GNUNET_SCHEDULER_Task *timeout_task;
120
121 /**
122  * Do we want to give our stdout to gnunet-service-arm?
123  */
124 static int no_stdout;
125
126 /**
127  * Do we want to give our stderr to gnunet-service-arm?
128  */
129 static int no_stderr;
130
131 /**
132  * Handle for the task running the #action_loop().
133  */
134 static struct GNUNET_SCHEDULER_Task *al_task;
135
136 /**
137  * Current operation.
138  */
139 static struct GNUNET_ARM_Operation *op;
140
141 /**
142  * Attempts to delete configuration file and GNUNET_HOME
143  * on ARM shutdown provided the end and delete options
144  * were specified when gnunet-arm was run.
145  */
146 static void
147 delete_files ()
148 {
149   GNUNET_log (
150     GNUNET_ERROR_TYPE_DEBUG,
151     "Will attempt to remove configuration file %s and service directory %s\n",
152     config_file,
153     dir);
154   if (0 != UNLINK (config_file))
155   {
156     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
157                 _ ("Failed to remove configuration file %s\n"),
158                 config_file);
159   }
160   if (GNUNET_OK != GNUNET_DISK_directory_remove (dir))
161   {
162     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
163                 _ ("Failed to remove servicehome directory %s\n"),
164                 dir);
165   }
166 }
167
168
169 /**
170  * Main continuation-passing-style loop.  Runs the various
171  * jobs that we've been asked to do in order.
172  *
173  * @param cls closure, unused
174  */
175 static void
176 shutdown_task (void *cls)
177 {
178   (void) cls;
179   if (NULL != al_task)
180   {
181     GNUNET_SCHEDULER_cancel (al_task);
182     al_task = NULL;
183   }
184   if (NULL != op)
185   {
186     GNUNET_ARM_operation_cancel (op);
187     op = NULL;
188   }
189   if (NULL != h)
190   {
191     GNUNET_ARM_disconnect (h);
192     h = NULL;
193   }
194   if (NULL != m)
195   {
196     GNUNET_ARM_monitor_stop (m);
197     m = NULL;
198   }
199   if (NULL != timeout_task)
200   {
201     GNUNET_SCHEDULER_cancel (timeout_task);
202     timeout_task = NULL;
203   }
204   if ((GNUNET_YES == end) && (GNUNET_YES == delete))
205     delete_files ();
206   GNUNET_CONFIGURATION_destroy (cfg);
207   cfg = NULL;
208 }
209
210
211 /**
212  * Returns a string interpretation of @a rs
213  *
214  * @param rs the request status from ARM
215  * @return a string interpretation of the request status
216  */
217 static const char *
218 req_string (enum GNUNET_ARM_RequestStatus rs)
219 {
220   switch (rs)
221   {
222   case GNUNET_ARM_REQUEST_SENT_OK:
223     return _ ("Message was sent successfully");
224   case GNUNET_ARM_REQUEST_DISCONNECTED:
225     return _ ("We disconnected from ARM before we could send a request");
226   }
227   return _ ("Unknown request status");
228 }
229
230
231 /**
232  * Returns a string interpretation of the @a result
233  *
234  * @param result the arm result
235  * @return a string interpretation
236  */
237 static const char *
238 ret_string (enum GNUNET_ARM_Result result)
239 {
240   switch (result)
241   {
242   case GNUNET_ARM_RESULT_STOPPED:
243     return _ ("is stopped");
244   case GNUNET_ARM_RESULT_STARTING:
245     return _ ("is starting");
246   case GNUNET_ARM_RESULT_STOPPING:
247     return _ ("is stopping");
248   case GNUNET_ARM_RESULT_IS_STARTING_ALREADY:
249     return _ ("is starting already");
250   case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY:
251     return _ ("is stopping already");
252   case GNUNET_ARM_RESULT_IS_STARTED_ALREADY:
253     return _ ("is started already");
254   case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY:
255     return _ ("is stopped already");
256   case GNUNET_ARM_RESULT_IS_NOT_KNOWN:
257     return _ ("service is not known to ARM");
258   case GNUNET_ARM_RESULT_START_FAILED:
259     return _ ("service failed to start");
260   case GNUNET_ARM_RESULT_IN_SHUTDOWN:
261     return _ ("service cannot be manipulated because ARM is shutting down");
262   }
263   return _ ("Unknown result code.");
264 }
265
266
267 /**
268  * Main task that runs our various operations in order.
269  *
270  * @param cls closure
271  */
272 static void
273 action_loop (void *cls);
274
275
276 /**
277  * Function called whenever we connect to or disconnect from ARM.
278  * Termiantes the process if we fail to connect to the service on
279  * our first attempt.
280  *
281  * @param cls closure
282  * @param connected #GNUNET_YES if connected, #GNUNET_NO if disconnected,
283  *                  #GNUNET_SYSERR on error.
284  */
285 static void
286 conn_status (void *cls, int connected)
287 {
288   static int once;
289
290   (void) cls;
291   if ((GNUNET_SYSERR == connected) && (0 == once))
292   {
293     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
294                 _ ("Fatal error initializing ARM API.\n"));
295     GNUNET_SCHEDULER_shutdown ();
296     return;
297   }
298   once = 1;
299 }
300
301
302 /**
303  * We have requested ARM to be started, this function
304  * is called with the result of the operation.  Informs the
305  * use of the result; on success, we continue with the event
306  * loop, on failure we terminate the process.
307  *
308  * @param cls closure unused
309  * @param rs what happened to our request
310  * @param result if the request was processed, this is the result
311  *               according to ARM
312  */
313 static void
314 start_callback (void *cls,
315                 enum GNUNET_ARM_RequestStatus rs,
316                 enum GNUNET_ARM_Result result)
317 {
318   (void) cls;
319   op = NULL;
320   if (GNUNET_ARM_REQUEST_SENT_OK != rs)
321   {
322     FPRINTF (stdout,
323              _ ("Failed to start the ARM service: %s\n"),
324              req_string (rs));
325     GNUNET_SCHEDULER_shutdown ();
326     return;
327   }
328   if ((GNUNET_ARM_RESULT_STARTING != result) &&
329       (GNUNET_ARM_RESULT_IS_STARTED_ALREADY != result))
330   {
331     FPRINTF (stdout,
332              _ ("Failed to start the ARM service: %s\n"),
333              ret_string (result));
334     GNUNET_SCHEDULER_shutdown ();
335     return;
336   }
337   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM service [re]start successful\n");
338   start = 0;
339   al_task = GNUNET_SCHEDULER_add_now (&action_loop, NULL);
340 }
341
342
343 /**
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.
348  *
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
352  *               according to ARM
353  */
354 static void
355 stop_callback (void *cls,
356                enum GNUNET_ARM_RequestStatus rs,
357                enum GNUNET_ARM_Result result)
358 {
359   char *msg;
360
361   (void) cls;
362   op = NULL;
363   if (GNUNET_ARM_REQUEST_SENT_OK != rs)
364   {
365     GNUNET_asprintf (&msg,
366                      "%s",
367                      _ (
368                        "Failed to send a stop request to the ARM service: %s\n"));
369     FPRINTF (stdout, msg, req_string (rs));
370     GNUNET_free (msg);
371     GNUNET_SCHEDULER_shutdown ();
372     return;
373   }
374   if ((GNUNET_ARM_RESULT_STOPPING != result) &&
375       (GNUNET_ARM_RESULT_STOPPED != result) &&
376       (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY != result))
377   {
378     FPRINTF (stdout,
379              _ ("Failed to stop the ARM service: %s\n"),
380              ret_string (result));
381     GNUNET_SCHEDULER_shutdown ();
382     return;
383   }
384   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM service shutdown successful\n");
385   end = 0;
386   if (restart)
387   {
388     restart = 0;
389     start = 1;
390     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Initiating an ARM restart\n");
391   }
392   al_task = GNUNET_SCHEDULER_add_now (&action_loop, NULL);
393 }
394
395
396 /**
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.
401  *
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
405  *               according to ARM
406  */
407 static void
408 init_callback (void *cls,
409                enum GNUNET_ARM_RequestStatus rs,
410                enum GNUNET_ARM_Result result)
411 {
412   (void) cls;
413   op = NULL;
414   if (GNUNET_ARM_REQUEST_SENT_OK != rs)
415   {
416     FPRINTF (stdout,
417              _ ("Failed to send a request to start the `%s' service: %s\n"),
418              init,
419              req_string (rs));
420     GNUNET_SCHEDULER_shutdown ();
421     return;
422   }
423   if ((GNUNET_ARM_RESULT_STARTING != result) &&
424       (GNUNET_ARM_RESULT_IS_STARTED_ALREADY != result))
425   {
426     FPRINTF (stdout,
427              _ ("Failed to start the `%s' service: %s\n"),
428              init,
429              ret_string (result));
430     GNUNET_SCHEDULER_shutdown ();
431     return;
432   }
433   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
434               "Service %s [re]started successfully\n",
435               init);
436   GNUNET_free (init);
437   init = NULL;
438   al_task = GNUNET_SCHEDULER_add_now (&action_loop, NULL);
439 }
440
441
442 /**
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.
447  *
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
451  *               according to ARM
452  */
453 static void
454 term_callback (void *cls,
455                enum GNUNET_ARM_RequestStatus rs,
456                enum GNUNET_ARM_Result result)
457 {
458   char *msg;
459
460   (void) cls;
461   op = NULL;
462   if (GNUNET_ARM_REQUEST_SENT_OK != rs)
463   {
464     GNUNET_asprintf (&msg,
465                      _ (
466                        "Failed to send a request to kill the `%s' service: %%s\n"),
467                      term);
468     FPRINTF (stdout, msg, req_string (rs));
469     GNUNET_free (msg);
470     GNUNET_SCHEDULER_shutdown ();
471     return;
472   }
473   if ((GNUNET_ARM_RESULT_STOPPED != result) &&
474       (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY != result))
475   {
476     FPRINTF (stdout,
477              _ ("Failed to kill the `%s' service: %s\n"),
478              term,
479              ret_string (result));
480     GNUNET_SCHEDULER_shutdown ();
481     return;
482   }
483
484   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
485               "Service %s stopped successfully\n",
486               term);
487   GNUNET_free (term);
488   term = NULL;
489   al_task = GNUNET_SCHEDULER_add_now (&action_loop, NULL);
490 }
491
492
493 /**
494  * Function called with the list of running services. Prints
495  * the list to stdout, then starts the event loop again.
496  * Prints an error message and terminates the process on errors.
497  *
498  * @param cls closure (unused)
499  * @param rs request status (success, failure, etc.)
500  * @param count number of services in the list
501  * @param list list of services that are running
502  */
503 static void
504 list_callback (void *cls,
505                enum GNUNET_ARM_RequestStatus rs,
506                unsigned int count,
507                const char *const *list)
508 {
509   (void) cls;
510   op = NULL;
511   if (GNUNET_ARM_REQUEST_SENT_OK != rs)
512   {
513     char *msg;
514
515     GNUNET_asprintf (&msg,
516                      "%s",
517                      _ ("Failed to request a list of services: %s\n"));
518     FPRINTF (stdout, msg, req_string (rs));
519     GNUNET_free (msg);
520     ret = 3;
521     GNUNET_SCHEDULER_shutdown ();
522   }
523   if (NULL == list)
524   {
525     FPRINTF (stderr,
526              "%s",
527              _ ("Error communicating with ARM. ARM not running?\n"));
528     GNUNET_SCHEDULER_shutdown ();
529     ret = 3;
530     return;
531   }
532   if (! quiet)
533     FPRINTF (stdout, "%s", _ ("Running services:\n"));
534   for (unsigned int i = 0; i < count; i++)
535     FPRINTF (stdout, "%s\n", list[i]);
536   al_task = GNUNET_SCHEDULER_add_now (&action_loop, NULL);
537 }
538
539
540 /**
541  * Main action loop.  Runs the various jobs that we've been asked to
542  * do, in order.
543  *
544  * @param cls closure, unused
545  */
546 static void
547 action_loop (void *cls)
548 {
549   (void) cls;
550   al_task = NULL;
551   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Running requested actions\n");
552   while (1)
553   {
554     switch (phase++)
555     {
556     case 0:
557       if (NULL != term)
558       {
559         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Termination action\n");
560         op = GNUNET_ARM_request_service_stop (h, term, &term_callback, NULL);
561         return;
562       }
563       break;
564     case 1:
565       if (end || restart)
566       {
567         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "End action\n");
568         op = GNUNET_ARM_request_service_stop (h, "arm", &stop_callback, NULL);
569         return;
570       }
571       break;
572     case 2:
573       if (start)
574       {
575         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Start action\n");
576         op =
577           GNUNET_ARM_request_service_start (h,
578                                             "arm",
579                                             (no_stdout
580                                                ? 0
581                                                : GNUNET_OS_INHERIT_STD_OUT) |
582                                               (no_stderr
583                                                  ? 0
584                                                  : GNUNET_OS_INHERIT_STD_ERR),
585                                             &start_callback,
586                                             NULL);
587         return;
588       }
589       break;
590     case 3:
591       if (NULL != init)
592       {
593         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Initialization action\n");
594         op = GNUNET_ARM_request_service_start (h,
595                                                init,
596                                                GNUNET_OS_INHERIT_STD_NONE,
597                                                &init_callback,
598                                                NULL);
599         return;
600       }
601       break;
602     case 4:
603       if (list)
604       {
605         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
606                     "Going to list all running services controlled by ARM.\n");
607         op = GNUNET_ARM_request_service_list (h, &list_callback, &list);
608         return;
609       }
610       break;
611     case 5:
612       if (monitor)
613       {
614         if (! quiet)
615           fprintf (stderr, _ ("Now only monitoring, press CTRL-C to stop.\n"));
616         quiet =
617           0; /* does not make sense to stay quiet in monitor mode at this time */
618         return; /* done with tasks, just monitor */
619       }
620       break;
621     default: /* last phase */
622       GNUNET_SCHEDULER_shutdown ();
623       return;
624     }
625   }
626 }
627
628
629 /**
630  * Function called when a service starts or stops.
631  *
632  * @param cls closure
633  * @param service service name
634  * @param status status of the service
635  */
636 static void
637 srv_status (void *cls,
638             const char *service,
639             enum GNUNET_ARM_ServiceStatus status)
640 {
641   const char *msg;
642
643   (void) cls;
644   switch (status)
645   {
646   case GNUNET_ARM_SERVICE_MONITORING_STARTED:
647     return; /* this should be done silently */
648   case GNUNET_ARM_SERVICE_STOPPED:
649     msg = _ ("Stopped %s.\n");
650     break;
651   case GNUNET_ARM_SERVICE_STARTING:
652     msg = _ ("Starting %s...\n");
653     break;
654   case GNUNET_ARM_SERVICE_STOPPING:
655     msg = _ ("Stopping %s...\n");
656     break;
657   default:
658     msg = NULL;
659     break;
660   }
661   if (! quiet)
662   {
663     if (NULL != msg)
664       FPRINTF (stderr, msg, service);
665     else
666       FPRINTF (stderr,
667                _ ("Unknown status %u for service %s.\n"),
668                status,
669                service);
670   }
671   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
672               "Got service %s status %d\n",
673               service,
674               (int) status);
675 }
676
677
678 /**
679  * Task run on timeout (if -T is given).
680  */
681 static void
682 timeout_task_cb (void *cls)
683 {
684   (void) cls;
685   timeout_task = NULL;
686   ret = 2;
687   GNUNET_SCHEDULER_shutdown ();
688 }
689
690
691 /**
692  * Main function that will be run by the scheduler.
693  *
694  * @param cls closure
695  * @param args remaining command-line arguments
696  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
697  * @param c configuration
698  */
699 static void
700 run (void *cls,
701      char *const *args,
702      const char *cfgfile,
703      const struct GNUNET_CONFIGURATION_Handle *c)
704 {
705   (void) cls;
706   (void) args;
707   (void) cfgfile;
708   cfg = GNUNET_CONFIGURATION_dup (c);
709   if (GNUNET_OK !=
710       GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", "GNUNET_HOME", &dir))
711   {
712     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "PATHS", "GNUNET_HOME");
713     return;
714   }
715   (void) GNUNET_CONFIGURATION_get_value_filename (cfg,
716                                                   "arm",
717                                                   "CONFIG",
718                                                   &config_file);
719   if (NULL == (h = GNUNET_ARM_connect (cfg, &conn_status, NULL)))
720     return;
721   if (monitor)
722     m = GNUNET_ARM_monitor_start (cfg, &srv_status, NULL);
723   al_task = GNUNET_SCHEDULER_add_now (&action_loop, NULL);
724   GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
725   if (0 != timeout.rel_value_us)
726     timeout_task =
727       GNUNET_SCHEDULER_add_delayed (timeout, &timeout_task_cb, NULL);
728 }
729
730
731 /**
732  * The main function to obtain arm from gnunetd.
733  *
734  * @param argc number of arguments from the command line
735  * @param argv command line arguments
736  * @return 0 ok, 1 on error, 2 on timeout
737  */
738 int
739 main (int argc, char *const *argv)
740 {
741   struct GNUNET_GETOPT_CommandLineOption options[] =
742     {GNUNET_GETOPT_option_flag ('e',
743                                 "end",
744                                 gettext_noop ("stop all GNUnet services"),
745                                 &end),
746      GNUNET_GETOPT_option_string ('i',
747                                   "init",
748                                   "SERVICE",
749                                   gettext_noop ("start a particular service"),
750                                   &init),
751      GNUNET_GETOPT_option_string ('k',
752                                   "kill",
753                                   "SERVICE",
754                                   gettext_noop ("stop a particular service"),
755                                   &term),
756      GNUNET_GETOPT_option_flag ('s',
757                                 "start",
758                                 gettext_noop (
759                                   "start all GNUnet default services"),
760                                 &start),
761      GNUNET_GETOPT_option_flag ('r',
762                                 "restart",
763                                 gettext_noop (
764                                   "stop and start all GNUnet default services"),
765                                 &restart),
766      GNUNET_GETOPT_option_flag ('d',
767                                 "delete",
768                                 gettext_noop (
769                                   "delete config file and directory on exit"),
770                                 &delete),
771      GNUNET_GETOPT_option_flag ('m',
772                                 "monitor",
773                                 gettext_noop ("monitor ARM activities"),
774                                 &monitor),
775      GNUNET_GETOPT_option_flag ('q',
776                                 "quiet",
777                                 gettext_noop ("don't print status messages"),
778                                 &quiet),
779      GNUNET_GETOPT_option_relative_time (
780        'T',
781        "timeout",
782        "DELAY",
783        gettext_noop (
784          "exit with error status if operation does not finish after DELAY"),
785        &timeout),
786      GNUNET_GETOPT_option_flag ('I',
787                                 "info",
788                                 gettext_noop (
789                                   "list currently running services"),
790                                 &list),
791      GNUNET_GETOPT_option_flag (
792        'O',
793        "no-stdout",
794        gettext_noop ("don't let gnunet-service-arm inherit standard output"),
795        &no_stdout),
796      GNUNET_GETOPT_option_flag (
797        'E',
798        "no-stderr",
799        gettext_noop ("don't let gnunet-service-arm inherit standard error"),
800        &no_stderr),
801      GNUNET_GETOPT_OPTION_END};
802
803   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
804     return 2;
805   if (GNUNET_OK ==
806       GNUNET_PROGRAM_run (
807         argc,
808         argv,
809         "gnunet-arm",
810         gettext_noop (
811           "Control services and the Automated Restart Manager (ARM)"),
812         options,
813         &run,
814         NULL))
815   {
816     GNUNET_free ((void *) argv);
817     return ret;
818   }
819   GNUNET_free ((void *) argv);
820   return 1;
821 }
822
823 /* end of gnunet-arm.c */