diff options
Diffstat (limited to 'src/cli/arm/gnunet-arm.c')
-rw-r--r-- | src/cli/arm/gnunet-arm.c | 1065 |
1 files changed, 1065 insertions, 0 deletions
diff --git a/src/cli/arm/gnunet-arm.c b/src/cli/arm/gnunet-arm.c new file mode 100644 index 000000000..ea3a012ab --- /dev/null +++ b/src/cli/arm/gnunet-arm.c | |||
@@ -0,0 +1,1065 @@ | |||
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 | * Set if we should print all services, including stopped ones. | ||
58 | */ | ||
59 | static int show_all; | ||
60 | |||
61 | /** | ||
62 | * Monitor ARM activity. | ||
63 | */ | ||
64 | static int monitor; | ||
65 | |||
66 | /** | ||
67 | * Set if we should print a list of currently running services. | ||
68 | */ | ||
69 | static int list; | ||
70 | |||
71 | /** | ||
72 | * Set to the name of a service to start. | ||
73 | */ | ||
74 | static char *init; | ||
75 | |||
76 | /** | ||
77 | * Set to the name of a service to kill. | ||
78 | */ | ||
79 | static char *term; | ||
80 | |||
81 | /** | ||
82 | * Set to the name of the config file used. | ||
83 | */ | ||
84 | static char *config_file; | ||
85 | |||
86 | /** | ||
87 | * Set to the directory where runtime files are stored. | ||
88 | */ | ||
89 | static char *dir; | ||
90 | |||
91 | /** | ||
92 | * Final status code. | ||
93 | */ | ||
94 | static int ret; | ||
95 | |||
96 | /** | ||
97 | * Connection with ARM. | ||
98 | */ | ||
99 | static struct GNUNET_ARM_Handle *h; | ||
100 | |||
101 | /** | ||
102 | * Monitor connection with ARM. | ||
103 | */ | ||
104 | static struct GNUNET_ARM_MonitorHandle *m; | ||
105 | |||
106 | /** | ||
107 | * Our configuration. | ||
108 | */ | ||
109 | static struct GNUNET_CONFIGURATION_Handle *cfg; | ||
110 | |||
111 | /** | ||
112 | * Processing stage that we are in. Simple counter. | ||
113 | */ | ||
114 | static unsigned int phase; | ||
115 | |||
116 | /** | ||
117 | * User defined timestamp for completing operations. | ||
118 | */ | ||
119 | static struct GNUNET_TIME_Relative timeout; | ||
120 | |||
121 | /** | ||
122 | * Task to be run on timeout. | ||
123 | */ | ||
124 | static struct GNUNET_SCHEDULER_Task *timeout_task; | ||
125 | |||
126 | /** | ||
127 | * Do we want to give our stdout to gnunet-service-arm? | ||
128 | */ | ||
129 | static int no_stdout; | ||
130 | |||
131 | /** | ||
132 | * Do we want to give our stderr to gnunet-service-arm? | ||
133 | */ | ||
134 | static int no_stderr; | ||
135 | |||
136 | /** | ||
137 | * Handle for the task running the #action_loop(). | ||
138 | */ | ||
139 | static struct GNUNET_SCHEDULER_Task *al_task; | ||
140 | |||
141 | /** | ||
142 | * Current operation. | ||
143 | */ | ||
144 | static struct GNUNET_ARM_Operation *op; | ||
145 | |||
146 | /** | ||
147 | * Attempts to delete configuration file and GNUNET_HOME | ||
148 | * on ARM shutdown provided the end and delete options | ||
149 | * were specified when gnunet-arm was run. | ||
150 | */ | ||
151 | static void | ||
152 | delete_files () | ||
153 | { | ||
154 | GNUNET_log ( | ||
155 | GNUNET_ERROR_TYPE_DEBUG, | ||
156 | "Will attempt to remove configuration file %s and service directory %s\n", | ||
157 | config_file, | ||
158 | dir); | ||
159 | if (0 != unlink (config_file)) | ||
160 | { | ||
161 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
162 | _ ("Failed to remove configuration file %s\n"), | ||
163 | config_file); | ||
164 | } | ||
165 | if (GNUNET_OK != GNUNET_DISK_directory_remove (dir)) | ||
166 | { | ||
167 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
168 | _ ("Failed to remove servicehome directory %s\n"), | ||
169 | dir); | ||
170 | } | ||
171 | } | ||
172 | |||
173 | |||
174 | /** | ||
175 | * Main continuation-passing-style loop. Runs the various | ||
176 | * jobs that we've been asked to do in order. | ||
177 | * | ||
178 | * @param cls closure, unused | ||
179 | */ | ||
180 | static void | ||
181 | shutdown_task (void *cls) | ||
182 | { | ||
183 | (void) cls; | ||
184 | if (NULL != al_task) | ||
185 | { | ||
186 | GNUNET_SCHEDULER_cancel (al_task); | ||
187 | al_task = NULL; | ||
188 | } | ||
189 | if (NULL != op) | ||
190 | { | ||
191 | GNUNET_ARM_operation_cancel (op); | ||
192 | op = NULL; | ||
193 | } | ||
194 | if (NULL != h) | ||
195 | { | ||
196 | GNUNET_ARM_disconnect (h); | ||
197 | h = NULL; | ||
198 | } | ||
199 | if (NULL != m) | ||
200 | { | ||
201 | GNUNET_ARM_monitor_stop (m); | ||
202 | m = NULL; | ||
203 | } | ||
204 | if (NULL != timeout_task) | ||
205 | { | ||
206 | GNUNET_SCHEDULER_cancel (timeout_task); | ||
207 | timeout_task = NULL; | ||
208 | } | ||
209 | if ( (GNUNET_YES == end) && | ||
210 | (GNUNET_YES == delete) ) | ||
211 | delete_files (); | ||
212 | GNUNET_CONFIGURATION_destroy (cfg); | ||
213 | cfg = NULL; | ||
214 | } | ||
215 | |||
216 | |||
217 | /** | ||
218 | * Returns a string interpretation of @a rs | ||
219 | * | ||
220 | * @param rs the request status from ARM | ||
221 | * @return a string interpretation of the request status | ||
222 | */ | ||
223 | static const char * | ||
224 | req_string (enum GNUNET_ARM_RequestStatus rs) | ||
225 | { | ||
226 | switch (rs) | ||
227 | { | ||
228 | case GNUNET_ARM_REQUEST_SENT_OK: | ||
229 | return _ ("Message was sent successfully"); | ||
230 | |||
231 | case GNUNET_ARM_REQUEST_DISCONNECTED: | ||
232 | return _ ("We disconnected from ARM before we could send a request"); | ||
233 | } | ||
234 | return _ ("Unknown request status"); | ||
235 | } | ||
236 | |||
237 | |||
238 | /** | ||
239 | * Returns a string interpretation of the @a result | ||
240 | * | ||
241 | * @param result the arm result | ||
242 | * @return a string interpretation | ||
243 | */ | ||
244 | static const char * | ||
245 | ret_string (enum GNUNET_ARM_Result result) | ||
246 | { | ||
247 | switch (result) | ||
248 | { | ||
249 | case GNUNET_ARM_RESULT_STOPPED: | ||
250 | return _ ("is stopped"); | ||
251 | |||
252 | case GNUNET_ARM_RESULT_STARTING: | ||
253 | return _ ("is starting"); | ||
254 | |||
255 | case GNUNET_ARM_RESULT_STOPPING: | ||
256 | return _ ("is stopping"); | ||
257 | |||
258 | case GNUNET_ARM_RESULT_IS_STARTING_ALREADY: | ||
259 | return _ ("is starting already"); | ||
260 | |||
261 | case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY: | ||
262 | return _ ("is stopping already"); | ||
263 | |||
264 | case GNUNET_ARM_RESULT_IS_STARTED_ALREADY: | ||
265 | return _ ("is started already"); | ||
266 | |||
267 | case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY: | ||
268 | return _ ("is stopped already"); | ||
269 | |||
270 | case GNUNET_ARM_RESULT_IS_NOT_KNOWN: | ||
271 | return _ ("service is not known to ARM"); | ||
272 | |||
273 | case GNUNET_ARM_RESULT_START_FAILED: | ||
274 | return _ ("service failed to start"); | ||
275 | |||
276 | case GNUNET_ARM_RESULT_IN_SHUTDOWN: | ||
277 | return _ ("service cannot be manipulated because ARM is shutting down"); | ||
278 | } | ||
279 | return _ ("Unknown result code."); | ||
280 | } | ||
281 | |||
282 | |||
283 | /** | ||
284 | * Main task that runs our various operations in order. | ||
285 | * | ||
286 | * @param cls closure | ||
287 | */ | ||
288 | static void | ||
289 | action_loop (void *cls); | ||
290 | |||
291 | |||
292 | /** | ||
293 | * Function called whenever we connect to or disconnect from ARM. | ||
294 | * Termiantes the process if we fail to connect to the service on | ||
295 | * our first attempt. | ||
296 | * | ||
297 | * @param cls closure | ||
298 | * @param connected #GNUNET_YES if connected, #GNUNET_NO if disconnected, | ||
299 | * #GNUNET_SYSERR on error. | ||
300 | */ | ||
301 | static void | ||
302 | conn_status (void *cls, | ||
303 | int connected) | ||
304 | { | ||
305 | static int once; | ||
306 | |||
307 | (void) cls; | ||
308 | if ( (GNUNET_SYSERR == connected) && | ||
309 | (0 == once) ) | ||
310 | { | ||
311 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
312 | _ ("Fatal error initializing ARM API.\n")); | ||
313 | GNUNET_SCHEDULER_shutdown (); | ||
314 | return; | ||
315 | } | ||
316 | once = 1; | ||
317 | } | ||
318 | |||
319 | |||
320 | /** | ||
321 | * We have requested ARM to be started, this function | ||
322 | * is called with the result of the operation. Informs the | ||
323 | * use of the result; on success, we continue with the event | ||
324 | * loop, on failure we terminate the process. | ||
325 | * | ||
326 | * @param cls closure unused | ||
327 | * @param rs what happened to our request | ||
328 | * @param result if the request was processed, this is the result | ||
329 | * according to ARM | ||
330 | */ | ||
331 | static void | ||
332 | start_callback (void *cls, | ||
333 | enum GNUNET_ARM_RequestStatus rs, | ||
334 | enum GNUNET_ARM_Result result) | ||
335 | { | ||
336 | (void) cls; | ||
337 | op = NULL; | ||
338 | if (GNUNET_ARM_REQUEST_SENT_OK != rs) | ||
339 | { | ||
340 | fprintf (stdout, | ||
341 | _ ("Failed to start the ARM service: %s\n"), | ||
342 | req_string (rs)); | ||
343 | GNUNET_SCHEDULER_shutdown (); | ||
344 | return; | ||
345 | } | ||
346 | if ((GNUNET_ARM_RESULT_STARTING != result) && | ||
347 | (GNUNET_ARM_RESULT_IS_STARTED_ALREADY != result)) | ||
348 | { | ||
349 | fprintf (stdout, | ||
350 | _ ("Failed to start the ARM service: %s\n"), | ||
351 | ret_string (result)); | ||
352 | GNUNET_SCHEDULER_shutdown (); | ||
353 | return; | ||
354 | } | ||
355 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
356 | "ARM service [re]start successful\n"); | ||
357 | start = 0; | ||
358 | al_task = GNUNET_SCHEDULER_add_now (&action_loop, | ||
359 | NULL); | ||
360 | } | ||
361 | |||
362 | |||
363 | /** | ||
364 | * We have requested ARM to be stopped, this function | ||
365 | * is called with the result of the operation. Informs the | ||
366 | * use of the result; on success, we continue with the event | ||
367 | * loop, on failure we terminate the process. | ||
368 | * | ||
369 | * @param cls closure unused | ||
370 | * @param rs what happened to our request | ||
371 | * @param result if the request was processed, this is the result | ||
372 | * according to ARM | ||
373 | */ | ||
374 | static void | ||
375 | stop_callback (void *cls, | ||
376 | enum GNUNET_ARM_RequestStatus rs, | ||
377 | enum GNUNET_ARM_Result result) | ||
378 | { | ||
379 | char *msg; | ||
380 | |||
381 | (void) cls; | ||
382 | op = NULL; | ||
383 | if (GNUNET_ARM_REQUEST_SENT_OK != rs) | ||
384 | { | ||
385 | GNUNET_asprintf (&msg, | ||
386 | "%s", | ||
387 | _ ( | ||
388 | "Failed to send a stop request to the ARM service: %s\n")); | ||
389 | fprintf (stdout, msg, req_string (rs)); | ||
390 | GNUNET_free (msg); | ||
391 | GNUNET_SCHEDULER_shutdown (); | ||
392 | return; | ||
393 | } | ||
394 | if ( (GNUNET_ARM_RESULT_STOPPING != result) && | ||
395 | (GNUNET_ARM_RESULT_STOPPED != result) && | ||
396 | (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY != result) ) | ||
397 | { | ||
398 | fprintf (stdout, | ||
399 | _ ("Failed to stop the ARM service: %s\n"), | ||
400 | ret_string (result)); | ||
401 | GNUNET_SCHEDULER_shutdown (); | ||
402 | return; | ||
403 | } | ||
404 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
405 | "ARM service shutdown successful\n"); | ||
406 | end = 0; | ||
407 | if (restart) | ||
408 | { | ||
409 | restart = 0; | ||
410 | start = 1; | ||
411 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
412 | "Initiating an ARM restart\n"); | ||
413 | } | ||
414 | al_task = GNUNET_SCHEDULER_add_now (&action_loop, | ||
415 | NULL); | ||
416 | } | ||
417 | |||
418 | |||
419 | /** | ||
420 | * We have requested a service to be started, this function | ||
421 | * is called with the result of the operation. Informs the | ||
422 | * use of the result; on success, we continue with the event | ||
423 | * loop, on failure we terminate the process. | ||
424 | * | ||
425 | * @param cls closure unused | ||
426 | * @param rs what happened to our request | ||
427 | * @param result if the request was processed, this is the result | ||
428 | * according to ARM | ||
429 | */ | ||
430 | static void | ||
431 | init_callback (void *cls, | ||
432 | enum GNUNET_ARM_RequestStatus rs, | ||
433 | enum GNUNET_ARM_Result result) | ||
434 | { | ||
435 | (void) cls; | ||
436 | op = NULL; | ||
437 | if (GNUNET_ARM_REQUEST_SENT_OK != rs) | ||
438 | { | ||
439 | fprintf (stdout, | ||
440 | _ ("Failed to send a request to start the `%s' service: %s\n"), | ||
441 | init, | ||
442 | req_string (rs)); | ||
443 | GNUNET_SCHEDULER_shutdown (); | ||
444 | return; | ||
445 | } | ||
446 | if ((GNUNET_ARM_RESULT_STARTING != result) && | ||
447 | (GNUNET_ARM_RESULT_IS_STARTED_ALREADY != result)) | ||
448 | { | ||
449 | fprintf (stdout, | ||
450 | _ ("Failed to start the `%s' service: %s\n"), | ||
451 | init, | ||
452 | ret_string (result)); | ||
453 | GNUNET_SCHEDULER_shutdown (); | ||
454 | return; | ||
455 | } | ||
456 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
457 | "Service %s [re]started successfully\n", | ||
458 | init); | ||
459 | GNUNET_free (init); | ||
460 | init = NULL; | ||
461 | al_task = GNUNET_SCHEDULER_add_now (&action_loop, | ||
462 | NULL); | ||
463 | } | ||
464 | |||
465 | |||
466 | /** | ||
467 | * We have requested a service to be stopped, this function | ||
468 | * is called with the result of the operation. Informs the | ||
469 | * use of the result; on success, we continue with the event | ||
470 | * loop, on failure we terminate the process. | ||
471 | * | ||
472 | * @param cls closure unused | ||
473 | * @param rs what happened to our request | ||
474 | * @param result if the request was processed, this is the result | ||
475 | * according to ARM | ||
476 | */ | ||
477 | static void | ||
478 | term_callback (void *cls, | ||
479 | enum GNUNET_ARM_RequestStatus rs, | ||
480 | enum GNUNET_ARM_Result result) | ||
481 | { | ||
482 | char *msg; | ||
483 | |||
484 | (void) cls; | ||
485 | op = NULL; | ||
486 | if (GNUNET_ARM_REQUEST_SENT_OK != rs) | ||
487 | { | ||
488 | GNUNET_asprintf (&msg, | ||
489 | _ ( | ||
490 | "Failed to send a request to kill the `%s' service: %%s\n"), | ||
491 | term); | ||
492 | fprintf (stdout, | ||
493 | msg, | ||
494 | req_string (rs)); | ||
495 | GNUNET_free (msg); | ||
496 | GNUNET_SCHEDULER_shutdown (); | ||
497 | return; | ||
498 | } | ||
499 | if ( (GNUNET_ARM_RESULT_STOPPED != result) && | ||
500 | (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY != result) ) | ||
501 | { | ||
502 | fprintf (stdout, | ||
503 | _ ("Failed to kill the `%s' service: %s\n"), | ||
504 | term, | ||
505 | ret_string (result)); | ||
506 | GNUNET_SCHEDULER_shutdown (); | ||
507 | return; | ||
508 | } | ||
509 | |||
510 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
511 | "Service %s stopped successfully\n", | ||
512 | term); | ||
513 | GNUNET_free (term); | ||
514 | term = NULL; | ||
515 | al_task = GNUNET_SCHEDULER_add_now (&action_loop, | ||
516 | NULL); | ||
517 | } | ||
518 | |||
519 | |||
520 | /** | ||
521 | * Function called with the list of running services. Prints | ||
522 | * the list to stdout, then starts the event loop again. | ||
523 | * Prints an error message and terminates the process on errors. | ||
524 | * | ||
525 | * @param cls closure (unused) | ||
526 | * @param rs request status (success, failure, etc.) | ||
527 | * @param count number of services in the list | ||
528 | * @param list list of services managed by arm | ||
529 | */ | ||
530 | static void | ||
531 | list_callback (void *cls, | ||
532 | enum GNUNET_ARM_RequestStatus rs, | ||
533 | unsigned int count, | ||
534 | const struct GNUNET_ARM_ServiceInfo *list) | ||
535 | { | ||
536 | unsigned int num_stopped = 0; | ||
537 | unsigned int num_started = 0; | ||
538 | unsigned int num_stopping = 0; | ||
539 | unsigned int num_failed = 0; | ||
540 | unsigned int num_finished = 0; | ||
541 | (void) cls; | ||
542 | op = NULL; | ||
543 | if (GNUNET_ARM_REQUEST_SENT_OK != rs) | ||
544 | { | ||
545 | char *msg; | ||
546 | |||
547 | GNUNET_asprintf (&msg, | ||
548 | "%s", | ||
549 | _ ("Failed to request a list of services: %s\n")); | ||
550 | fprintf (stdout, | ||
551 | msg, | ||
552 | req_string (rs)); | ||
553 | GNUNET_free (msg); | ||
554 | ret = 3; | ||
555 | GNUNET_SCHEDULER_shutdown (); | ||
556 | } | ||
557 | if (NULL == list) | ||
558 | { | ||
559 | fprintf (stderr, | ||
560 | "%s", | ||
561 | _ ("Error communicating with ARM. ARM not running?\n")); | ||
562 | GNUNET_SCHEDULER_shutdown (); | ||
563 | ret = 3; | ||
564 | return; | ||
565 | } | ||
566 | for (unsigned int i = 0; i < count; i++) | ||
567 | { | ||
568 | switch (list[i].status) | ||
569 | { | ||
570 | case GNUNET_ARM_SERVICE_STATUS_STOPPED: | ||
571 | num_stopped++; | ||
572 | break; | ||
573 | case GNUNET_ARM_SERVICE_STATUS_FAILED: | ||
574 | num_failed++; | ||
575 | break; | ||
576 | case GNUNET_ARM_SERVICE_STATUS_FINISHED: | ||
577 | num_finished++; | ||
578 | break; | ||
579 | case GNUNET_ARM_SERVICE_STATUS_STARTED: | ||
580 | num_started++; | ||
581 | break; | ||
582 | case GNUNET_ARM_SERVICE_STATUS_STOPPING: | ||
583 | num_stopping++; | ||
584 | fprintf (stdout, | ||
585 | "%s (binary='%s', status=stopping)\n", | ||
586 | list[i].name, | ||
587 | list[i].binary); | ||
588 | break; | ||
589 | default: | ||
590 | GNUNET_break_op (0); | ||
591 | fprintf (stdout, | ||
592 | "%s (binary='%s', status=unknown)\n", | ||
593 | list[i].name, | ||
594 | list[i].binary); | ||
595 | break; | ||
596 | } | ||
597 | } | ||
598 | if (! quiet) | ||
599 | { | ||
600 | if (show_all) | ||
601 | fprintf (stdout, | ||
602 | "%s", | ||
603 | _ ("All services:\n")); | ||
604 | else | ||
605 | fprintf (stdout, | ||
606 | "%s", | ||
607 | _ ("Services (excluding stopped services):\n")); | ||
608 | if (num_stopped || num_failed || num_finished || num_stopping || | ||
609 | num_started) | ||
610 | { | ||
611 | int sep = 0; | ||
612 | fprintf (stdout, "("); | ||
613 | if (0 != num_started) | ||
614 | { | ||
615 | if (sep) | ||
616 | fprintf (stdout, " / "); | ||
617 | fprintf (stdout, | ||
618 | "started: %u", | ||
619 | num_started); | ||
620 | sep = 1; | ||
621 | } | ||
622 | if (0 != num_failed) | ||
623 | { | ||
624 | if (sep) | ||
625 | fprintf (stdout, " / "); | ||
626 | fprintf (stdout, | ||
627 | "failed: %u", | ||
628 | num_failed); | ||
629 | sep = 1; | ||
630 | } | ||
631 | if (0 != num_stopping) | ||
632 | { | ||
633 | if (sep) | ||
634 | fprintf (stdout, " / "); | ||
635 | fprintf (stdout, | ||
636 | "stopping: %u", | ||
637 | num_stopping); | ||
638 | sep = 1; | ||
639 | } | ||
640 | if (0 != num_stopped) | ||
641 | { | ||
642 | if (sep) | ||
643 | fprintf (stdout, " / "); | ||
644 | fprintf (stdout, | ||
645 | "stopped: %u", | ||
646 | num_stopped); | ||
647 | sep = 1; | ||
648 | } | ||
649 | if (0 != num_finished) | ||
650 | { | ||
651 | if (sep) | ||
652 | fprintf (stdout, " / "); | ||
653 | fprintf (stdout, | ||
654 | "finished: %u", | ||
655 | num_finished); | ||
656 | sep = 1; | ||
657 | } | ||
658 | fprintf (stdout, ")\n"); | ||
659 | } | ||
660 | else | ||
661 | { | ||
662 | fprintf (stdout, | ||
663 | "%s", | ||
664 | _ ("(No services configured.)\n")); | ||
665 | } | ||
666 | } | ||
667 | for (unsigned int i = 0; i < count; i++) | ||
668 | { | ||
669 | struct GNUNET_TIME_Relative restart_in; | ||
670 | switch (list[i].status) | ||
671 | { | ||
672 | case GNUNET_ARM_SERVICE_STATUS_STOPPED: | ||
673 | if (show_all) | ||
674 | fprintf (stdout, | ||
675 | "%s (binary='%s', status=stopped)\n", | ||
676 | list[i].name, | ||
677 | list[i].binary); | ||
678 | break; | ||
679 | case GNUNET_ARM_SERVICE_STATUS_FAILED: | ||
680 | restart_in = GNUNET_TIME_absolute_get_remaining (list[i].restart_at); | ||
681 | fprintf (stdout, | ||
682 | "%s (binary='%s', status=failed, exit_status=%d, restart_delay='%s')\n", | ||
683 | list[i].name, | ||
684 | list[i].binary, | ||
685 | list[i].last_exit_status, | ||
686 | GNUNET_STRINGS_relative_time_to_string (restart_in, | ||
687 | GNUNET_YES)); | ||
688 | break; | ||
689 | case GNUNET_ARM_SERVICE_STATUS_FINISHED: | ||
690 | fprintf (stdout, | ||
691 | "%s (binary='%s', status=finished)\n", | ||
692 | list[i].name, | ||
693 | list[i].binary); | ||
694 | break; | ||
695 | case GNUNET_ARM_SERVICE_STATUS_STARTED: | ||
696 | fprintf (stdout, | ||
697 | "%s (binary='%s', status=started)\n", | ||
698 | list[i].name, | ||
699 | list[i].binary); | ||
700 | break; | ||
701 | case GNUNET_ARM_SERVICE_STATUS_STOPPING: | ||
702 | fprintf (stdout, | ||
703 | "%s (binary='%s', status=stopping)\n", | ||
704 | list[i].name, | ||
705 | list[i].binary); | ||
706 | break; | ||
707 | default: | ||
708 | GNUNET_break_op (0); | ||
709 | fprintf (stdout, | ||
710 | "%s (binary='%s', status=unknown)\n", | ||
711 | list[i].name, | ||
712 | list[i].binary); | ||
713 | break; | ||
714 | } | ||
715 | } | ||
716 | al_task = GNUNET_SCHEDULER_add_now (&action_loop, | ||
717 | NULL); | ||
718 | } | ||
719 | |||
720 | |||
721 | /** | ||
722 | * Main action loop. Runs the various jobs that we've been asked to | ||
723 | * do, in order. | ||
724 | * | ||
725 | * @param cls closure, unused | ||
726 | */ | ||
727 | static void | ||
728 | action_loop (void *cls) | ||
729 | { | ||
730 | (void) cls; | ||
731 | al_task = NULL; | ||
732 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
733 | "Running requested actions\n"); | ||
734 | while (1) | ||
735 | { | ||
736 | switch (phase++) | ||
737 | { | ||
738 | case 0: | ||
739 | if (NULL != term) | ||
740 | { | ||
741 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
742 | "Termination action\n"); | ||
743 | op = GNUNET_ARM_request_service_stop (h, | ||
744 | term, | ||
745 | &term_callback, | ||
746 | NULL); | ||
747 | return; | ||
748 | } | ||
749 | break; | ||
750 | |||
751 | case 1: | ||
752 | if (end || restart) | ||
753 | { | ||
754 | if (GNUNET_YES != | ||
755 | GNUNET_CLIENT_test (cfg, | ||
756 | "arm")) | ||
757 | { | ||
758 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
759 | "GNUnet not running, cannot stop the peer\n"); | ||
760 | } | ||
761 | else | ||
762 | { | ||
763 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
764 | "End action\n"); | ||
765 | op = GNUNET_ARM_request_service_stop (h, | ||
766 | "arm", | ||
767 | &stop_callback, | ||
768 | NULL); | ||
769 | return; | ||
770 | } | ||
771 | } | ||
772 | break; | ||
773 | |||
774 | case 2: | ||
775 | if (start) | ||
776 | { | ||
777 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
778 | "Start action\n"); | ||
779 | op = | ||
780 | GNUNET_ARM_request_service_start (h, | ||
781 | "arm", | ||
782 | (no_stdout | ||
783 | ? 0 | ||
784 | : GNUNET_OS_INHERIT_STD_OUT) | ||
785 | | (no_stderr | ||
786 | ? 0 | ||
787 | : GNUNET_OS_INHERIT_STD_ERR), | ||
788 | &start_callback, | ||
789 | NULL); | ||
790 | return; | ||
791 | } | ||
792 | break; | ||
793 | |||
794 | case 3: | ||
795 | if (NULL != init) | ||
796 | { | ||
797 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
798 | "Initialization action\n"); | ||
799 | op = GNUNET_ARM_request_service_start (h, | ||
800 | init, | ||
801 | GNUNET_OS_INHERIT_STD_NONE, | ||
802 | &init_callback, | ||
803 | NULL); | ||
804 | return; | ||
805 | } | ||
806 | break; | ||
807 | |||
808 | case 4: | ||
809 | if (list) | ||
810 | { | ||
811 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
812 | "Going to list all running services controlled by ARM.\n"); | ||
813 | op = GNUNET_ARM_request_service_list (h, | ||
814 | &list_callback, | ||
815 | &list); | ||
816 | return; | ||
817 | } | ||
818 | break; | ||
819 | |||
820 | case 5: | ||
821 | if (monitor) | ||
822 | { | ||
823 | if (! quiet) | ||
824 | fprintf (stderr, | ||
825 | _ ("Now only monitoring, press CTRL-C to stop.\n")); | ||
826 | quiet = | ||
827 | 0; /* does not make sense to stay quiet in monitor mode at this time */ | ||
828 | return; /* done with tasks, just monitor */ | ||
829 | } | ||
830 | break; | ||
831 | |||
832 | default: /* last phase */ | ||
833 | GNUNET_SCHEDULER_shutdown (); | ||
834 | return; | ||
835 | } | ||
836 | } | ||
837 | } | ||
838 | |||
839 | |||
840 | /** | ||
841 | * Function called when a service starts or stops. | ||
842 | * | ||
843 | * @param cls closure | ||
844 | * @param service service name | ||
845 | * @param status status of the service | ||
846 | */ | ||
847 | static void | ||
848 | srv_status (void *cls, | ||
849 | const char *service, | ||
850 | enum GNUNET_ARM_ServiceMonitorStatus status) | ||
851 | { | ||
852 | const char *msg; | ||
853 | |||
854 | (void) cls; | ||
855 | switch (status) | ||
856 | { | ||
857 | case GNUNET_ARM_SERVICE_MONITORING_STARTED: | ||
858 | return; /* this should be done silently */ | ||
859 | |||
860 | case GNUNET_ARM_SERVICE_STOPPED: | ||
861 | msg = _ ("Stopped %s.\n"); | ||
862 | break; | ||
863 | |||
864 | case GNUNET_ARM_SERVICE_STARTING: | ||
865 | msg = _ ("Starting %s...\n"); | ||
866 | break; | ||
867 | |||
868 | case GNUNET_ARM_SERVICE_STOPPING: | ||
869 | msg = _ ("Stopping %s...\n"); | ||
870 | break; | ||
871 | |||
872 | default: | ||
873 | msg = NULL; | ||
874 | break; | ||
875 | } | ||
876 | if (! quiet) | ||
877 | { | ||
878 | if (NULL != msg) | ||
879 | fprintf (stderr, | ||
880 | msg, | ||
881 | service); | ||
882 | else | ||
883 | fprintf (stderr, | ||
884 | _ ("Unknown status %u for service %s.\n"), | ||
885 | status, | ||
886 | service); | ||
887 | } | ||
888 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
889 | "Got service %s status %d\n", | ||
890 | service, | ||
891 | (int) status); | ||
892 | } | ||
893 | |||
894 | |||
895 | /** | ||
896 | * Task run on timeout (if -T is given). | ||
897 | */ | ||
898 | static void | ||
899 | timeout_task_cb (void *cls) | ||
900 | { | ||
901 | (void) cls; | ||
902 | timeout_task = NULL; | ||
903 | ret = 2; | ||
904 | GNUNET_SCHEDULER_shutdown (); | ||
905 | } | ||
906 | |||
907 | |||
908 | /** | ||
909 | * Main function that will be run by the scheduler. | ||
910 | * | ||
911 | * @param cls closure | ||
912 | * @param args remaining command-line arguments | ||
913 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | ||
914 | * @param c configuration | ||
915 | */ | ||
916 | static void | ||
917 | run (void *cls, | ||
918 | char *const *args, | ||
919 | const char *cfgfile, | ||
920 | const struct GNUNET_CONFIGURATION_Handle *c) | ||
921 | { | ||
922 | (void) cls; | ||
923 | (void) args; | ||
924 | (void) cfgfile; | ||
925 | cfg = GNUNET_CONFIGURATION_dup (c); | ||
926 | if (GNUNET_OK != | ||
927 | GNUNET_CONFIGURATION_get_value_string (cfg, | ||
928 | "PATHS", | ||
929 | "GNUNET_HOME", | ||
930 | &dir)) | ||
931 | { | ||
932 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, | ||
933 | "PATHS", | ||
934 | "GNUNET_HOME"); | ||
935 | return; | ||
936 | } | ||
937 | (void) GNUNET_CONFIGURATION_get_value_filename (cfg, | ||
938 | "arm", | ||
939 | "CONFIG", | ||
940 | &config_file); | ||
941 | if (NULL == (h = GNUNET_ARM_connect (cfg, | ||
942 | &conn_status, | ||
943 | NULL))) | ||
944 | return; | ||
945 | if (monitor) | ||
946 | m = GNUNET_ARM_monitor_start (cfg, | ||
947 | &srv_status, | ||
948 | NULL); | ||
949 | al_task = GNUNET_SCHEDULER_add_now (&action_loop, | ||
950 | NULL); | ||
951 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, | ||
952 | NULL); | ||
953 | if (0 != timeout.rel_value_us) | ||
954 | timeout_task = | ||
955 | GNUNET_SCHEDULER_add_delayed (timeout, | ||
956 | &timeout_task_cb, | ||
957 | NULL); | ||
958 | } | ||
959 | |||
960 | |||
961 | /** | ||
962 | * The main function to obtain arm from gnunetd. | ||
963 | * | ||
964 | * @param argc number of arguments from the command line | ||
965 | * @param argv command line arguments | ||
966 | * @return 0 ok, 1 on error, 2 on timeout | ||
967 | */ | ||
968 | int | ||
969 | main (int argc, char *const *argv) | ||
970 | { | ||
971 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
972 | GNUNET_GETOPT_option_flag ('e', | ||
973 | "end", | ||
974 | gettext_noop ("stop all GNUnet services"), | ||
975 | &end), | ||
976 | GNUNET_GETOPT_option_string ('i', | ||
977 | "init", | ||
978 | "SERVICE", | ||
979 | gettext_noop ("start a particular service"), | ||
980 | &init), | ||
981 | GNUNET_GETOPT_option_string ('k', | ||
982 | "kill", | ||
983 | "SERVICE", | ||
984 | gettext_noop ("stop a particular service"), | ||
985 | &term), | ||
986 | GNUNET_GETOPT_option_flag ('a', | ||
987 | "all", | ||
988 | gettext_noop ( | ||
989 | "also show stopped services (used with -I)"), | ||
990 | &show_all), | ||
991 | GNUNET_GETOPT_option_flag ('s', | ||
992 | "start", | ||
993 | gettext_noop ( | ||
994 | "start all GNUnet default services"), | ||
995 | &start), | ||
996 | GNUNET_GETOPT_option_flag ('r', | ||
997 | "restart", | ||
998 | gettext_noop ( | ||
999 | "stop and start all GNUnet default services"), | ||
1000 | &restart), | ||
1001 | GNUNET_GETOPT_option_flag ('d', | ||
1002 | "delete", | ||
1003 | gettext_noop ( | ||
1004 | "delete config file and directory on exit"), | ||
1005 | &delete), | ||
1006 | GNUNET_GETOPT_option_flag ('m', | ||
1007 | "monitor", | ||
1008 | gettext_noop ("monitor ARM activities"), | ||
1009 | &monitor), | ||
1010 | GNUNET_GETOPT_option_flag ('q', | ||
1011 | "quiet", | ||
1012 | gettext_noop ("don't print status messages"), | ||
1013 | &quiet), | ||
1014 | GNUNET_GETOPT_option_relative_time ( | ||
1015 | 'T', | ||
1016 | "timeout", | ||
1017 | "DELAY", | ||
1018 | gettext_noop ( | ||
1019 | "exit with error status if operation does not finish after DELAY"), | ||
1020 | &timeout), | ||
1021 | GNUNET_GETOPT_option_flag ('I', | ||
1022 | "info", | ||
1023 | gettext_noop ( | ||
1024 | "list currently running services"), | ||
1025 | &list), | ||
1026 | GNUNET_GETOPT_option_flag ( | ||
1027 | 'O', | ||
1028 | "no-stdout", | ||
1029 | gettext_noop ("don't let gnunet-service-arm inherit standard output"), | ||
1030 | &no_stdout), | ||
1031 | GNUNET_GETOPT_option_flag ( | ||
1032 | 'E', | ||
1033 | "no-stderr", | ||
1034 | gettext_noop ("don't let gnunet-service-arm inherit standard error"), | ||
1035 | &no_stderr), | ||
1036 | GNUNET_GETOPT_OPTION_END | ||
1037 | }; | ||
1038 | int lret; | ||
1039 | |||
1040 | if (GNUNET_OK != | ||
1041 | GNUNET_STRINGS_get_utf8_args (argc, | ||
1042 | argv, | ||
1043 | &argc, | ||
1044 | &argv)) | ||
1045 | return 2; | ||
1046 | if (GNUNET_OK == | ||
1047 | (lret = GNUNET_PROGRAM_run ( | ||
1048 | argc, | ||
1049 | argv, | ||
1050 | "gnunet-arm", | ||
1051 | gettext_noop ( | ||
1052 | "Control services and the Automated Restart Manager (ARM)"), | ||
1053 | options, | ||
1054 | &run, | ||
1055 | NULL))) | ||
1056 | { | ||
1057 | GNUNET_free_nz ((void *) argv); | ||
1058 | return ret; | ||
1059 | } | ||
1060 | GNUNET_free_nz ((void *) argv); | ||
1061 | return lret; | ||
1062 | } | ||
1063 | |||
1064 | |||
1065 | /* end of gnunet-arm.c */ | ||