aboutsummaryrefslogtreecommitdiff
path: root/src/arm
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2014-12-10 17:11:06 +0000
committerChristian Grothoff <christian@grothoff.org>2014-12-10 17:11:06 +0000
commitb8fc68d6cb81adb3803186359b3a30b1a4bb7b5a (patch)
treebe6defbdf18e3af9bdcc979cf27b253fe0b4d5f9 /src/arm
parent3871fc32bbd05da817d94f4188023a4edebc367a (diff)
downloadgnunet-b8fc68d6cb81adb3803186359b3a30b1a4bb7b5a.tar.gz
gnunet-b8fc68d6cb81adb3803186359b3a30b1a4bb7b5a.zip
moving away from DEFAULTSERVICES to per-section FORCESTART, thus addressing #3565 indirectly
Diffstat (limited to 'src/arm')
-rw-r--r--src/arm/arm.conf.in4
-rw-r--r--src/arm/gnunet-service-arm.c91
-rw-r--r--src/arm/test_arm_api_data.conf17
-rw-r--r--src/arm/test_gnunet_service_arm.c97
4 files changed, 117 insertions, 92 deletions
diff --git a/src/arm/arm.conf.in b/src/arm/arm.conf.in
index 83582659a..53731586b 100644
--- a/src/arm/arm.conf.in
+++ b/src/arm/arm.conf.in
@@ -1,11 +1,13 @@
1
2[arm] 1[arm]
3@UNIXONLY@ PORT = 2087 2@UNIXONLY@ PORT = 2087
4HOSTNAME = localhost 3HOSTNAME = localhost
5BINARY = gnunet-service-arm 4BINARY = gnunet-service-arm
6ACCEPT_FROM = 127.0.0.1; 5ACCEPT_FROM = 127.0.0.1;
7ACCEPT_FROM6 = ::1; 6ACCEPT_FROM6 = ::1;
7
8
8DEFAULTSERVICES = topology hostlist dht nse cadet fs revocation 9DEFAULTSERVICES = topology hostlist dht nse cadet fs revocation
10
9# Special case, uses user runtime dir even for per-system service. 11# Special case, uses user runtime dir even for per-system service.
10UNIXPATH = $GNUNET_USER_RUNTIME_DIR/gnunet-service-arm.sock 12UNIXPATH = $GNUNET_USER_RUNTIME_DIR/gnunet-service-arm.sock
11UNIX_MATCH_UID = YES 13UNIX_MATCH_UID = YES
diff --git a/src/arm/gnunet-service-arm.c b/src/arm/gnunet-service-arm.c
index 1249fe003..c6259c273 100644
--- a/src/arm/gnunet-service-arm.c
+++ b/src/arm/gnunet-service-arm.c
@@ -163,7 +163,7 @@ struct ServiceList
163 * to start it)? #GNUNET_NO if the service is started only upon 'accept' on a 163 * to start it)? #GNUNET_NO if the service is started only upon 'accept' on a
164 * listen socket or possibly explicitly by a client changing the value. 164 * listen socket or possibly explicitly by a client changing the value.
165 */ 165 */
166 int is_default; 166 int force_start;
167 167
168 /** 168 /**
169 * Should we use pipes to signal this process? (YES for Java binaries and if we 169 * Should we use pipes to signal this process? (YES for Java binaries and if we
@@ -669,7 +669,7 @@ create_listen_socket (struct sockaddr *sa, socklen_t addr_len,
669#ifdef LINUX 669#ifdef LINUX
670 /* Permission settings are not required when abstract sockets are used */ 670 /* Permission settings are not required when abstract sockets are used */
671 && ('\0' != ((const struct sockaddr_un *)sa)->sun_path[0]) 671 && ('\0' != ((const struct sockaddr_un *)sa)->sun_path[0])
672#endif 672#endif
673 ) 673 )
674 { 674 {
675 match_uid = 675 match_uid =
@@ -735,7 +735,8 @@ free_service (struct ServiceList *sl)
735 * #GNUNET_SYSERR to close it (signal serious error) 735 * #GNUNET_SYSERR to close it (signal serious error)
736 */ 736 */
737static void 737static void
738handle_start (void *cls, struct GNUNET_SERVER_Client *client, 738handle_start (void *cls,
739 struct GNUNET_SERVER_Client *client,
739 const struct GNUNET_MessageHeader *message) 740 const struct GNUNET_MessageHeader *message)
740{ 741{
741 const char *servicename; 742 const char *servicename;
@@ -770,7 +771,7 @@ handle_start (void *cls, struct GNUNET_SERVER_Client *client,
770 GNUNET_SERVER_receive_done (client, GNUNET_OK); 771 GNUNET_SERVER_receive_done (client, GNUNET_OK);
771 return; 772 return;
772 } 773 }
773 sl->is_default = GNUNET_YES; 774 sl->force_start = GNUNET_YES;
774 if (NULL != sl->proc) 775 if (NULL != sl->proc)
775 { 776 {
776 signal_result (client, servicename, request_id, 777 signal_result (client, servicename, request_id,
@@ -790,9 +791,11 @@ handle_start (void *cls, struct GNUNET_SERVER_Client *client,
790 * @param tc task context 791 * @param tc task context
791 */ 792 */
792static void 793static void
793trigger_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 794trigger_shutdown (void *cls,
795 const struct GNUNET_SCHEDULER_TaskContext *tc)
794{ 796{
795 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Triggering shutdown\n"); 797 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
798 "Triggering shutdown\n");
796 GNUNET_SCHEDULER_shutdown (); 799 GNUNET_SCHEDULER_shutdown ();
797} 800}
798 801
@@ -807,7 +810,8 @@ trigger_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
807 * #GNUNET_SYSERR to close it (signal serious error) 810 * #GNUNET_SYSERR to close it (signal serious error)
808 */ 811 */
809static void 812static void
810handle_stop (void *cls, struct GNUNET_SERVER_Client *client, 813handle_stop (void *cls,
814 struct GNUNET_SERVER_Client *client,
811 const struct GNUNET_MessageHeader *message) 815 const struct GNUNET_MessageHeader *message)
812{ 816{
813 struct ServiceList *sl; 817 struct ServiceList *sl;
@@ -846,7 +850,7 @@ handle_stop (void *cls, struct GNUNET_SERVER_Client *client,
846 GNUNET_SERVER_receive_done (client, GNUNET_OK); 850 GNUNET_SERVER_receive_done (client, GNUNET_OK);
847 return; 851 return;
848 } 852 }
849 sl->is_default = GNUNET_NO; 853 sl->force_start = GNUNET_NO;
850 if (GNUNET_YES == in_shutdown) 854 if (GNUNET_YES == in_shutdown)
851 { 855 {
852 /* shutdown in progress */ 856 /* shutdown in progress */
@@ -1002,7 +1006,8 @@ list_count (struct ServiceList *running_head)
1002 * @param tc context 1006 * @param tc context
1003 */ 1007 */
1004static void 1008static void
1005shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 1009shutdown_task (void *cls,
1010 const struct GNUNET_SCHEDULER_TaskContext *tc)
1006{ 1011{
1007 struct ServiceList *pos; 1012 struct ServiceList *pos;
1008 struct ServiceList *nxt; 1013 struct ServiceList *nxt;
@@ -1093,11 +1098,12 @@ delayed_restart_task (void *cls,
1093 if (0 == GNUNET_TIME_absolute_get_remaining (sl->restart_at).rel_value_us) 1098 if (0 == GNUNET_TIME_absolute_get_remaining (sl->restart_at).rel_value_us)
1094 { 1099 {
1095 /* restart is now allowed */ 1100 /* restart is now allowed */
1096 if (sl->is_default) 1101 if (sl->force_start)
1097 { 1102 {
1098 /* process should run by default, start immediately */ 1103 /* process should run by default, start immediately */
1099 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1104 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1100 _("Restarting service `%s'.\n"), sl->name); 1105 _("Restarting service `%s'.\n"),
1106 sl->name);
1101 start_process (sl, NULL, 0); 1107 start_process (sl, NULL, 0);
1102 } 1108 }
1103 else 1109 else
@@ -1377,9 +1383,18 @@ setup_service (void *cls, const char *section)
1377#endif 1383#endif
1378 GNUNET_CONTAINER_DLL_insert (running_head, running_tail, sl); 1384 GNUNET_CONTAINER_DLL_insert (running_head, running_tail, sl);
1379 1385
1380 if (GNUNET_YES != 1386 if (GNUNET_YES ==
1381 GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "AUTOSTART")) 1387 GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "FORCESTART"))
1388 {
1389 sl->force_start = GNUNET_YES;
1382 return; 1390 return;
1391 }
1392 else
1393 {
1394 if (GNUNET_YES !=
1395 GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "AUTOSTART"))
1396 return;
1397 }
1383 if (0 >= (ret = GNUNET_SERVICE_get_server_addresses (section, cfg, 1398 if (0 >= (ret = GNUNET_SERVICE_get_server_addresses (section, cfg,
1384 &addrs, &addr_lens))) 1399 &addrs, &addr_lens)))
1385 return; 1400 return;
@@ -1451,8 +1466,6 @@ run (void *cls, struct GNUNET_SERVER_Handle *serv,
1451 sizeof (struct GNUNET_ARM_Message)}, 1466 sizeof (struct GNUNET_ARM_Message)},
1452 {NULL, NULL, 0, 0} 1467 {NULL, NULL, 0, 0}
1453 }; 1468 };
1454 char *defaultservices;
1455 const char *pos;
1456 struct ServiceList *sl; 1469 struct ServiceList *sl;
1457 1470
1458 cfg = c; 1471 cfg = c;
@@ -1490,45 +1503,17 @@ run (void *cls, struct GNUNET_SERVER_Handle *serv,
1490 GNUNET_CONFIGURATION_iterate_sections (cfg, &setup_service, NULL); 1503 GNUNET_CONFIGURATION_iterate_sections (cfg, &setup_service, NULL);
1491 1504
1492 /* start default services... */ 1505 /* start default services... */
1493 if (GNUNET_OK == 1506 for (sl = running_head; NULL != sl; sl = sl->next)
1494 GNUNET_CONFIGURATION_get_value_string (cfg, 1507 if (GNUNET_YES == sl->force_start)
1495 "ARM", 1508 start_process (sl, NULL, 0);
1496 "DEFAULTSERVICES", 1509 notifier
1497 &defaultservices)) 1510 = GNUNET_SERVER_notification_context_create (server,
1498 { 1511 MAX_NOTIFY_QUEUE);
1499 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1512 GNUNET_SERVER_connect_notify (server,
1500 _("Starting default services `%s'\n"), 1513 &handle_client_connecting, NULL);
1501 defaultservices);
1502 if (0 < strlen (defaultservices))
1503 {
1504 for (pos = strtok (defaultservices, " "); NULL != pos;
1505 pos = strtok (NULL, " "))
1506 {
1507 sl = find_service (pos);
1508 if (NULL == sl)
1509 {
1510 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1511 _("Default service `%s' not configured correctly!\n"),
1512 pos);
1513 continue;
1514 }
1515 sl->is_default = GNUNET_YES;
1516 start_process (sl, NULL, 0);
1517 }
1518 }
1519 GNUNET_free (defaultservices);
1520 }
1521 else
1522 {
1523 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1524 _("No default services configured, GNUnet will not really start right now.\n"));
1525 }
1526
1527 notifier =
1528 GNUNET_SERVER_notification_context_create (server, MAX_NOTIFY_QUEUE);
1529 GNUNET_SERVER_connect_notify (server, handle_client_connecting, NULL);
1530 /* process client requests */ 1514 /* process client requests */
1531 GNUNET_SERVER_add_handlers (server, handlers); 1515 GNUNET_SERVER_add_handlers (server,
1516 handlers);
1532} 1517}
1533 1518
1534 1519
diff --git a/src/arm/test_arm_api_data.conf b/src/arm/test_arm_api_data.conf
index d8354477e..3ae5271a1 100644
--- a/src/arm/test_arm_api_data.conf
+++ b/src/arm/test_arm_api_data.conf
@@ -3,7 +3,6 @@ GNUNET_TEST_HOME = /tmp/test-gnunetd-arm/
3 3
4[arm] 4[arm]
5PORT = 23354 5PORT = 23354
6DEFAULTSERVICES =
7BINARY = gnunet-service-arm 6BINARY = gnunet-service-arm
8OPTIONS = -L ERROR 7OPTIONS = -L ERROR
9#PREFIX = valgrind --tool=memcheck --leak-check=yes 8#PREFIX = valgrind --tool=memcheck --leak-check=yes
@@ -22,6 +21,7 @@ ACCEPT_FROM6 = ::1;
22 21
23[fs] 22[fs]
24AUTOSTART = NO 23AUTOSTART = NO
24FORCESTART = NO
25 25
26[datastore] 26[datastore]
27AUTOSTART = NO 27AUTOSTART = NO
@@ -46,5 +46,20 @@ AUTOSTART = NO
46 46
47[nse] 47[nse]
48AUTOSTART = NO 48AUTOSTART = NO
49FORCESTART = NO
49 50
51[hostlist]
52AUTOSTART = NO
53FORCESTART = NO
54
55[dht]
56AUTOSTART = NO
57FORCESTART = NO
50 58
59[cadet]
60AUTOSTART = NO
61FORCESTART = NO
62
63[revocation]
64AUTOSTART = NO
65FORCESTART = NO
diff --git a/src/arm/test_gnunet_service_arm.c b/src/arm/test_gnunet_service_arm.c
index 5c08293a4..77b6f36dd 100644
--- a/src/arm/test_gnunet_service_arm.c
+++ b/src/arm/test_gnunet_service_arm.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors) 3 (C) 2009, 2014 Christian Grothoff (and other contributing authors)
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -40,14 +40,16 @@
40 40
41static int ret = 1; 41static int ret = 1;
42 42
43static int resolved_ok = 0; 43static int resolved_ok;
44 44
45static int asked_for_a_list = 0; 45static int asked_for_a_list;
46 46
47static struct GNUNET_ARM_Handle *arm; 47static struct GNUNET_ARM_Handle *arm;
48 48
49
49static void 50static void
50trigger_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 51trigger_disconnect (void *cls,
52 const struct GNUNET_SCHEDULER_TaskContext *tc)
51{ 53{
52 GNUNET_ARM_disconnect_and_free (arm); 54 GNUNET_ARM_disconnect_and_free (arm);
53 arm = NULL; 55 arm = NULL;
@@ -71,40 +73,52 @@ arm_stop_cb (void *cls,
71static void 73static void
72service_list (void *cls, 74service_list (void *cls,
73 enum GNUNET_ARM_RequestStatus rs, 75 enum GNUNET_ARM_RequestStatus rs,
74 unsigned int count, const char *const*list) 76 unsigned int count,
77 const char *const*list)
75{ 78{
79 unsigned int i;
80
76 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 81 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
77 "%u services are are currently running\n", 82 "%u services are are currently running\n",
78 count); 83 count);
79 if (GNUNET_ARM_REQUEST_SENT_OK != rs) 84 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
80 goto stop_arm; 85 goto stop_arm;
81 if (1 == count) 86 for (i=0;i<count;i++)
82 { 87 {
83 GNUNET_break (0 == strcasecmp (list[0], "resolver (gnunet-service-resolver)")); 88 if (0 == strcasecmp (list[i],
84 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got service list, now stopping arm\n"); 89 "resolver (gnunet-service-resolver)"));
85 ret = 0; 90 {
91 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
92 "Got service list, now stopping arm\n");
93 ret = 0;
94 }
86 } 95 }
87 96
88 stop_arm: 97 stop_arm:
89 GNUNET_ARM_request_service_stop (arm, "arm", TIMEOUT, arm_stop_cb, NULL); 98 GNUNET_ARM_request_service_stop (arm, "arm", TIMEOUT,
99 &arm_stop_cb, NULL);
90} 100}
91 101
92 102
93static void 103static void
94hostNameResolveCB (void *cls, const struct sockaddr *addr, socklen_t addrlen) 104hostNameResolveCB (void *cls,
105 const struct sockaddr *addr,
106 socklen_t addrlen)
95{ 107{
96 if ((ret == 0) || (ret == 4) || (resolved_ok == 1)) 108 if ((ret == 0) || (ret == 4) || (resolved_ok == 1))
97 return; 109 return;
98 if (NULL == addr) 110 if (NULL == addr)
99 { 111 {
100 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Name not resolved!\n"); 112 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
113 "Name not resolved!\n");
101 ret = 3; 114 ret = 3;
102 GNUNET_ARM_request_service_stop (arm, "arm", TIMEOUT, arm_stop_cb, NULL); 115 GNUNET_ARM_request_service_stop (arm, "arm", TIMEOUT,
116 &arm_stop_cb, NULL);
103 } 117 }
104 else if (asked_for_a_list == 0) 118 else if (asked_for_a_list == 0)
105 { 119 {
106 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 120 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
107 "Resolved hostname, now checking the service list\n"); 121 "Resolved hostname, now checking the service list\n");
108 GNUNET_ARM_request_service_list (arm, TIMEOUT, service_list, NULL); 122 GNUNET_ARM_request_service_list (arm, TIMEOUT, service_list, NULL);
109 asked_for_a_list = 1; 123 asked_for_a_list = 1;
110 resolved_ok = 1; 124 resolved_ok = 1;
@@ -121,21 +135,26 @@ arm_start_cb (void *cls,
121 GNUNET_break (status == GNUNET_ARM_REQUEST_SENT_OK); 135 GNUNET_break (status == GNUNET_ARM_REQUEST_SENT_OK);
122 GNUNET_break (result == GNUNET_ARM_RESULT_STARTING); 136 GNUNET_break (result == GNUNET_ARM_RESULT_STARTING);
123 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 137 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
124 "Trying to resolve our own hostname!\n"); 138 "Trying to resolve our own hostname!\n");
125 /* connect to the resolver service */ 139 /* connect to the resolver service */
126 if (NULL == GNUNET_RESOLVER_hostname_resolve ( 140 if (NULL ==
127 AF_UNSPEC, TIMEOUT, &hostNameResolveCB, NULL)) 141 GNUNET_RESOLVER_hostname_resolve (AF_UNSPEC, TIMEOUT,
142 &hostNameResolveCB, NULL))
128 { 143 {
129 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 144 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
130 "Unable initiate connection to resolver service\n"); 145 "Unable initiate connection to resolver service\n");
131 ret = 2; 146 ret = 2;
132 GNUNET_ARM_request_service_stop (arm, "arm", TIMEOUT, arm_stop_cb, NULL); 147 GNUNET_ARM_request_service_stop (arm,
148 "arm", TIMEOUT,
149 &arm_stop_cb, NULL);
133 } 150 }
134} 151}
135 152
136 153
137static void 154static void
138run (void *cls, char *const *args, const char *cfgfile, 155run (void *cls,
156 char *const *args,
157 const char *cfgfile,
139 const struct GNUNET_CONFIGURATION_Handle *c) 158 const struct GNUNET_CONFIGURATION_Handle *c)
140{ 159{
141 char *armconfig; 160 char *armconfig;
@@ -144,10 +163,10 @@ run (void *cls, char *const *args, const char *cfgfile,
144 { 163 {
145 if (GNUNET_OK != 164 if (GNUNET_OK !=
146 GNUNET_CONFIGURATION_get_value_filename (c, "arm", "CONFIG", 165 GNUNET_CONFIGURATION_get_value_filename (c, "arm", "CONFIG",
147 &armconfig)) 166 &armconfig))
148 { 167 {
149 GNUNET_CONFIGURATION_set_value_string ((struct GNUNET_CONFIGURATION_Handle 168 GNUNET_CONFIGURATION_set_value_string ((struct GNUNET_CONFIGURATION_Handle *) c,
150 *) c, "arm", "CONFIG", 169 "arm", "CONFIG",
151 cfgfile); 170 cfgfile);
152 } 171 }
153 else 172 else
@@ -155,7 +174,9 @@ run (void *cls, char *const *args, const char *cfgfile,
155 } 174 }
156 arm = GNUNET_ARM_connect (c, NULL, NULL); 175 arm = GNUNET_ARM_connect (c, NULL, NULL);
157 GNUNET_ARM_request_service_start (arm, "arm", 176 GNUNET_ARM_request_service_start (arm, "arm",
158 GNUNET_OS_INHERIT_STD_OUT_AND_ERR, START_TIMEOUT, arm_start_cb, NULL); 177 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
178 START_TIMEOUT,
179 &arm_start_cb, NULL);
159} 180}
160 181
161 182
@@ -173,27 +194,29 @@ main (int argc, char *av[])
173 char hostname[GNUNET_OS_get_hostname_max_length () + 1]; 194 char hostname[GNUNET_OS_get_hostname_max_length () + 1];
174 195
175 if (0 != gethostname (hostname, sizeof (hostname) - 1)) 196 if (0 != gethostname (hostname, sizeof (hostname) - 1))
176 { 197 {
177 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 198 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
178 "gethostname"); 199 "gethostname");
179 FPRINTF (stderr, 200 FPRINTF (stderr,
180 "%s", "Failed to determine my own hostname, testcase not run.\n"); 201 "%s",
181 return 0; 202 "Failed to determine my own hostname, testcase not run.\n");
182 } 203 return 0;
204 }
183 if (NULL == gethostbyname (hostname)) 205 if (NULL == gethostbyname (hostname))
184 { 206 {
185 FPRINTF (stderr, 207 FPRINTF (stderr,
186 "Failed to resolve my hostname `%s', testcase not run.\n", 208 "Failed to resolve my hostname `%s', testcase not run.\n",
187 hostname); 209 hostname);
188 return 0; 210 return 0;
189 } 211 }
190 GNUNET_log_setup ("test-gnunet-service-arm", 212 GNUNET_log_setup ("test-gnunet-service-arm",
191 "WARNING", 213 "WARNING",
192 NULL); 214 NULL);
193 GNUNET_break (GNUNET_OK == 215 GNUNET_break (GNUNET_OK ==
194 GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, 216 GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
195 argv, "test-gnunet-service-arm", 217 argv, "test-gnunet-service-arm",
196 "nohelp", options, &run, NULL)); 218 "nohelp", options,
219 &run, NULL));
197 return ret; 220 return ret;
198} 221}
199 222