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.2 2011-02-28 01:19:59 tbox 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 validation newstate [view]\n\
146 Enable / disable DNSSEC validation.\n\
147 *restart Restart the server.\n\
148 addzone [\"file\"] zone [class [view]] { zone-options }\n\
149 Add zone to given view. Requires new-zone-file option.\n\
150 delzone [\"file\"] zone [class [view]]\n\
151 Removes zone from given view. Requires new-zone-file option.\n\
153 * == not yet implemented\n\
161 get_addresses(const char *host, in_port_t port) {
163 int found = 0, count;
166 result = isc_sockaddr_frompath(&serveraddrs[nserveraddrs],
168 if (result == ISC_R_SUCCESS)
171 count = SERVERADDRS - nserveraddrs;
172 result = bind9_getaddresses(host, port,
173 &serveraddrs[nserveraddrs],
175 nserveraddrs += found;
177 if (result != ISC_R_SUCCESS)
178 fatal("couldn't get address for '%s': %s",
179 host, isc_result_totext(result));
180 INSIST(nserveraddrs > 0);
184 rndc_senddone(isc_task_t *task, isc_event_t *event) {
185 isc_socketevent_t *sevent = (isc_socketevent_t *)event;
190 if (sevent->result != ISC_R_SUCCESS)
191 fatal("send failed: %s", isc_result_totext(sevent->result));
192 isc_event_free(&event);
193 if (sends == 0 && recvs == 0) {
194 isc_socket_detach(&sock);
195 isc_task_shutdown(task);
196 RUNTIME_CHECK(isc_app_shutdown() == ISC_R_SUCCESS);
201 rndc_recvdone(isc_task_t *task, isc_event_t *event) {
202 isccc_sexpr_t *response = NULL;
204 isccc_region_t source;
205 char *errormsg = NULL;
206 char *textmsg = NULL;
211 if (ccmsg.result == ISC_R_EOF)
212 fatal("connection to remote host closed\n"
213 "This may indicate that\n"
214 "* the remote server is using an older version of"
215 " the command protocol,\n"
216 "* this host is not authorized to connect,\n"
217 "* the clocks are not synchronized, or\n"
218 "* the key is invalid.");
220 if (ccmsg.result != ISC_R_SUCCESS)
221 fatal("recv failed: %s", isc_result_totext(ccmsg.result));
223 source.rstart = isc_buffer_base(&ccmsg.buffer);
224 source.rend = isc_buffer_used(&ccmsg.buffer);
226 DO("parse message", isccc_cc_fromwire(&source, &response, &secret));
228 data = isccc_alist_lookup(response, "_data");
230 fatal("no data section in response");
231 result = isccc_cc_lookupstring(data, "err", &errormsg);
232 if (result == ISC_R_SUCCESS) {
234 fprintf(stderr, "%s: '%s' failed: %s\n",
235 progname, command, errormsg);
237 else if (result != ISC_R_NOTFOUND)
238 fprintf(stderr, "%s: parsing response failed: %s\n",
239 progname, isc_result_totext(result));
241 result = isccc_cc_lookupstring(data, "text", &textmsg);
242 if (result == ISC_R_SUCCESS)
243 printf("%s\n", textmsg);
244 else if (result != ISC_R_NOTFOUND)
245 fprintf(stderr, "%s: parsing response failed: %s\n",
246 progname, isc_result_totext(result));
248 isc_event_free(&event);
249 isccc_sexpr_free(&response);
250 if (sends == 0 && recvs == 0) {
251 isc_socket_detach(&sock);
252 isc_task_shutdown(task);
253 RUNTIME_CHECK(isc_app_shutdown() == ISC_R_SUCCESS);
258 rndc_recvnonce(isc_task_t *task, isc_event_t *event) {
259 isccc_sexpr_t *response = NULL;
260 isccc_sexpr_t *_ctrl;
261 isccc_region_t source;
264 isccc_sexpr_t *request = NULL;
268 isccc_region_t message;
274 if (ccmsg.result == ISC_R_EOF)
275 fatal("connection to remote host closed\n"
276 "This may indicate that\n"
277 "* the remote server is using an older version of"
278 " the command protocol,\n"
279 "* this host is not authorized to connect,\n"
280 "* the clocks are not synchronized, or\n"
281 "* the key is invalid.");
283 if (ccmsg.result != ISC_R_SUCCESS)
284 fatal("recv failed: %s", isc_result_totext(ccmsg.result));
286 source.rstart = isc_buffer_base(&ccmsg.buffer);
287 source.rend = isc_buffer_used(&ccmsg.buffer);
289 DO("parse message", isccc_cc_fromwire(&source, &response, &secret));
291 _ctrl = isccc_alist_lookup(response, "_ctrl");
293 fatal("_ctrl section missing");
295 if (isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS)
298 isc_stdtime_get(&now);
300 DO("create message", isccc_cc_createmessage(1, NULL, NULL, ++serial,
301 now, now + 60, &request));
302 data = isccc_alist_lookup(request, "_data");
304 fatal("_data section missing");
305 if (isccc_cc_definestring(data, "type", args) == NULL)
306 fatal("out of memory");
308 _ctrl = isccc_alist_lookup(request, "_ctrl");
310 fatal("_ctrl section missing");
311 if (isccc_cc_defineuint32(_ctrl, "_nonce", nonce) == NULL)
312 fatal("out of memory");
314 message.rstart = databuf + 4;
315 message.rend = databuf + sizeof(databuf);
316 DO("render message", isccc_cc_towire(request, &message, &secret));
317 len = sizeof(databuf) - REGION_SIZE(message);
318 isc_buffer_init(&b, databuf, 4);
319 isc_buffer_putuint32(&b, len - 4);
323 isccc_ccmsg_cancelread(&ccmsg);
324 DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg, task,
325 rndc_recvdone, NULL));
327 DO("send message", isc_socket_send(sock, &r, task, rndc_senddone,
331 isc_event_free(&event);
332 isccc_sexpr_free(&response);
337 rndc_connected(isc_task_t *task, isc_event_t *event) {
338 char socktext[ISC_SOCKADDR_FORMATSIZE];
339 isc_socketevent_t *sevent = (isc_socketevent_t *)event;
340 isccc_sexpr_t *request = NULL;
343 isccc_region_t message;
351 if (sevent->result != ISC_R_SUCCESS) {
352 isc_sockaddr_format(&serveraddrs[currentaddr], socktext,
354 if (sevent->result != ISC_R_CANCELED &&
355 ++currentaddr < nserveraddrs)
357 notify("connection failed: %s: %s", socktext,
358 isc_result_totext(sevent->result));
359 isc_socket_detach(&sock);
360 isc_event_free(&event);
361 rndc_startconnect(&serveraddrs[currentaddr], task);
364 fatal("connect failed: %s: %s", socktext,
365 isc_result_totext(sevent->result));
368 isc_stdtime_get(&now);
369 DO("create message", isccc_cc_createmessage(1, NULL, NULL, ++serial,
370 now, now + 60, &request));
371 data = isccc_alist_lookup(request, "_data");
373 fatal("_data section missing");
374 if (isccc_cc_definestring(data, "type", "null") == NULL)
375 fatal("out of memory");
376 message.rstart = databuf + 4;
377 message.rend = databuf + sizeof(databuf);
378 DO("render message", isccc_cc_towire(request, &message, &secret));
379 len = sizeof(databuf) - REGION_SIZE(message);
380 isc_buffer_init(&b, databuf, 4);
381 isc_buffer_putuint32(&b, len - 4);
385 isccc_ccmsg_init(mctx, sock, &ccmsg);
386 isccc_ccmsg_setmaxsize(&ccmsg, 1024 * 1024);
388 DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg, task,
389 rndc_recvnonce, NULL));
391 DO("send message", isc_socket_send(sock, &r, task, rndc_senddone,
394 isc_event_free(&event);
398 rndc_startconnect(isc_sockaddr_t *addr, isc_task_t *task) {
401 isc_sockettype_t type;
403 char socktext[ISC_SOCKADDR_FORMATSIZE];
405 isc_sockaddr_format(addr, socktext, sizeof(socktext));
407 notify("using server %s (%s)", servername, socktext);
409 pf = isc_sockaddr_pf(addr);
410 if (pf == AF_INET || pf == AF_INET6)
411 type = isc_sockettype_tcp;
413 type = isc_sockettype_unix;
414 DO("create socket", isc_socket_create(socketmgr, pf, type, &sock));
415 switch (isc_sockaddr_pf(addr)) {
417 DO("bind socket", isc_socket_bind(sock, &local4, 0));
420 DO("bind socket", isc_socket_bind(sock, &local6, 0));
425 DO("connect", isc_socket_connect(sock, addr, task, rndc_connected,
431 rndc_start(isc_task_t *task, isc_event_t *event) {
432 isc_event_free(&event);
435 rndc_startconnect(&serveraddrs[currentaddr], task);
439 parse_config(isc_mem_t *mctx, isc_log_t *log, const char *keyname,
440 cfg_parser_t **pctxp, cfg_obj_t **configp)
443 const char *conffile = admin_conffile;
444 const cfg_obj_t *addresses = NULL;
445 const cfg_obj_t *defkey = NULL;
446 const cfg_obj_t *options = NULL;
447 const cfg_obj_t *servers = NULL;
448 const cfg_obj_t *server = NULL;
449 const cfg_obj_t *keys = NULL;
450 const cfg_obj_t *key = NULL;
451 const cfg_obj_t *defport = NULL;
452 const cfg_obj_t *secretobj = NULL;
453 const cfg_obj_t *algorithmobj = NULL;
454 cfg_obj_t *config = NULL;
455 const cfg_obj_t *address = NULL;
456 const cfg_listelt_t *elt;
457 const char *secretstr;
458 const char *algorithm;
459 static char secretarray[1024];
460 const cfg_type_t *conftype = &cfg_type_rndcconf;
461 isc_boolean_t key_only = ISC_FALSE;
462 const cfg_listelt_t *element;
464 if (! isc_file_exists(conffile)) {
465 conffile = admin_keyfile;
466 conftype = &cfg_type_rndckey;
468 if (! isc_file_exists(conffile))
469 fatal("neither %s nor %s was found",
470 admin_conffile, admin_keyfile);
472 } else if (! c_flag && isc_file_exists(admin_keyfile)) {
473 fprintf(stderr, "WARNING: key file (%s) exists, but using "
474 "default configuration file (%s)\n",
475 admin_keyfile, admin_conffile);
478 DO("create parser", cfg_parser_create(mctx, log, pctxp));
481 * The parser will output its own errors, so DO() is not used.
483 result = cfg_parse_file(*pctxp, conffile, conftype, &config);
484 if (result != ISC_R_SUCCESS)
485 fatal("could not load rndc configuration");
488 (void)cfg_map_get(config, "options", &options);
490 if (key_only && servername == NULL)
491 servername = "127.0.0.1";
492 else if (servername == NULL && options != NULL) {
493 const cfg_obj_t *defserverobj = NULL;
494 (void)cfg_map_get(options, "default-server", &defserverobj);
495 if (defserverobj != NULL)
496 servername = cfg_obj_asstring(defserverobj);
499 if (servername == NULL)
500 fatal("no server specified and no default");
503 (void)cfg_map_get(config, "server", &servers);
504 if (servers != NULL) {
505 for (elt = cfg_list_first(servers);
507 elt = cfg_list_next(elt))
510 server = cfg_listelt_value(elt);
511 name = cfg_obj_asstring(cfg_map_getname(server));
512 if (strcasecmp(name, servername) == 0)
520 * Look for the name of the key to use.
523 ; /* Was set on command line, do nothing. */
524 else if (server != NULL) {
525 DO("get key for server", cfg_map_get(server, "key", &defkey));
526 keyname = cfg_obj_asstring(defkey);
527 } else if (options != NULL) {
528 DO("get default key", cfg_map_get(options, "default-key",
530 keyname = cfg_obj_asstring(defkey);
531 } else if (!key_only)
532 fatal("no key for server and no default");
535 * Get the key's definition.
538 DO("get key", cfg_map_get(config, "key", &key));
540 DO("get config key list", cfg_map_get(config, "key", &keys));
541 for (elt = cfg_list_first(keys);
543 elt = cfg_list_next(elt))
545 key = cfg_listelt_value(elt);
546 if (strcasecmp(cfg_obj_asstring(cfg_map_getname(key)),
551 fatal("no key definition for name %s", keyname);
553 (void)cfg_map_get(key, "secret", &secretobj);
554 (void)cfg_map_get(key, "algorithm", &algorithmobj);
555 if (secretobj == NULL || algorithmobj == NULL)
556 fatal("key must have algorithm and secret");
558 secretstr = cfg_obj_asstring(secretobj);
559 algorithm = cfg_obj_asstring(algorithmobj);
561 if (strcasecmp(algorithm, "hmac-md5") != 0)
562 fatal("unsupported algorithm: %s", algorithm);
564 secret.rstart = (unsigned char *)secretarray;
565 secret.rend = (unsigned char *)secretarray + sizeof(secretarray);
566 DO("decode base64 secret", isccc_base64_decode(secretstr, &secret));
567 secret.rend = secret.rstart;
568 secret.rstart = (unsigned char *)secretarray;
571 * Find the port to connect to.
574 ; /* Was set on command line, do nothing. */
577 (void)cfg_map_get(server, "port", &defport);
578 if (defport == NULL && options != NULL)
579 (void)cfg_map_get(options, "default-port", &defport);
581 if (defport != NULL) {
582 remoteport = cfg_obj_asuint32(defport);
583 if (remoteport > 65535 || remoteport == 0)
584 fatal("port %u out of range", remoteport);
585 } else if (remoteport == 0)
586 remoteport = NS_CONTROL_PORT;
589 result = cfg_map_get(server, "addresses", &addresses);
591 result = ISC_R_NOTFOUND;
592 if (result == ISC_R_SUCCESS) {
593 for (element = cfg_list_first(addresses);
595 element = cfg_list_next(element))
599 address = cfg_listelt_value(element);
600 if (!cfg_obj_issockaddr(address)) {
603 const cfg_obj_t *obj;
605 obj = cfg_tuple_get(address, "name");
606 name = cfg_obj_asstring(obj);
607 obj = cfg_tuple_get(address, "port");
608 if (cfg_obj_isuint32(obj)) {
609 myport = cfg_obj_asuint32(obj);
610 if (myport > ISC_UINT16_MAX ||
612 fatal("port %u out of range",
616 if (nserveraddrs < SERVERADDRS)
617 get_addresses(name, (in_port_t) myport);
619 fprintf(stderr, "too many address: "
620 "%s: dropped\n", name);
623 sa = *cfg_obj_assockaddr(address);
624 if (isc_sockaddr_getport(&sa) == 0)
625 isc_sockaddr_setport(&sa, remoteport);
626 if (nserveraddrs < SERVERADDRS)
627 serveraddrs[nserveraddrs++] = sa;
629 char socktext[ISC_SOCKADDR_FORMATSIZE];
631 isc_sockaddr_format(&sa, socktext,
634 "too many address: %s: dropped\n",
640 if (!local4set && server != NULL) {
642 cfg_map_get(server, "source-address", &address);
643 if (address != NULL) {
644 local4 = *cfg_obj_assockaddr(address);
645 local4set = ISC_TRUE;
648 if (!local4set && options != NULL) {
650 cfg_map_get(options, "default-source-address", &address);
651 if (address != NULL) {
652 local4 = *cfg_obj_assockaddr(address);
653 local4set = ISC_TRUE;
657 if (!local6set && server != NULL) {
659 cfg_map_get(server, "source-address-v6", &address);
660 if (address != NULL) {
661 local6 = *cfg_obj_assockaddr(address);
662 local6set = ISC_TRUE;
665 if (!local6set && options != NULL) {
667 cfg_map_get(options, "default-source-address-v6", &address);
668 if (address != NULL) {
669 local6 = *cfg_obj_assockaddr(address);
670 local6set = ISC_TRUE;
678 main(int argc, char **argv) {
679 isc_boolean_t show_final_mem = ISC_FALSE;
680 isc_result_t result = ISC_R_SUCCESS;
681 isc_taskmgr_t *taskmgr = NULL;
682 isc_task_t *task = NULL;
683 isc_log_t *log = NULL;
684 isc_logconfig_t *logconfig = NULL;
685 isc_logdestination_t logdest;
686 cfg_parser_t *pctx = NULL;
687 cfg_obj_t *config = NULL;
688 const char *keyname = NULL;
696 result = isc_file_progname(*argv, program, sizeof(program));
697 if (result != ISC_R_SUCCESS)
698 memcpy(program, "rndc", 5);
701 admin_conffile = RNDC_CONFFILE;
702 admin_keyfile = RNDC_KEYFILE;
704 isc_sockaddr_any(&local4);
705 isc_sockaddr_any6(&local6);
707 result = isc_app_start();
708 if (result != ISC_R_SUCCESS)
709 fatal("isc_app_start() failed: %s", isc_result_totext(result));
711 isc_commandline_errprint = ISC_FALSE;
713 while ((ch = isc_commandline_parse(argc, argv, "b:c:hk:Mmp:s:Vy:"))
717 if (inet_pton(AF_INET, isc_commandline_argument,
719 isc_sockaddr_fromin(&local4, &in, 0);
720 local4set = ISC_TRUE;
721 } else if (inet_pton(AF_INET6, isc_commandline_argument,
723 isc_sockaddr_fromin6(&local6, &in6, 0);
724 local6set = ISC_TRUE;
729 admin_conffile = isc_commandline_argument;
734 admin_keyfile = isc_commandline_argument;
738 isc_mem_debugging = ISC_MEM_DEBUGTRACE;
742 show_final_mem = ISC_TRUE;
746 remoteport = atoi(isc_commandline_argument);
747 if (remoteport > 65535 || remoteport == 0)
748 fatal("port '%s' out of range",
749 isc_commandline_argument);
753 servername = isc_commandline_argument;
761 keyname = isc_commandline_argument;
765 if (isc_commandline_option != '?') {
766 fprintf(stderr, "%s: invalid argument -%c\n",
767 program, isc_commandline_option);
774 fprintf(stderr, "%s: unhandled option -%c\n",
775 program, isc_commandline_option);
780 argc -= isc_commandline_index;
781 argv += isc_commandline_index;
786 isc_random_get(&serial);
788 DO("create memory context", isc_mem_create(0, 0, &mctx));
789 DO("create socket manager", isc_socketmgr_create(mctx, &socketmgr));
790 DO("create task manager", isc_taskmgr_create(mctx, 1, 0, &taskmgr));
791 DO("create task", isc_task_create(taskmgr, 0, &task));
793 DO("create logging context", isc_log_create(mctx, &log, &logconfig));
794 isc_log_setcontext(log);
795 DO("setting log tag", isc_log_settag(logconfig, progname));
796 logdest.file.stream = stderr;
797 logdest.file.name = NULL;
798 logdest.file.versions = ISC_LOG_ROLLNEVER;
799 logdest.file.maximum_size = 0;
800 DO("creating log channel",
801 isc_log_createchannel(logconfig, "stderr",
802 ISC_LOG_TOFILEDESC, ISC_LOG_INFO, &logdest,
803 ISC_LOG_PRINTTAG|ISC_LOG_PRINTLEVEL));
804 DO("enabling log channel", isc_log_usechannel(logconfig, "stderr",
807 parse_config(mctx, log, keyname, &pctx, &config);
809 isccc_result_register();
814 * Convert argc/argv into a space-delimited command string
815 * similar to what the user might enter in interactive mode
816 * (if that were implemented).
819 for (i = 0; i < argc; i++)
820 argslen += strlen(argv[i]) + 1;
822 args = isc_mem_get(mctx, argslen);
824 DO("isc_mem_get", ISC_R_NOMEMORY);
827 for (i = 0; i < argc; i++) {
828 size_t len = strlen(argv[i]);
829 memcpy(p, argv[i], len);
836 INSIST(p == args + argslen);
838 notify("%s", command);
840 if (strcmp(command, "restart") == 0)
841 fatal("'%s' is not implemented", command);
843 if (nserveraddrs == 0)
844 get_addresses(servername, (in_port_t) remoteport);
846 DO("post event", isc_app_onrun(mctx, task, rndc_start, NULL));
848 result = isc_app_run();
849 if (result != ISC_R_SUCCESS)
850 fatal("isc_app_run() failed: %s", isc_result_totext(result));
852 if (connects > 0 || sends > 0 || recvs > 0)
853 isc_socket_cancel(sock, task, ISC_SOCKCANCEL_ALL);
855 isc_task_detach(&task);
856 isc_taskmgr_destroy(&taskmgr);
857 isc_socketmgr_destroy(&socketmgr);
858 isc_log_destroy(&log);
859 isc_log_setcontext(NULL);
861 cfg_obj_destroy(pctx, &config);
862 cfg_parser_destroy(&pctx);
864 isc_mem_put(mctx, args, argslen);
865 isccc_ccmsg_invalidate(&ccmsg);
870 isc_mem_stats(mctx, stderr);
872 isc_mem_destroy(&mctx);