2 * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: rndc.c,v 1.131.20.3 2011/11/03 22:06:31 each Exp $ */
23 * Principal Author: DCL
31 #include <isc/buffer.h>
32 #include <isc/commandline.h>
37 #include <isc/random.h>
38 #include <isc/socket.h>
39 #include <isc/stdtime.h>
40 #include <isc/string.h>
42 #include <isc/thread.h>
45 #include <isccfg/namedconf.h>
47 #include <isccc/alist.h>
48 #include <isccc/base64.h>
50 #include <isccc/ccmsg.h>
51 #include <isccc/result.h>
52 #include <isccc/sexpr.h>
53 #include <isccc/types.h>
54 #include <isccc/util.h>
58 #include <bind9/getaddresses.h>
62 #define SERVERADDRS 10
65 isc_boolean_t verbose;
67 static const char *admin_conffile;
68 static const char *admin_keyfile;
69 static const char *version = VERSION;
70 static const char *servername = NULL;
71 static isc_sockaddr_t serveraddrs[SERVERADDRS];
72 static isc_sockaddr_t local4, local6;
73 static isc_boolean_t local4set = ISC_FALSE, local6set = ISC_FALSE;
74 static int nserveraddrs;
75 static int currentaddr = 0;
76 static unsigned int remoteport = 0;
77 static isc_socketmgr_t *socketmgr = NULL;
78 static unsigned char databuf[2048];
79 static isccc_ccmsg_t ccmsg;
80 static isccc_region_t secret;
81 static isc_boolean_t failed = ISC_FALSE;
82 static isc_boolean_t c_flag = ISC_FALSE;
83 static isc_mem_t *mctx;
84 static int sends, recvs, connects;
87 static char program[256];
88 static isc_socket_t *sock = NULL;
89 static isc_uint32_t serial;
91 static void rndc_startconnect(isc_sockaddr_t *addr, isc_task_t *task);
93 ISC_PLATFORM_NORETURN_PRE static void
94 usage(int status) ISC_PLATFORM_NORETURN_POST;
99 Usage: %s [-b address] [-c config] [-s server] [-p port]\n\
100 [-k key-file ] [-y key] [-V] command\n\
102 command is one of the following:\n\
104 reload Reload configuration file and zones.\n\
105 reload zone [class [view]]\n\
106 Reload a single zone.\n\
107 refresh zone [class [view]]\n\
108 Schedule immediate maintenance for a zone.\n\
109 retransfer zone [class [view]]\n\
110 Retransfer a single zone without checking serial number.\n\
111 freeze Suspend updates to all dynamic zones.\n\
112 freeze zone [class [view]]\n\
113 Suspend updates to a dynamic zone.\n\
114 thaw Enable updates to all dynamic zones and reload them.\n\
115 thaw zone [class [view]]\n\
116 Enable updates to a frozen dynamic zone and reload it.\n\
117 notify zone [class [view]]\n\
118 Resend NOTIFY messages for the zone.\n\
119 reconfig Reload configuration file and new zones only.\n\
120 sign zone [class [view]]\n\
121 Update zone keys, and sign as needed.\n\
122 loadkeys zone [class [view]]\n\
123 Update keys without signing immediately.\n\
124 stats Write server statistics to the statistics file.\n\
125 querylog Toggle query logging.\n\
126 dumpdb [-all|-cache|-zones] [view ...]\n\
127 Dump cache(s) to the dump file (named_dump.db).\n\
128 secroots [view ...]\n\
129 Write security roots to the secroots file.\n\
130 stop Save pending updates to master files and stop the server.\n\
131 stop -p Save pending updates to master files and stop the server\n\
132 reporting process id.\n\
133 halt Stop the server without saving pending updates.\n\
134 halt -p Stop the server without saving pending updates reporting\n\
136 trace Increment debugging level by one.\n\
137 trace level Change the debugging level.\n\
138 notrace Set debugging level to 0.\n\
139 flush Flushes all of the server's caches.\n\
140 flush [view] Flushes the server's cache for a view.\n\
141 flushname name [view]\n\
142 Flush the given name from the server's cache(s)\n\
143 status Display status of the server.\n\
144 recursing Dump the queries that are currently recursing (named.recursing)\n\
145 tsig-list List all currently active TSIG keys, including both statically\n\
146 configured and TKEY-negotiated keys.\n\
147 tsig-delete keyname [view] \n\
148 Delete a TKEY-negotiated TSIG key.\n\
149 validation newstate [view]\n\
150 Enable / disable DNSSEC validation.\n\
151 addzone [\"file\"] zone [class [view]] { zone-options }\n\
152 Add zone to given view. Requires new-zone-file option.\n\
153 delzone [\"file\"] zone [class [view]]\n\
154 Removes zone from given view. Requires new-zone-file option.\n\
155 *restart Restart the server.\n\
157 * == not yet implemented\n\
165 get_addresses(const char *host, in_port_t port) {
167 int found = 0, count;
170 result = isc_sockaddr_frompath(&serveraddrs[nserveraddrs],
172 if (result == ISC_R_SUCCESS)
175 count = SERVERADDRS - nserveraddrs;
176 result = bind9_getaddresses(host, port,
177 &serveraddrs[nserveraddrs],
179 nserveraddrs += found;
181 if (result != ISC_R_SUCCESS)
182 fatal("couldn't get address for '%s': %s",
183 host, isc_result_totext(result));
184 INSIST(nserveraddrs > 0);
188 rndc_senddone(isc_task_t *task, isc_event_t *event) {
189 isc_socketevent_t *sevent = (isc_socketevent_t *)event;
194 if (sevent->result != ISC_R_SUCCESS)
195 fatal("send failed: %s", isc_result_totext(sevent->result));
196 isc_event_free(&event);
197 if (sends == 0 && recvs == 0) {
198 isc_socket_detach(&sock);
199 isc_task_shutdown(task);
200 RUNTIME_CHECK(isc_app_shutdown() == ISC_R_SUCCESS);
205 rndc_recvdone(isc_task_t *task, isc_event_t *event) {
206 isccc_sexpr_t *response = NULL;
208 isccc_region_t source;
209 char *errormsg = NULL;
210 char *textmsg = NULL;
215 if (ccmsg.result == ISC_R_EOF)
216 fatal("connection to remote host closed\n"
217 "This may indicate that\n"
218 "* the remote server is using an older version of"
219 " the command protocol,\n"
220 "* this host is not authorized to connect,\n"
221 "* the clocks are not synchronized, or\n"
222 "* the key is invalid.");
224 if (ccmsg.result != ISC_R_SUCCESS)
225 fatal("recv failed: %s", isc_result_totext(ccmsg.result));
227 source.rstart = isc_buffer_base(&ccmsg.buffer);
228 source.rend = isc_buffer_used(&ccmsg.buffer);
230 DO("parse message", isccc_cc_fromwire(&source, &response, &secret));
232 data = isccc_alist_lookup(response, "_data");
234 fatal("no data section in response");
235 result = isccc_cc_lookupstring(data, "err", &errormsg);
236 if (result == ISC_R_SUCCESS) {
238 fprintf(stderr, "%s: '%s' failed: %s\n",
239 progname, command, errormsg);
241 else if (result != ISC_R_NOTFOUND)
242 fprintf(stderr, "%s: parsing response failed: %s\n",
243 progname, isc_result_totext(result));
245 result = isccc_cc_lookupstring(data, "text", &textmsg);
246 if (result == ISC_R_SUCCESS)
247 printf("%s\n", textmsg);
248 else if (result != ISC_R_NOTFOUND)
249 fprintf(stderr, "%s: parsing response failed: %s\n",
250 progname, isc_result_totext(result));
252 isc_event_free(&event);
253 isccc_sexpr_free(&response);
254 if (sends == 0 && recvs == 0) {
255 isc_socket_detach(&sock);
256 isc_task_shutdown(task);
257 RUNTIME_CHECK(isc_app_shutdown() == ISC_R_SUCCESS);
262 rndc_recvnonce(isc_task_t *task, isc_event_t *event) {
263 isccc_sexpr_t *response = NULL;
264 isccc_sexpr_t *_ctrl;
265 isccc_region_t source;
268 isccc_sexpr_t *request = NULL;
272 isccc_region_t message;
278 if (ccmsg.result == ISC_R_EOF)
279 fatal("connection to remote host closed\n"
280 "This may indicate that\n"
281 "* the remote server is using an older version of"
282 " the command protocol,\n"
283 "* this host is not authorized to connect,\n"
284 "* the clocks are not synchronized, or\n"
285 "* the key is invalid.");
287 if (ccmsg.result != ISC_R_SUCCESS)
288 fatal("recv failed: %s", isc_result_totext(ccmsg.result));
290 source.rstart = isc_buffer_base(&ccmsg.buffer);
291 source.rend = isc_buffer_used(&ccmsg.buffer);
293 DO("parse message", isccc_cc_fromwire(&source, &response, &secret));
295 _ctrl = isccc_alist_lookup(response, "_ctrl");
297 fatal("_ctrl section missing");
299 if (isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS)
302 isc_stdtime_get(&now);
304 DO("create message", isccc_cc_createmessage(1, NULL, NULL, ++serial,
305 now, now + 60, &request));
306 data = isccc_alist_lookup(request, "_data");
308 fatal("_data section missing");
309 if (isccc_cc_definestring(data, "type", args) == NULL)
310 fatal("out of memory");
312 _ctrl = isccc_alist_lookup(request, "_ctrl");
314 fatal("_ctrl section missing");
315 if (isccc_cc_defineuint32(_ctrl, "_nonce", nonce) == NULL)
316 fatal("out of memory");
318 message.rstart = databuf + 4;
319 message.rend = databuf + sizeof(databuf);
320 DO("render message", isccc_cc_towire(request, &message, &secret));
321 len = sizeof(databuf) - REGION_SIZE(message);
322 isc_buffer_init(&b, databuf, 4);
323 isc_buffer_putuint32(&b, len - 4);
327 isccc_ccmsg_cancelread(&ccmsg);
328 DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg, task,
329 rndc_recvdone, NULL));
331 DO("send message", isc_socket_send(sock, &r, task, rndc_senddone,
335 isc_event_free(&event);
336 isccc_sexpr_free(&response);
341 rndc_connected(isc_task_t *task, isc_event_t *event) {
342 char socktext[ISC_SOCKADDR_FORMATSIZE];
343 isc_socketevent_t *sevent = (isc_socketevent_t *)event;
344 isccc_sexpr_t *request = NULL;
347 isccc_region_t message;
355 if (sevent->result != ISC_R_SUCCESS) {
356 isc_sockaddr_format(&serveraddrs[currentaddr], socktext,
358 if (sevent->result != ISC_R_CANCELED &&
359 ++currentaddr < nserveraddrs)
361 notify("connection failed: %s: %s", socktext,
362 isc_result_totext(sevent->result));
363 isc_socket_detach(&sock);
364 isc_event_free(&event);
365 rndc_startconnect(&serveraddrs[currentaddr], task);
368 fatal("connect failed: %s: %s", socktext,
369 isc_result_totext(sevent->result));
372 isc_stdtime_get(&now);
373 DO("create message", isccc_cc_createmessage(1, NULL, NULL, ++serial,
374 now, now + 60, &request));
375 data = isccc_alist_lookup(request, "_data");
377 fatal("_data section missing");
378 if (isccc_cc_definestring(data, "type", "null") == NULL)
379 fatal("out of memory");
380 message.rstart = databuf + 4;
381 message.rend = databuf + sizeof(databuf);
382 DO("render message", isccc_cc_towire(request, &message, &secret));
383 len = sizeof(databuf) - REGION_SIZE(message);
384 isc_buffer_init(&b, databuf, 4);
385 isc_buffer_putuint32(&b, len - 4);
389 isccc_ccmsg_init(mctx, sock, &ccmsg);
390 isccc_ccmsg_setmaxsize(&ccmsg, 1024 * 1024);
392 DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg, task,
393 rndc_recvnonce, NULL));
395 DO("send message", isc_socket_send(sock, &r, task, rndc_senddone,
398 isc_event_free(&event);
402 rndc_startconnect(isc_sockaddr_t *addr, isc_task_t *task) {
405 isc_sockettype_t type;
407 char socktext[ISC_SOCKADDR_FORMATSIZE];
409 isc_sockaddr_format(addr, socktext, sizeof(socktext));
411 notify("using server %s (%s)", servername, socktext);
413 pf = isc_sockaddr_pf(addr);
414 if (pf == AF_INET || pf == AF_INET6)
415 type = isc_sockettype_tcp;
417 type = isc_sockettype_unix;
418 DO("create socket", isc_socket_create(socketmgr, pf, type, &sock));
419 switch (isc_sockaddr_pf(addr)) {
421 DO("bind socket", isc_socket_bind(sock, &local4, 0));
424 DO("bind socket", isc_socket_bind(sock, &local6, 0));
429 DO("connect", isc_socket_connect(sock, addr, task, rndc_connected,
435 rndc_start(isc_task_t *task, isc_event_t *event) {
436 isc_event_free(&event);
439 rndc_startconnect(&serveraddrs[currentaddr], task);
443 parse_config(isc_mem_t *mctx, isc_log_t *log, const char *keyname,
444 cfg_parser_t **pctxp, cfg_obj_t **configp)
447 const char *conffile = admin_conffile;
448 const cfg_obj_t *addresses = NULL;
449 const cfg_obj_t *defkey = NULL;
450 const cfg_obj_t *options = NULL;
451 const cfg_obj_t *servers = NULL;
452 const cfg_obj_t *server = NULL;
453 const cfg_obj_t *keys = NULL;
454 const cfg_obj_t *key = NULL;
455 const cfg_obj_t *defport = NULL;
456 const cfg_obj_t *secretobj = NULL;
457 const cfg_obj_t *algorithmobj = NULL;
458 cfg_obj_t *config = NULL;
459 const cfg_obj_t *address = NULL;
460 const cfg_listelt_t *elt;
461 const char *secretstr;
462 const char *algorithm;
463 static char secretarray[1024];
464 const cfg_type_t *conftype = &cfg_type_rndcconf;
465 isc_boolean_t key_only = ISC_FALSE;
466 const cfg_listelt_t *element;
468 if (! isc_file_exists(conffile)) {
469 conffile = admin_keyfile;
470 conftype = &cfg_type_rndckey;
472 if (! isc_file_exists(conffile))
473 fatal("neither %s nor %s was found",
474 admin_conffile, admin_keyfile);
476 } else if (! c_flag && isc_file_exists(admin_keyfile)) {
477 fprintf(stderr, "WARNING: key file (%s) exists, but using "
478 "default configuration file (%s)\n",
479 admin_keyfile, admin_conffile);
482 DO("create parser", cfg_parser_create(mctx, log, pctxp));
485 * The parser will output its own errors, so DO() is not used.
487 result = cfg_parse_file(*pctxp, conffile, conftype, &config);
488 if (result != ISC_R_SUCCESS)
489 fatal("could not load rndc configuration");
492 (void)cfg_map_get(config, "options", &options);
494 if (key_only && servername == NULL)
495 servername = "127.0.0.1";
496 else if (servername == NULL && options != NULL) {
497 const cfg_obj_t *defserverobj = NULL;
498 (void)cfg_map_get(options, "default-server", &defserverobj);
499 if (defserverobj != NULL)
500 servername = cfg_obj_asstring(defserverobj);
503 if (servername == NULL)
504 fatal("no server specified and no default");
507 (void)cfg_map_get(config, "server", &servers);
508 if (servers != NULL) {
509 for (elt = cfg_list_first(servers);
511 elt = cfg_list_next(elt))
514 server = cfg_listelt_value(elt);
515 name = cfg_obj_asstring(cfg_map_getname(server));
516 if (strcasecmp(name, servername) == 0)
524 * Look for the name of the key to use.
527 ; /* Was set on command line, do nothing. */
528 else if (server != NULL) {
529 DO("get key for server", cfg_map_get(server, "key", &defkey));
530 keyname = cfg_obj_asstring(defkey);
531 } else if (options != NULL) {
532 DO("get default key", cfg_map_get(options, "default-key",
534 keyname = cfg_obj_asstring(defkey);
535 } else if (!key_only)
536 fatal("no key for server and no default");
539 * Get the key's definition.
542 DO("get key", cfg_map_get(config, "key", &key));
544 DO("get config key list", cfg_map_get(config, "key", &keys));
545 for (elt = cfg_list_first(keys);
547 elt = cfg_list_next(elt))
549 key = cfg_listelt_value(elt);
550 if (strcasecmp(cfg_obj_asstring(cfg_map_getname(key)),
555 fatal("no key definition for name %s", keyname);
557 (void)cfg_map_get(key, "secret", &secretobj);
558 (void)cfg_map_get(key, "algorithm", &algorithmobj);
559 if (secretobj == NULL || algorithmobj == NULL)
560 fatal("key must have algorithm and secret");
562 secretstr = cfg_obj_asstring(secretobj);
563 algorithm = cfg_obj_asstring(algorithmobj);
565 if (strcasecmp(algorithm, "hmac-md5") != 0)
566 fatal("unsupported algorithm: %s", algorithm);
568 secret.rstart = (unsigned char *)secretarray;
569 secret.rend = (unsigned char *)secretarray + sizeof(secretarray);
570 DO("decode base64 secret", isccc_base64_decode(secretstr, &secret));
571 secret.rend = secret.rstart;
572 secret.rstart = (unsigned char *)secretarray;
575 * Find the port to connect to.
578 ; /* Was set on command line, do nothing. */
581 (void)cfg_map_get(server, "port", &defport);
582 if (defport == NULL && options != NULL)
583 (void)cfg_map_get(options, "default-port", &defport);
585 if (defport != NULL) {
586 remoteport = cfg_obj_asuint32(defport);
587 if (remoteport > 65535 || remoteport == 0)
588 fatal("port %u out of range", remoteport);
589 } else if (remoteport == 0)
590 remoteport = NS_CONTROL_PORT;
593 result = cfg_map_get(server, "addresses", &addresses);
595 result = ISC_R_NOTFOUND;
596 if (result == ISC_R_SUCCESS) {
597 for (element = cfg_list_first(addresses);
599 element = cfg_list_next(element))
603 address = cfg_listelt_value(element);
604 if (!cfg_obj_issockaddr(address)) {
607 const cfg_obj_t *obj;
609 obj = cfg_tuple_get(address, "name");
610 name = cfg_obj_asstring(obj);
611 obj = cfg_tuple_get(address, "port");
612 if (cfg_obj_isuint32(obj)) {
613 myport = cfg_obj_asuint32(obj);
614 if (myport > ISC_UINT16_MAX ||
616 fatal("port %u out of range",
620 if (nserveraddrs < SERVERADDRS)
621 get_addresses(name, (in_port_t) myport);
623 fprintf(stderr, "too many address: "
624 "%s: dropped\n", name);
627 sa = *cfg_obj_assockaddr(address);
628 if (isc_sockaddr_getport(&sa) == 0)
629 isc_sockaddr_setport(&sa, remoteport);
630 if (nserveraddrs < SERVERADDRS)
631 serveraddrs[nserveraddrs++] = sa;
633 char socktext[ISC_SOCKADDR_FORMATSIZE];
635 isc_sockaddr_format(&sa, socktext,
638 "too many address: %s: dropped\n",
644 if (!local4set && server != NULL) {
646 cfg_map_get(server, "source-address", &address);
647 if (address != NULL) {
648 local4 = *cfg_obj_assockaddr(address);
649 local4set = ISC_TRUE;
652 if (!local4set && options != NULL) {
654 cfg_map_get(options, "default-source-address", &address);
655 if (address != NULL) {
656 local4 = *cfg_obj_assockaddr(address);
657 local4set = ISC_TRUE;
661 if (!local6set && server != NULL) {
663 cfg_map_get(server, "source-address-v6", &address);
664 if (address != NULL) {
665 local6 = *cfg_obj_assockaddr(address);
666 local6set = ISC_TRUE;
669 if (!local6set && options != NULL) {
671 cfg_map_get(options, "default-source-address-v6", &address);
672 if (address != NULL) {
673 local6 = *cfg_obj_assockaddr(address);
674 local6set = ISC_TRUE;
682 main(int argc, char **argv) {
683 isc_boolean_t show_final_mem = ISC_FALSE;
684 isc_result_t result = ISC_R_SUCCESS;
685 isc_taskmgr_t *taskmgr = NULL;
686 isc_task_t *task = NULL;
687 isc_log_t *log = NULL;
688 isc_logconfig_t *logconfig = NULL;
689 isc_logdestination_t logdest;
690 cfg_parser_t *pctx = NULL;
691 cfg_obj_t *config = NULL;
692 const char *keyname = NULL;
700 result = isc_file_progname(*argv, program, sizeof(program));
701 if (result != ISC_R_SUCCESS)
702 memcpy(program, "rndc", 5);
705 admin_conffile = RNDC_CONFFILE;
706 admin_keyfile = RNDC_KEYFILE;
708 isc_sockaddr_any(&local4);
709 isc_sockaddr_any6(&local6);
711 result = isc_app_start();
712 if (result != ISC_R_SUCCESS)
713 fatal("isc_app_start() failed: %s", isc_result_totext(result));
715 isc_commandline_errprint = ISC_FALSE;
717 while ((ch = isc_commandline_parse(argc, argv, "b:c:hk:Mmp:s:Vy:"))
721 if (inet_pton(AF_INET, isc_commandline_argument,
723 isc_sockaddr_fromin(&local4, &in, 0);
724 local4set = ISC_TRUE;
725 } else if (inet_pton(AF_INET6, isc_commandline_argument,
727 isc_sockaddr_fromin6(&local6, &in6, 0);
728 local6set = ISC_TRUE;
733 admin_conffile = isc_commandline_argument;
738 admin_keyfile = isc_commandline_argument;
742 isc_mem_debugging = ISC_MEM_DEBUGTRACE;
746 show_final_mem = ISC_TRUE;
750 remoteport = atoi(isc_commandline_argument);
751 if (remoteport > 65535 || remoteport == 0)
752 fatal("port '%s' out of range",
753 isc_commandline_argument);
757 servername = isc_commandline_argument;
765 keyname = isc_commandline_argument;
769 if (isc_commandline_option != '?') {
770 fprintf(stderr, "%s: invalid argument -%c\n",
771 program, isc_commandline_option);
778 fprintf(stderr, "%s: unhandled option -%c\n",
779 program, isc_commandline_option);
784 argc -= isc_commandline_index;
785 argv += isc_commandline_index;
790 isc_random_get(&serial);
792 DO("create memory context", isc_mem_create(0, 0, &mctx));
793 DO("create socket manager", isc_socketmgr_create(mctx, &socketmgr));
794 DO("create task manager", isc_taskmgr_create(mctx, 1, 0, &taskmgr));
795 DO("create task", isc_task_create(taskmgr, 0, &task));
797 DO("create logging context", isc_log_create(mctx, &log, &logconfig));
798 isc_log_setcontext(log);
799 DO("setting log tag", isc_log_settag(logconfig, progname));
800 logdest.file.stream = stderr;
801 logdest.file.name = NULL;
802 logdest.file.versions = ISC_LOG_ROLLNEVER;
803 logdest.file.maximum_size = 0;
804 DO("creating log channel",
805 isc_log_createchannel(logconfig, "stderr",
806 ISC_LOG_TOFILEDESC, ISC_LOG_INFO, &logdest,
807 ISC_LOG_PRINTTAG|ISC_LOG_PRINTLEVEL));
808 DO("enabling log channel", isc_log_usechannel(logconfig, "stderr",
811 parse_config(mctx, log, keyname, &pctx, &config);
813 isccc_result_register();
818 * Convert argc/argv into a space-delimited command string
819 * similar to what the user might enter in interactive mode
820 * (if that were implemented).
823 for (i = 0; i < argc; i++)
824 argslen += strlen(argv[i]) + 1;
826 args = isc_mem_get(mctx, argslen);
828 DO("isc_mem_get", ISC_R_NOMEMORY);
831 for (i = 0; i < argc; i++) {
832 size_t len = strlen(argv[i]);
833 memcpy(p, argv[i], len);
840 INSIST(p == args + argslen);
842 notify("%s", command);
844 if (strcmp(command, "restart") == 0)
845 fatal("'%s' is not implemented", command);
847 if (nserveraddrs == 0)
848 get_addresses(servername, (in_port_t) remoteport);
850 DO("post event", isc_app_onrun(mctx, task, rndc_start, NULL));
852 result = isc_app_run();
853 if (result != ISC_R_SUCCESS)
854 fatal("isc_app_run() failed: %s", isc_result_totext(result));
856 if (connects > 0 || sends > 0 || recvs > 0)
857 isc_socket_cancel(sock, task, ISC_SOCKCANCEL_ALL);
859 isc_task_detach(&task);
860 isc_taskmgr_destroy(&taskmgr);
861 isc_socketmgr_destroy(&socketmgr);
862 isc_log_destroy(&log);
863 isc_log_setcontext(NULL);
865 cfg_obj_destroy(pctx, &config);
866 cfg_parser_destroy(&pctx);
868 isc_mem_put(mctx, args, argslen);
869 isccc_ccmsg_invalidate(&ccmsg);
874 isc_mem_stats(mctx, stderr);
876 isc_mem_destroy(&mctx);