bind - Upgraded vendor branch to 9.5.2-P1
[dragonfly.git] / contrib / bind-9.2.4rc7 / bin / rndc / rndc.c
1 /*
2  * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 2000, 2001, 2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and 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.
8  *
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.
16  */
17
18 /* $Id: rndc.c,v 1.77.2.6 2004/03/09 06:09:27 marka Exp $ */
19
20 /*
21  * Principal Author: DCL
22  */
23
24 #include <config.h>
25
26 #include <stdlib.h>
27
28 #include <isc/app.h>
29 #include <isc/buffer.h>
30 #include <isc/commandline.h>
31 #include <isc/file.h>
32 #include <isc/log.h>
33 #include <isc/mem.h>
34 #include <isc/netdb.h>
35 #include <isc/random.h>
36 #include <isc/socket.h>
37 #include <isc/stdtime.h>
38 #include <isc/string.h>
39 #include <isc/task.h>
40 #include <isc/thread.h>
41 #include <isc/util.h>
42
43 #include <isccfg/cfg.h>
44
45 #include <isccc/alist.h>
46 #include <isccc/base64.h>
47 #include <isccc/cc.h>
48 #include <isccc/ccmsg.h>
49 #include <isccc/result.h>
50 #include <isccc/sexpr.h>
51 #include <isccc/types.h>
52 #include <isccc/util.h>
53
54 #include "util.h"
55
56 #ifdef HAVE_ADDRINFO
57 #ifdef HAVE_GETADDRINFO
58 #ifdef HAVE_GAISTRERROR
59 #define USE_GETADDRINFO
60 #endif
61 #endif
62 #endif
63
64 #ifndef USE_GETADDRINFO
65 #ifndef ISC_PLATFORM_NONSTDHERRNO
66 extern int h_errno;
67 #endif
68 #endif
69
70 char *progname;
71 isc_boolean_t verbose;
72
73 static const char *admin_conffile;
74 static const char *admin_keyfile;
75 static const char *version = VERSION;
76 static const char *servername = NULL;
77 static unsigned int remoteport = 0;
78 static isc_socketmgr_t *socketmgr = NULL;
79 static unsigned char databuf[2048];
80 static isccc_ccmsg_t ccmsg;
81 static isccc_region_t secret;
82 static isc_boolean_t failed = ISC_FALSE;
83 static isc_mem_t *mctx;
84 static int sends, recvs, connects;
85 static char *command;
86 static char *args;
87 static char program[256];
88 static isc_socket_t *sock = NULL;
89 static isc_uint32_t serial;
90
91 static void
92 usage(int status) {
93         fprintf(stderr, "\
94 Usage: %s [-c config] [-s server] [-p port]\n\
95         [-k key-file ] [-y key] [-V] command\n\
96 \n\
97 command is one of the following:\n\
98 \n\
99   reload        Reload configuration file and zones.\n\
100   reload zone [class [view]]\n\
101                 Reload a single zone.\n\
102   refresh zone [class [view]]\n\
103                 Schedule immediate maintenance for a zone.\n\
104   reconfig      Reload configuration file and new zones only.\n\
105   stats         Write server statistics to the statistics file.\n\
106   querylog      Toggle query logging.\n\
107   dumpdb        Dump cache(s) to the dump file (named_dump.db).\n\
108   stop          Save pending updates to master files and stop the server.\n\
109   halt          Stop the server without saving pending updates.\n\
110   trace         Increment debugging level by one.\n\
111   trace level   Change the debugging level.\n\
112   notrace       Set debugging level to 0.\n\
113   flush         Flushes all of the server's caches.\n\
114   flush [view]  Flushes the server's cache for a view.\n\
115   status        Display status of the server.\n\
116   *restart      Restart the server.\n\
117 \n\
118 * == not yet implemented\n\
119 Version: %s\n",
120                 progname, version);
121
122         exit(status);
123 }
124
125 static void
126 get_address(const char *host, in_port_t port, isc_sockaddr_t *sockaddr) {
127         struct in_addr in4;
128         struct in6_addr in6;
129         isc_boolean_t have_ipv6;
130 #ifdef USE_GETADDRINFO
131         struct addrinfo *res = NULL, hints;
132         int result;
133 #else
134         struct hostent *he;
135 #endif
136
137         have_ipv6 = ISC_TF(isc_net_probeipv6() == ISC_R_SUCCESS);
138
139         /*
140          * Assume we have v4 if we don't have v6, since setup_libs
141          * fatal()'s out if we don't have either.
142          */
143         if (have_ipv6 && inet_pton(AF_INET6, host, &in6) == 1)
144                 isc_sockaddr_fromin6(sockaddr, &in6, port);
145         else if (inet_pton(AF_INET, host, &in4) == 1)
146                 isc_sockaddr_fromin(sockaddr, &in4, port);
147         else {
148 #ifdef USE_GETADDRINFO
149                 memset(&hints, 0, sizeof(hints));
150                 if (!have_ipv6)
151                         hints.ai_family = PF_INET;
152                 else if (isc_net_probeipv4() != ISC_R_SUCCESS)
153                         hints.ai_family = PF_INET6;
154                 else {
155                         hints.ai_family = PF_UNSPEC;
156 #ifdef AI_ADDRCONFIG
157                         hints.ai_flags = AI_ADDRCONFIG;
158 #endif
159                 }
160                 hints.ai_socktype = SOCK_STREAM;
161                 isc_app_block();
162 #ifdef AI_ADDRCONFIG
163  again:
164 #endif
165                 result = getaddrinfo(host, NULL, &hints, &res);
166 #ifdef AI_ADDRCONFIG
167                 if (result == EAI_BADFLAGS &&
168                     (hints.ai_flags & AI_ADDRCONFIG) != 0) {
169                         hints.ai_flags &= ~AI_ADDRCONFIG;
170                         goto again;
171                 }
172 #endif
173                 isc_app_unblock();
174                 if (result != 0)
175                         fatal("Couldn't find server '%s': %s",
176                               host, gai_strerror(result));
177                 memcpy(&sockaddr->type.sa, res->ai_addr, res->ai_addrlen);
178                 sockaddr->length = res->ai_addrlen;
179                 isc_sockaddr_setport(sockaddr, port);
180                 freeaddrinfo(res);
181 #else
182                 isc_app_block();
183                 he = gethostbyname(host);
184                 isc_app_unblock();
185                 if (he == NULL)
186                         fatal("Couldn't find server '%s' (h_errno=%d)",
187                               host, h_errno);
188                 INSIST(he->h_addrtype == AF_INET);
189                 isc_sockaddr_fromin(sockaddr,
190                                     (struct in_addr *)(he->h_addr_list[0]),
191                                     port);
192 #endif
193         }
194 }
195
196 static void
197 rndc_senddone(isc_task_t *task, isc_event_t *event) {
198         isc_socketevent_t *sevent = (isc_socketevent_t *)event;
199
200         UNUSED(task);
201
202         sends--;
203         if (sevent->result != ISC_R_SUCCESS)
204                 fatal("send failed: %s", isc_result_totext(sevent->result));
205         isc_event_free(&event);
206 }
207
208 static void
209 rndc_recvdone(isc_task_t *task, isc_event_t *event) {
210         isccc_sexpr_t *response = NULL;
211         isccc_sexpr_t *data;
212         isccc_region_t source;
213         char *errormsg = NULL;
214         char *textmsg = NULL;
215         isc_result_t result;
216
217         recvs--;
218
219         if (ccmsg.result == ISC_R_EOF)
220                 fatal("connection to remote host closed\n"
221                       "This may indicate that the remote server is using "
222                       "an older version of \n"
223                       "the command protocol, this host is not authorized "
224                       "to connect,\nor the key is invalid.");
225
226         if (ccmsg.result != ISC_R_SUCCESS)
227                 fatal("recv failed: %s", isc_result_totext(ccmsg.result));
228
229         source.rstart = isc_buffer_base(&ccmsg.buffer);
230         source.rend = isc_buffer_used(&ccmsg.buffer);
231
232         DO("parse message", isccc_cc_fromwire(&source, &response, &secret));
233
234         data = isccc_alist_lookup(response, "_data");
235         if (data == NULL)
236                 fatal("no data section in response");
237         result = isccc_cc_lookupstring(data, "err", &errormsg);
238         if (result == ISC_R_SUCCESS) {
239                 failed = ISC_TRUE;
240                 fprintf(stderr, "%s: '%s' failed: %s\n",
241                         progname, command, errormsg);
242         }
243         else if (result != ISC_R_NOTFOUND)
244                 fprintf(stderr, "%s: parsing response failed: %s\n",
245                         progname, isc_result_totext(result));
246
247         result = isccc_cc_lookupstring(data, "text", &textmsg);
248         if (result == ISC_R_SUCCESS)
249                 printf("%s\n", textmsg);
250         else if (result != ISC_R_NOTFOUND)
251                 fprintf(stderr, "%s: parsing response failed: %s\n",
252                         progname, isc_result_totext(result));
253
254         isc_event_free(&event);
255         isccc_sexpr_free(&response);
256         isc_socket_detach(&sock);
257         isc_task_shutdown(task);
258         isc_app_shutdown();
259 }
260
261 static void
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;
266         isc_result_t result;
267         isc_uint32_t nonce;
268         isccc_sexpr_t *request = NULL;
269         isccc_time_t now;
270         isc_region_t r;
271         isccc_sexpr_t *data;
272         isccc_region_t message;
273         isc_uint32_t len;
274         isc_buffer_t b;
275
276         recvs--;
277
278         if (ccmsg.result == ISC_R_EOF)
279                 fatal("connection to remote host closed\n"
280                       "This may indicate that the remote server is using "
281                       "an older version of \n"
282                       "the command protocol, this host is not authorized "
283                       "to connect,\nor the key is invalid.");
284
285         if (ccmsg.result != ISC_R_SUCCESS)
286                 fatal("recv failed: %s", isc_result_totext(ccmsg.result));
287
288         source.rstart = isc_buffer_base(&ccmsg.buffer);
289         source.rend = isc_buffer_used(&ccmsg.buffer);
290
291         DO("parse message", isccc_cc_fromwire(&source, &response, &secret));
292
293         _ctrl = isccc_alist_lookup(response, "_ctrl");
294         if (_ctrl == NULL)
295                 fatal("_ctrl section missing");
296         nonce = 0;
297         if (isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS)
298                 nonce = 0;
299
300         isc_stdtime_get(&now);
301
302         DO("create message", isccc_cc_createmessage(1, NULL, NULL, ++serial,
303                                                     now, now + 60, &request));
304         data = isccc_alist_lookup(request, "_data");
305         if (data == NULL)
306                 fatal("_data section missing");
307         if (isccc_cc_definestring(data, "type", args) == NULL)
308                 fatal("out of memory");
309         if (nonce != 0) {
310                 _ctrl = isccc_alist_lookup(request, "_ctrl");
311                 if (_ctrl == NULL)
312                         fatal("_ctrl section missing");
313                 if (isccc_cc_defineuint32(_ctrl, "_nonce", nonce) == NULL)
314                         fatal("out of memory");
315         }
316         message.rstart = databuf + 4;
317         message.rend = databuf + sizeof(databuf);
318         DO("render message", isccc_cc_towire(request, &message, &secret));
319         len = sizeof(databuf) - REGION_SIZE(message);
320         isc_buffer_init(&b, databuf, 4);
321         isc_buffer_putuint32(&b, len - 4);
322         r.length = len;
323         r.base = databuf;
324
325         isccc_ccmsg_cancelread(&ccmsg);
326         DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg, task,
327                                                     rndc_recvdone, NULL));
328         recvs++;
329         DO("send message", isc_socket_send(sock, &r, task, rndc_senddone,
330                                            NULL));
331         sends++;
332
333         isc_event_free(&event);
334         isccc_sexpr_free(&response);
335         return;
336 }
337
338 static void
339 rndc_connected(isc_task_t *task, isc_event_t *event) {
340         isc_socketevent_t *sevent = (isc_socketevent_t *)event;
341         isccc_sexpr_t *request = NULL;
342         isccc_sexpr_t *data;
343         isccc_time_t now;
344         isccc_region_t message;
345         isc_region_t r;
346         isc_uint32_t len;
347         isc_buffer_t b;
348         isc_result_t result;
349
350         connects--;
351
352         if (sevent->result != ISC_R_SUCCESS)
353                 fatal("connect failed: %s", isc_result_totext(sevent->result));
354
355         isc_stdtime_get(&now);
356         DO("create message", isccc_cc_createmessage(1, NULL, NULL, ++serial,
357                                                     now, now + 60, &request));
358         data = isccc_alist_lookup(request, "_data");
359         if (data == NULL)
360                 fatal("_data section missing");
361         if (isccc_cc_definestring(data, "type", "null") == NULL)
362                 fatal("out of memory");
363         message.rstart = databuf + 4;
364         message.rend = databuf + sizeof(databuf);
365         DO("render message", isccc_cc_towire(request, &message, &secret));
366         len = sizeof(databuf) - REGION_SIZE(message);
367         isc_buffer_init(&b, databuf, 4);
368         isc_buffer_putuint32(&b, len - 4);
369         r.length = len;
370         r.base = databuf;
371
372         isccc_ccmsg_init(mctx, sock, &ccmsg);
373         isccc_ccmsg_setmaxsize(&ccmsg, 1024);
374
375         DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg, task,
376                                                     rndc_recvnonce, NULL));
377         recvs++;
378         DO("send message", isc_socket_send(sock, &r, task, rndc_senddone,
379                                            NULL));
380         sends++;
381         isc_event_free(&event);
382 }
383
384 static void
385 rndc_start(isc_task_t *task, isc_event_t *event) {
386         isc_sockaddr_t addr;
387         isc_result_t result;
388         char socktext[ISC_SOCKADDR_FORMATSIZE];
389
390         isc_event_free(&event);
391
392         get_address(servername, (in_port_t) remoteport, &addr);
393
394         isc_sockaddr_format(&addr, socktext, sizeof(socktext));
395
396         notify("using server %s (%s)", servername, socktext);
397
398         DO("create socket", isc_socket_create(socketmgr,
399                                               isc_sockaddr_pf(&addr),
400                                               isc_sockettype_tcp, &sock));
401         DO("connect", isc_socket_connect(sock, &addr, task, rndc_connected,
402                                          NULL));
403         connects++;
404 }
405
406 static void
407 parse_config(isc_mem_t *mctx, isc_log_t *log, const char *keyname,
408              cfg_parser_t **pctxp, cfg_obj_t **configp)
409 {
410         isc_result_t result;
411         const char *conffile = admin_conffile;
412         cfg_obj_t *defkey = NULL;
413         cfg_obj_t *options = NULL;
414         cfg_obj_t *servers = NULL;
415         cfg_obj_t *server = NULL;
416         cfg_obj_t *keys = NULL;
417         cfg_obj_t *key = NULL;
418         cfg_obj_t *defport = NULL;
419         cfg_obj_t *secretobj = NULL;
420         cfg_obj_t *algorithmobj = NULL;
421         cfg_obj_t *config = NULL;
422         cfg_listelt_t *elt;
423         const char *secretstr;
424         const char *algorithm;
425         static char secretarray[1024];
426         const cfg_type_t *conftype = &cfg_type_rndcconf;
427         isc_boolean_t key_only = ISC_FALSE;
428
429         if (! isc_file_exists(conffile)) {
430                 conffile = admin_keyfile;
431                 conftype = &cfg_type_rndckey;
432
433                 if (! isc_file_exists(conffile))
434                         fatal("neither %s nor %s was found",
435                               admin_conffile, admin_keyfile);
436                 key_only = ISC_TRUE;
437         }
438
439         DO("create parser", cfg_parser_create(mctx, log, pctxp));
440
441         /*
442          * The parser will output its own errors, so DO() is not used.
443          */
444         result = cfg_parse_file(*pctxp, conffile, conftype, &config);
445         if (result != ISC_R_SUCCESS)
446                 fatal("could not load rndc configuration");
447
448         if (!key_only)
449                 (void)cfg_map_get(config, "options", &options);
450
451         if (key_only && servername == NULL)
452                 servername = "127.0.0.1";
453         else if (servername == NULL && options != NULL) {
454                 cfg_obj_t *defserverobj = NULL;
455                 (void)cfg_map_get(options, "default-server", &defserverobj);
456                 if (defserverobj != NULL)
457                         servername = cfg_obj_asstring(defserverobj);
458         }
459
460         if (servername == NULL)
461                 fatal("no server specified and no default");
462
463         if (!key_only) {
464                 cfg_map_get(config, "server", &servers);
465                 if (servers != NULL) {
466                         for (elt = cfg_list_first(servers);
467                              elt != NULL; 
468                              elt = cfg_list_next(elt))
469                         {
470                                 const char *name;
471                                 server = cfg_listelt_value(elt);
472                                 name = cfg_obj_asstring(cfg_map_getname(server));
473                                 if (strcasecmp(name, servername) == 0)
474                                         break;
475                                 server = NULL;
476                         }
477                 }
478         }
479
480         /*
481          * Look for the name of the key to use.
482          */
483         if (keyname != NULL)
484                 ;               /* Was set on command line, do nothing. */
485         else if (server != NULL) {
486                 DO("get key for server", cfg_map_get(server, "key", &defkey));
487                 keyname = cfg_obj_asstring(defkey);
488         } else if (options != NULL) {
489                 DO("get default key", cfg_map_get(options, "default-key",
490                                                   &defkey));
491                 keyname = cfg_obj_asstring(defkey);
492         } else if (!key_only)
493                 fatal("no key for server and no default");
494
495         /*
496          * Get the key's definition.
497          */
498         if (key_only)
499                 DO("get key", cfg_map_get(config, "key", &key));
500         else {
501                 DO("get config key list", cfg_map_get(config, "key", &keys));
502                 for (elt = cfg_list_first(keys);
503                      elt != NULL; 
504                      elt = cfg_list_next(elt))
505                 {
506                         key = cfg_listelt_value(elt);
507                         if (strcasecmp(cfg_obj_asstring(cfg_map_getname(key)),
508                                        keyname) == 0)
509                                 break;
510                 }
511                 if (elt == NULL)
512                         fatal("no key definition for name %s", keyname);
513         }
514         (void)cfg_map_get(key, "secret", &secretobj);
515         (void)cfg_map_get(key, "algorithm", &algorithmobj);
516         if (secretobj == NULL || algorithmobj == NULL)
517                 fatal("key must have algorithm and secret");
518
519         secretstr = cfg_obj_asstring(secretobj);
520         algorithm = cfg_obj_asstring(algorithmobj);
521
522         if (strcasecmp(algorithm, "hmac-md5") != 0)
523                 fatal("unsupported algorithm: %s", algorithm);
524
525         secret.rstart = (unsigned char *)secretarray;
526         secret.rend = (unsigned char *)secretarray + sizeof(secretarray);
527         DO("decode base64 secret", isccc_base64_decode(secretstr, &secret));
528         secret.rend = secret.rstart;
529         secret.rstart = (unsigned char *)secretarray;
530
531         /*
532          * Find the port to connect to.
533          */
534         if (remoteport != 0)
535                 ;               /* Was set on command line, do nothing. */
536         else {
537                 if (server != NULL)
538                         (void)cfg_map_get(server, "port", &defport);
539                 if (defport == NULL && options != NULL)
540                         cfg_map_get(options, "default-port", &defport);
541         }
542         if (defport != NULL) {
543                 remoteport = cfg_obj_asuint32(defport);
544                 if (remoteport > 65535 || remoteport == 0)
545                         fatal("port %d out of range", remoteport);
546         } else if (remoteport == 0)
547                 remoteport = NS_CONTROL_PORT;
548
549         *configp = config;
550 }
551
552 int
553 main(int argc, char **argv) {
554         isc_boolean_t show_final_mem = ISC_FALSE;
555         isc_result_t result = ISC_R_SUCCESS;
556         isc_taskmgr_t *taskmgr = NULL;
557         isc_task_t *task = NULL;
558         isc_log_t *log = NULL;
559         isc_logconfig_t *logconfig = NULL;
560         isc_logdestination_t logdest;
561         cfg_parser_t *pctx = NULL;
562         cfg_obj_t *config = NULL;
563         const char *keyname = NULL;
564         char *p;
565         size_t argslen;
566         int ch;
567         int i;
568
569         result = isc_file_progname(*argv, program, sizeof(program));
570         if (result != ISC_R_SUCCESS)
571                 memcpy(program, "rndc", 5);
572         progname = program;
573
574         admin_conffile = RNDC_CONFFILE;
575         admin_keyfile = RNDC_KEYFILE;
576
577         isc_app_start();
578
579         while ((ch = isc_commandline_parse(argc, argv, "c:k:Mmp:s:Vy:"))
580                != -1) {
581                 switch (ch) {
582                 case 'c':
583                         admin_conffile = isc_commandline_argument;
584                         break;
585
586                 case 'k':
587                         admin_keyfile = isc_commandline_argument;
588                         break;
589
590                 case 'M':
591                         isc_mem_debugging = 1;
592                         break;
593
594                 case 'm':
595                         show_final_mem = ISC_TRUE;
596                         break;
597
598                 case 'p':
599                         remoteport = atoi(isc_commandline_argument);
600                         if (remoteport > 65535 || remoteport == 0)
601                                 fatal("port '%s' out of range",
602                                       isc_commandline_argument);
603                         break;
604
605                 case 's':
606                         servername = isc_commandline_argument;
607                         break;
608                 case 'V':
609                         verbose = ISC_TRUE;
610                         break;
611                 case 'y':
612                         keyname = isc_commandline_argument;
613                         break;
614                 case '?':
615                         usage(0);
616                         break;
617                 default:
618                         fatal("unexpected error parsing command arguments: "
619                               "got %c\n", ch);
620                         break;
621                 }
622         }
623
624         argc -= isc_commandline_index;
625         argv += isc_commandline_index;
626
627         if (argc < 1)
628                 usage(1);
629
630         isc_random_get(&serial);
631
632         DO("create memory context", isc_mem_create(0, 0, &mctx));
633         DO("create socket manager", isc_socketmgr_create(mctx, &socketmgr));
634         DO("create task manager", isc_taskmgr_create(mctx, 1, 0, &taskmgr));
635         DO("create task", isc_task_create(taskmgr, 0, &task));
636
637         DO("create logging context", isc_log_create(mctx, &log, &logconfig));
638         isc_log_setcontext(log);
639         DO("setting log tag", isc_log_settag(logconfig, progname));
640         logdest.file.stream = stderr;
641         logdest.file.name = NULL;
642         logdest.file.versions = ISC_LOG_ROLLNEVER;
643         logdest.file.maximum_size = 0;
644         DO("creating log channel",
645            isc_log_createchannel(logconfig, "stderr",
646                                  ISC_LOG_TOFILEDESC, ISC_LOG_INFO, &logdest,
647                                  ISC_LOG_PRINTTAG|ISC_LOG_PRINTLEVEL));
648         DO("enabling log channel", isc_log_usechannel(logconfig, "stderr",
649                                                       NULL, NULL));
650
651         parse_config(mctx, log, keyname, &pctx, &config);
652
653         isccc_result_register();
654
655         command = *argv;
656
657         /*
658          * Convert argc/argv into a space-delimited command string
659          * similar to what the user might enter in interactive mode
660          * (if that were implemented).
661          */
662         argslen = 0;
663         for (i = 0; i < argc; i++)
664                 argslen += strlen(argv[i]) + 1;
665
666         args = isc_mem_get(mctx, argslen);
667         if (args == NULL)
668                 DO("isc_mem_get", ISC_R_NOMEMORY);
669
670         p = args;
671         for (i = 0; i < argc; i++) {
672                 size_t len = strlen(argv[i]);
673                 memcpy(p, argv[i], len);
674                 p += len;
675                 *p++ = ' ';
676         }
677
678         p--;
679         *p++ = '\0';
680         INSIST(p == args + argslen);
681
682         notify("%s", command);
683
684         if (strcmp(command, "restart") == 0)
685                 fatal("'%s' is not implemented", command);
686
687         DO("post event", isc_app_onrun(mctx, task, rndc_start, NULL));
688
689         isc_app_run();
690
691         if (connects > 0 || sends > 0 || recvs > 0)
692                 isc_socket_cancel(sock, task, ISC_SOCKCANCEL_ALL);
693
694         isc_task_detach(&task);
695         isc_taskmgr_destroy(&taskmgr);
696         isc_socketmgr_destroy(&socketmgr);
697         isc_log_destroy(&log);
698         isc_log_setcontext(NULL);
699
700         cfg_obj_destroy(pctx, &config);
701         cfg_parser_destroy(&pctx);
702
703         isc_mem_put(mctx, args, argslen);
704         isccc_ccmsg_invalidate(&ccmsg);
705
706         if (show_final_mem)
707                 isc_mem_stats(mctx, stderr);
708
709         isc_mem_destroy(&mctx);
710
711         if (failed)
712                 return (1);
713
714         return (0);
715 }