Add function for mapping NDR error codes to strings.
[Samba/ekacnet.git] / source3 / utils / net_rpc_service.c
blob236414222c6221a248eda03431d36fa428940e02
1 /*
2 Samba Unix/Linux SMB client library
3 Distributed SMB/CIFS Server Management Utility
4 Copyright (C) Gerald (Jerry) Carter 2005
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "includes.h"
20 #include "utils/net.h"
23 struct svc_state_msg {
24 uint32 flag;
25 const char *message;
28 static struct svc_state_msg state_msg_table[] = {
29 { SVCCTL_STOPPED, "stopped" },
30 { SVCCTL_START_PENDING, "start pending" },
31 { SVCCTL_STOP_PENDING, "stop pending" },
32 { SVCCTL_RUNNING, "running" },
33 { SVCCTL_CONTINUE_PENDING, "resume pending" },
34 { SVCCTL_PAUSE_PENDING, "pause pending" },
35 { SVCCTL_PAUSED, "paused" },
36 { 0, NULL }
40 /********************************************************************
41 ********************************************************************/
42 const char *svc_status_string( uint32 state )
44 fstring msg;
45 int i;
47 fstr_sprintf( msg, "Unknown State [%d]", state );
49 for ( i=0; state_msg_table[i].message; i++ ) {
50 if ( state_msg_table[i].flag == state ) {
51 fstrcpy( msg, state_msg_table[i].message );
52 break;
56 return talloc_strdup(talloc_tos(), msg);
59 /********************************************************************
60 ********************************************************************/
62 static WERROR query_service_state(struct rpc_pipe_client *pipe_hnd,
63 TALLOC_CTX *mem_ctx,
64 POLICY_HND *hSCM,
65 const char *service,
66 uint32 *state )
68 POLICY_HND hService;
69 struct SERVICE_STATUS service_status;
70 WERROR result = WERR_GENERAL_FAILURE;
71 NTSTATUS status;
73 /* now cycle until the status is actually 'watch_state' */
75 status = rpccli_svcctl_OpenServiceW(pipe_hnd, mem_ctx,
76 hSCM,
77 service,
78 SC_RIGHT_SVC_QUERY_STATUS,
79 &hService,
80 &result);
81 if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result) ) {
82 d_fprintf(stderr, "Failed to open service. [%s]\n", win_errstr(result));
83 return result;
86 status = rpccli_svcctl_QueryServiceStatus(pipe_hnd, mem_ctx,
87 &hService,
88 &service_status,
89 &result);
91 if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result) ) {
92 *state = service_status.state;
95 rpccli_svcctl_CloseServiceHandle(pipe_hnd, mem_ctx, &hService, NULL);
97 return result;
100 /********************************************************************
101 ********************************************************************/
103 static WERROR watch_service_state(struct rpc_pipe_client *pipe_hnd,
104 TALLOC_CTX *mem_ctx,
105 POLICY_HND *hSCM,
106 const char *service,
107 uint32 watch_state,
108 uint32 *final_state )
110 uint32 i;
111 uint32 state = 0;
112 WERROR result = WERR_GENERAL_FAILURE;
115 i = 0;
116 while ( (state != watch_state ) && i<30 ) {
117 /* get the status */
119 result = query_service_state(pipe_hnd, mem_ctx, hSCM, service, &state );
120 if ( !W_ERROR_IS_OK(result) ) {
121 break;
124 d_printf(".");
125 i++;
126 sys_usleep( 100 );
128 d_printf("\n");
130 *final_state = state;
132 return result;
135 /********************************************************************
136 ********************************************************************/
138 static WERROR control_service(struct rpc_pipe_client *pipe_hnd,
139 TALLOC_CTX *mem_ctx,
140 POLICY_HND *hSCM,
141 const char *service,
142 uint32 control,
143 uint32 watch_state )
145 POLICY_HND hService;
146 WERROR result = WERR_GENERAL_FAILURE;
147 NTSTATUS status;
148 struct SERVICE_STATUS service_status;
149 uint32 state = 0;
151 /* Open the Service */
153 status = rpccli_svcctl_OpenServiceW(pipe_hnd, mem_ctx,
154 hSCM,
155 service,
156 (SC_RIGHT_SVC_STOP|SC_RIGHT_SVC_PAUSE_CONTINUE),
157 &hService,
158 &result);
160 if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result) ) {
161 d_fprintf(stderr, "Failed to open service. [%s]\n", win_errstr(result));
162 goto done;
165 /* get the status */
167 status = rpccli_svcctl_ControlService(pipe_hnd, mem_ctx,
168 &hService,
169 control,
170 &service_status,
171 &result);
173 if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result) ) {
174 d_fprintf(stderr, "Control service request failed. [%s]\n", win_errstr(result));
175 goto done;
178 /* loop -- checking the state until we are where we want to be */
180 result = watch_service_state(pipe_hnd, mem_ctx, hSCM, service, watch_state, &state );
182 d_printf("%s service is %s.\n", service, svc_status_string(state));
184 done:
185 rpccli_svcctl_CloseServiceHandle(pipe_hnd, mem_ctx, &hService, NULL);
187 return result;
190 /********************************************************************
191 ********************************************************************/
193 static NTSTATUS rpc_service_list_internal(struct net_context *c,
194 const DOM_SID *domain_sid,
195 const char *domain_name,
196 struct cli_state *cli,
197 struct rpc_pipe_client *pipe_hnd,
198 TALLOC_CTX *mem_ctx,
199 int argc,
200 const char **argv )
202 POLICY_HND hSCM;
203 struct ENUM_SERVICE_STATUSW *services = NULL;
204 WERROR result = WERR_GENERAL_FAILURE;
205 NTSTATUS status;
206 int i;
208 uint8_t *buffer = NULL;
209 uint32_t buf_size = 0;
210 uint32_t bytes_needed = 0;
211 uint32_t num_services = 0;
212 uint32_t resume_handle = 0;
214 if (argc != 0 ) {
215 d_printf("Usage: net rpc service list\n");
216 return NT_STATUS_OK;
219 status = rpccli_svcctl_OpenSCManagerW(pipe_hnd, mem_ctx,
220 pipe_hnd->srv_name_slash,
221 NULL,
222 SC_RIGHT_MGR_ENUMERATE_SERVICE,
223 &hSCM,
224 &result);
225 if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) {
226 d_fprintf(stderr, "Failed to open Service Control Manager. [%s]\n", win_errstr(result));
227 return werror_to_ntstatus(result);
230 do {
231 status = rpccli_svcctl_EnumServicesStatusW(pipe_hnd, mem_ctx,
232 &hSCM,
233 SERVICE_TYPE_WIN32,
234 SERVICE_STATE_ALL,
235 buffer,
236 buf_size,
237 &bytes_needed,
238 &num_services,
239 &resume_handle,
240 &result);
242 if (NT_STATUS_IS_ERR(status)) {
243 d_fprintf(stderr, "Failed to enumerate services. [%s]\n",
244 win_errstr(result));
245 break;
248 if (W_ERROR_EQUAL(result, WERR_MORE_DATA) && bytes_needed > 0) {
249 buffer = talloc_array(mem_ctx, uint8_t, bytes_needed);
250 buf_size = bytes_needed;
251 continue;
254 if ( num_services == 0 ) {
255 d_printf("No services returned\n");
256 break;
260 enum ndr_err_code ndr_err;
261 DATA_BLOB blob;
262 struct ndr_pull *ndr;
264 blob.length = buf_size;
265 blob.data = talloc_steal(mem_ctx, buffer);
267 services = talloc_array(mem_ctx, struct ENUM_SERVICE_STATUSW, num_services);
268 if (!services) {
269 status = NT_STATUS_NO_MEMORY;
270 break;
273 ndr = ndr_pull_init_blob(&blob, mem_ctx, NULL);
274 if (ndr == NULL) {
275 status = NT_STATUS_NO_MEMORY;
276 break;
279 ndr_err = ndr_pull_ENUM_SERVICE_STATUSW_array(
280 ndr, num_services, services);
281 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
282 status = ndr_map_error2ntstatus(ndr_err);
283 break;
286 for ( i=0; i<num_services; i++ ) {
287 d_printf("%-20s \"%s\"\n",
288 services[i].service_name,
289 services[i].display_name);
293 } while (W_ERROR_EQUAL(result, WERR_MORE_DATA));
295 rpccli_svcctl_CloseServiceHandle(pipe_hnd, mem_ctx, &hSCM, NULL);
297 return status;
300 /********************************************************************
301 ********************************************************************/
303 static NTSTATUS rpc_service_status_internal(struct net_context *c,
304 const DOM_SID *domain_sid,
305 const char *domain_name,
306 struct cli_state *cli,
307 struct rpc_pipe_client *pipe_hnd,
308 TALLOC_CTX *mem_ctx,
309 int argc,
310 const char **argv )
312 POLICY_HND hSCM, hService;
313 WERROR result = WERR_GENERAL_FAILURE;
314 NTSTATUS status;
315 struct SERVICE_STATUS service_status;
316 struct QUERY_SERVICE_CONFIG config;
317 uint32_t buf_size = sizeof(config);
318 uint32_t ret_size = 0;
320 if (argc != 1 ) {
321 d_printf("Usage: net rpc service status <service>\n");
322 return NT_STATUS_OK;
325 /* Open the Service Control Manager */
326 status = rpccli_svcctl_OpenSCManagerW(pipe_hnd, mem_ctx,
327 pipe_hnd->srv_name_slash,
328 NULL,
329 SC_RIGHT_MGR_ENUMERATE_SERVICE,
330 &hSCM,
331 &result);
332 if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) {
333 d_fprintf(stderr, "Failed to open Service Control Manager. [%s]\n", win_errstr(result));
334 return werror_to_ntstatus(result);
337 /* Open the Service */
339 status = rpccli_svcctl_OpenServiceW(pipe_hnd, mem_ctx,
340 &hSCM,
341 argv[0],
342 (SC_RIGHT_SVC_QUERY_STATUS|SC_RIGHT_SVC_QUERY_CONFIG),
343 &hService,
344 &result);
346 if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result) ) {
347 d_fprintf(stderr, "Failed to open service. [%s]\n", win_errstr(result));
348 goto done;
351 /* get the status */
353 status = rpccli_svcctl_QueryServiceStatus(pipe_hnd, mem_ctx,
354 &hService,
355 &service_status,
356 &result);
358 if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result) ) {
359 d_fprintf(stderr, "Query status request failed. [%s]\n", win_errstr(result));
360 goto done;
363 d_printf("%s service is %s.\n", argv[0], svc_status_string(service_status.state));
365 /* get the config */
367 status = rpccli_svcctl_QueryServiceConfigW(pipe_hnd, mem_ctx,
368 &hService,
369 &config,
370 buf_size,
371 &ret_size,
372 &result);
373 if (W_ERROR_EQUAL(result, WERR_INSUFFICIENT_BUFFER)) {
374 buf_size = ret_size;
375 status = rpccli_svcctl_QueryServiceConfigW(pipe_hnd, mem_ctx,
376 &hService,
377 &config,
378 buf_size,
379 &ret_size,
380 &result);
383 if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result) ) {
384 d_fprintf(stderr, "Query config request failed. [%s]\n", win_errstr(result));
385 goto done;
388 /* print out the configuration information for the service */
390 d_printf("Configuration details:\n");
391 d_printf("\tControls Accepted = 0x%x\n", service_status.controls_accepted);
392 d_printf("\tService Type = 0x%x\n", config.service_type);
393 d_printf("\tStart Type = 0x%x\n", config.start_type);
394 d_printf("\tError Control = 0x%x\n", config.error_control);
395 d_printf("\tTag ID = 0x%x\n", config.tag_id);
397 if (config.executablepath) {
398 d_printf("\tExecutable Path = %s\n", config.executablepath);
401 if (config.loadordergroup) {
402 d_printf("\tLoad Order Group = %s\n", config.loadordergroup);
405 if (config.dependencies) {
406 d_printf("\tDependencies = %s\n", config.dependencies);
409 if (config.startname) {
410 d_printf("\tStart Name = %s\n", config.startname);
413 if (config.displayname) {
414 d_printf("\tDisplay Name = %s\n", config.displayname);
417 done:
418 rpccli_svcctl_CloseServiceHandle(pipe_hnd, mem_ctx, &hService, NULL);
419 rpccli_svcctl_CloseServiceHandle(pipe_hnd, mem_ctx, &hSCM, NULL);
421 return werror_to_ntstatus(result);
424 /********************************************************************
425 ********************************************************************/
427 static NTSTATUS rpc_service_stop_internal(struct net_context *c,
428 const DOM_SID *domain_sid,
429 const char *domain_name,
430 struct cli_state *cli,
431 struct rpc_pipe_client *pipe_hnd,
432 TALLOC_CTX *mem_ctx,
433 int argc,
434 const char **argv )
436 POLICY_HND hSCM;
437 WERROR result = WERR_GENERAL_FAILURE;
438 NTSTATUS status;
439 fstring servicename;
441 if (argc != 1 ) {
442 d_printf("Usage: net rpc service status <service>\n");
443 return NT_STATUS_OK;
446 fstrcpy( servicename, argv[0] );
448 /* Open the Service Control Manager */
449 status = rpccli_svcctl_OpenSCManagerW(pipe_hnd, mem_ctx,
450 pipe_hnd->srv_name_slash,
451 NULL,
452 SC_RIGHT_MGR_ENUMERATE_SERVICE,
453 &hSCM,
454 &result);
455 if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) {
456 d_fprintf(stderr, "Failed to open Service Control Manager. [%s]\n", win_errstr(result));
457 return werror_to_ntstatus(result);
460 result = control_service(pipe_hnd, mem_ctx, &hSCM, servicename,
461 SVCCTL_CONTROL_STOP, SVCCTL_STOPPED );
463 rpccli_svcctl_CloseServiceHandle(pipe_hnd, mem_ctx, &hSCM, NULL);
465 return werror_to_ntstatus(result);
468 /********************************************************************
469 ********************************************************************/
471 static NTSTATUS rpc_service_pause_internal(struct net_context *c,
472 const DOM_SID *domain_sid,
473 const char *domain_name,
474 struct cli_state *cli,
475 struct rpc_pipe_client *pipe_hnd,
476 TALLOC_CTX *mem_ctx,
477 int argc,
478 const char **argv )
480 POLICY_HND hSCM;
481 WERROR result = WERR_GENERAL_FAILURE;
482 NTSTATUS status;
483 fstring servicename;
485 if (argc != 1 ) {
486 d_printf("Usage: net rpc service status <service>\n");
487 return NT_STATUS_OK;
490 fstrcpy( servicename, argv[0] );
492 /* Open the Service Control Manager */
493 status = rpccli_svcctl_OpenSCManagerW(pipe_hnd, mem_ctx,
494 pipe_hnd->srv_name_slash,
495 NULL,
496 SC_RIGHT_MGR_ENUMERATE_SERVICE,
497 &hSCM,
498 &result);
499 if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) {
500 d_fprintf(stderr, "Failed to open Service Control Manager. [%s]\n", win_errstr(result));
501 return werror_to_ntstatus(result);
504 result = control_service(pipe_hnd, mem_ctx, &hSCM, servicename,
505 SVCCTL_CONTROL_PAUSE, SVCCTL_PAUSED );
507 rpccli_svcctl_CloseServiceHandle(pipe_hnd, mem_ctx, &hSCM, NULL);
509 return werror_to_ntstatus(result);
512 /********************************************************************
513 ********************************************************************/
515 static NTSTATUS rpc_service_resume_internal(struct net_context *c,
516 const DOM_SID *domain_sid,
517 const char *domain_name,
518 struct cli_state *cli,
519 struct rpc_pipe_client *pipe_hnd,
520 TALLOC_CTX *mem_ctx,
521 int argc,
522 const char **argv )
524 POLICY_HND hSCM;
525 WERROR result = WERR_GENERAL_FAILURE;
526 NTSTATUS status;
527 fstring servicename;
529 if (argc != 1 ) {
530 d_printf("Usage: net rpc service status <service>\n");
531 return NT_STATUS_OK;
534 fstrcpy( servicename, argv[0] );
536 /* Open the Service Control Manager */
537 status = rpccli_svcctl_OpenSCManagerW(pipe_hnd, mem_ctx,
538 pipe_hnd->srv_name_slash,
539 NULL,
540 SC_RIGHT_MGR_ENUMERATE_SERVICE,
541 &hSCM,
542 &result);
543 if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) {
544 d_fprintf(stderr, "Failed to open Service Control Manager. [%s]\n", win_errstr(result));
545 return werror_to_ntstatus(result);
548 result = control_service(pipe_hnd, mem_ctx, &hSCM, servicename,
549 SVCCTL_CONTROL_CONTINUE, SVCCTL_RUNNING );
551 rpccli_svcctl_CloseServiceHandle(pipe_hnd, mem_ctx, &hSCM, NULL);
553 return werror_to_ntstatus(result);
556 /********************************************************************
557 ********************************************************************/
559 static NTSTATUS rpc_service_start_internal(struct net_context *c,
560 const DOM_SID *domain_sid,
561 const char *domain_name,
562 struct cli_state *cli,
563 struct rpc_pipe_client *pipe_hnd,
564 TALLOC_CTX *mem_ctx,
565 int argc,
566 const char **argv )
568 POLICY_HND hSCM, hService;
569 WERROR result = WERR_GENERAL_FAILURE;
570 NTSTATUS status;
571 uint32 state = 0;
573 if (argc != 1 ) {
574 d_printf("Usage: net rpc service status <service>\n");
575 return NT_STATUS_OK;
578 /* Open the Service Control Manager */
579 status = rpccli_svcctl_OpenSCManagerW(pipe_hnd, mem_ctx,
580 pipe_hnd->srv_name_slash,
581 NULL,
582 SC_RIGHT_MGR_ENUMERATE_SERVICE,
583 &hSCM,
584 &result);
585 if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) {
586 d_fprintf(stderr, "Failed to open Service Control Manager. [%s]\n", win_errstr(result));
587 return werror_to_ntstatus(result);
590 /* Open the Service */
592 status = rpccli_svcctl_OpenServiceW(pipe_hnd, mem_ctx,
593 &hSCM,
594 argv[0],
595 SC_RIGHT_SVC_START,
596 &hService,
597 &result);
599 if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result) ) {
600 d_fprintf(stderr, "Failed to open service. [%s]\n", win_errstr(result));
601 goto done;
604 /* get the status */
606 status = rpccli_svcctl_StartServiceW(pipe_hnd, mem_ctx,
607 &hService,
609 NULL,
610 &result);
612 if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result) ) {
613 d_fprintf(stderr, "Query status request failed. [%s]\n", win_errstr(result));
614 goto done;
617 result = watch_service_state(pipe_hnd, mem_ctx, &hSCM, argv[0], SVCCTL_RUNNING, &state );
619 if ( W_ERROR_IS_OK(result) && (state == SVCCTL_RUNNING) )
620 d_printf("Successfully started service: %s\n", argv[0] );
621 else
622 d_fprintf(stderr, "Failed to start service: %s [%s]\n", argv[0], win_errstr(result) );
624 done:
625 rpccli_svcctl_CloseServiceHandle(pipe_hnd, mem_ctx, &hService, NULL);
626 rpccli_svcctl_CloseServiceHandle(pipe_hnd, mem_ctx, &hSCM, NULL);
628 return werror_to_ntstatus(result);
631 /********************************************************************
632 ********************************************************************/
634 static int rpc_service_list(struct net_context *c, int argc, const char **argv )
636 if (c->display_usage) {
637 d_printf("Usage:\n"
638 "net rpc service list\n"
639 " View configured Win32 services\n");
640 return 0;
643 return run_rpc_command(c, NULL, &ndr_table_svcctl.syntax_id, 0,
644 rpc_service_list_internal, argc, argv );
647 /********************************************************************
648 ********************************************************************/
650 static int rpc_service_start(struct net_context *c, int argc, const char **argv )
652 if (c->display_usage) {
653 d_printf("Usage:\n"
654 "net rpc service start <service>\n"
655 " Start a Win32 service\n");
656 return 0;
659 return run_rpc_command(c, NULL, &ndr_table_svcctl.syntax_id, 0,
660 rpc_service_start_internal, argc, argv );
663 /********************************************************************
664 ********************************************************************/
666 static int rpc_service_stop(struct net_context *c, int argc, const char **argv )
668 if (c->display_usage) {
669 d_printf("Usage:\n"
670 "net rpc service stop <service>\n"
671 " Stop a Win32 service\n");
672 return 0;
675 return run_rpc_command(c, NULL, &ndr_table_svcctl.syntax_id, 0,
676 rpc_service_stop_internal, argc, argv );
679 /********************************************************************
680 ********************************************************************/
682 static int rpc_service_resume(struct net_context *c, int argc, const char **argv )
684 if (c->display_usage) {
685 d_printf("Usage:\n"
686 "net rpc service resume <service>\n"
687 " Resume a Win32 service\n");
688 return 0;
691 return run_rpc_command(c, NULL, &ndr_table_svcctl.syntax_id, 0,
692 rpc_service_resume_internal, argc, argv );
695 /********************************************************************
696 ********************************************************************/
698 static int rpc_service_pause(struct net_context *c, int argc, const char **argv )
700 if (c->display_usage) {
701 d_printf("Usage:\n"
702 "net rpc service pause <service>\n"
703 " Pause a Win32 service\n");
704 return 0;
707 return run_rpc_command(c, NULL, &ndr_table_svcctl.syntax_id, 0,
708 rpc_service_pause_internal, argc, argv );
711 /********************************************************************
712 ********************************************************************/
714 static int rpc_service_status(struct net_context *c, int argc, const char **argv )
716 if (c->display_usage) {
717 d_printf("Usage:\n"
718 "net rpc service status <service>\n"
719 " Show the current status of a service\n");
720 return 0;
723 return run_rpc_command(c, NULL, &ndr_table_svcctl.syntax_id, 0,
724 rpc_service_status_internal, argc, argv );
727 /********************************************************************
728 ********************************************************************/
730 int net_rpc_service(struct net_context *c, int argc, const char **argv)
732 struct functable func[] = {
734 "list",
735 rpc_service_list,
736 NET_TRANSPORT_RPC,
737 "View configured Win32 services",
738 "net rpc service list\n"
739 " View configured Win32 services"
742 "start",
743 rpc_service_start,
744 NET_TRANSPORT_RPC,
745 "Start a service",
746 "net rpc service start\n"
747 " Start a service"
750 "stop",
751 rpc_service_stop,
752 NET_TRANSPORT_RPC,
753 "Stop a service",
754 "net rpc service stop\n"
755 " Stop a service"
758 "pause",
759 rpc_service_pause,
760 NET_TRANSPORT_RPC,
761 "Pause a service",
762 "net rpc service pause\n"
763 " Pause a service"
766 "resume",
767 rpc_service_resume,
768 NET_TRANSPORT_RPC,
769 "Resume a paused service",
770 "net rpc service resume\n"
771 " Resume a service"
774 "status",
775 rpc_service_status,
776 NET_TRANSPORT_RPC,
777 "View current status of a service",
778 "net rpc service status\n"
779 " View current status of a service"
781 {NULL, NULL, 0, NULL, NULL}
784 return net_run_function(c, argc, argv, "net rpc service",func);