No empty .Rs/.Re
[netbsd-mini2440.git] / external / bsd / bind / dist / bin / check / check-tool.c
blobb164cca47704741549abc110aca104ccfdf6c01e
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000-2002 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: check-tool.c,v 1.39 2009/09/01 00:22:24 jinmei Exp */
22 /*! \file */
24 #include <config.h>
26 #include <stdio.h>
28 #include "check-tool.h"
29 #include <isc/buffer.h>
30 #include <isc/log.h>
31 #include <isc/mem.h>
32 #include <isc/netdb.h>
33 #include <isc/net.h>
34 #include <isc/region.h>
35 #include <isc/stdio.h>
36 #include <isc/string.h>
37 #include <isc/symtab.h>
38 #include <isc/types.h>
39 #include <isc/util.h>
41 #include <dns/fixedname.h>
42 #include <dns/log.h>
43 #include <dns/name.h>
44 #include <dns/rdata.h>
45 #include <dns/rdataclass.h>
46 #include <dns/rdataset.h>
47 #include <dns/types.h>
48 #include <dns/zone.h>
50 #include <isccfg/log.h>
52 #ifndef CHECK_SIBLING
53 #define CHECK_SIBLING 1
54 #endif
56 #ifndef CHECK_LOCAL
57 #define CHECK_LOCAL 1
58 #endif
60 #ifdef HAVE_ADDRINFO
61 #ifdef HAVE_GETADDRINFO
62 #ifdef HAVE_GAISTRERROR
63 #define USE_GETADDRINFO
64 #endif
65 #endif
66 #endif
68 #define CHECK(r) \
69 do { \
70 result = (r); \
71 if (result != ISC_R_SUCCESS) \
72 goto cleanup; \
73 } while (0)
75 #define ERR_IS_CNAME 1
76 #define ERR_NO_ADDRESSES 2
77 #define ERR_LOOKUP_FAILURE 3
78 #define ERR_EXTRA_A 4
79 #define ERR_EXTRA_AAAA 5
80 #define ERR_MISSING_GLUE 5
81 #define ERR_IS_MXCNAME 6
82 #define ERR_IS_SRVCNAME 7
84 static const char *dbtype[] = { "rbt" };
86 int debug = 0;
87 isc_boolean_t nomerge = ISC_TRUE;
88 #if CHECK_LOCAL
89 isc_boolean_t docheckmx = ISC_TRUE;
90 isc_boolean_t dochecksrv = ISC_TRUE;
91 isc_boolean_t docheckns = ISC_TRUE;
92 #else
93 isc_boolean_t docheckmx = ISC_FALSE;
94 isc_boolean_t dochecksrv = ISC_FALSE;
95 isc_boolean_t docheckns = ISC_FALSE;
96 #endif
97 unsigned int zone_options = DNS_ZONEOPT_CHECKNS |
98 DNS_ZONEOPT_CHECKMX |
99 DNS_ZONEOPT_MANYERRORS |
100 DNS_ZONEOPT_CHECKNAMES |
101 DNS_ZONEOPT_CHECKINTEGRITY |
102 #if CHECK_SIBLING
103 DNS_ZONEOPT_CHECKSIBLING |
104 #endif
105 DNS_ZONEOPT_CHECKWILDCARD |
106 DNS_ZONEOPT_WARNMXCNAME |
107 DNS_ZONEOPT_WARNSRVCNAME;
110 * This needs to match the list in bin/named/log.c.
112 static isc_logcategory_t categories[] = {
113 { "", 0 },
114 { "client", 0 },
115 { "network", 0 },
116 { "update", 0 },
117 { "queries", 0 },
118 { "unmatched", 0 },
119 { "update-security", 0 },
120 { "query-errors", 0 },
121 { NULL, 0 }
124 static isc_symtab_t *symtab = NULL;
125 static isc_mem_t *sym_mctx;
127 static void
128 freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
129 UNUSED(type);
130 UNUSED(value);
131 isc_mem_free(userarg, key);
134 static void
135 add(char *key, int value) {
136 isc_result_t result;
137 isc_symvalue_t symvalue;
139 if (sym_mctx == NULL) {
140 result = isc_mem_create(0, 0, &sym_mctx);
141 if (result != ISC_R_SUCCESS)
142 return;
145 if (symtab == NULL) {
146 result = isc_symtab_create(sym_mctx, 100, freekey, sym_mctx,
147 ISC_FALSE, &symtab);
148 if (result != ISC_R_SUCCESS)
149 return;
152 key = isc_mem_strdup(sym_mctx, key);
153 if (key == NULL)
154 return;
156 symvalue.as_pointer = NULL;
157 result = isc_symtab_define(symtab, key, value, symvalue,
158 isc_symexists_reject);
159 if (result != ISC_R_SUCCESS)
160 isc_mem_free(sym_mctx, key);
163 static isc_boolean_t
164 logged(char *key, int value) {
165 isc_result_t result;
167 if (symtab == NULL)
168 return (ISC_FALSE);
170 result = isc_symtab_lookup(symtab, key, value, NULL);
171 if (result == ISC_R_SUCCESS)
172 return (ISC_TRUE);
173 return (ISC_FALSE);
176 static isc_boolean_t
177 checkns(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner,
178 dns_rdataset_t *a, dns_rdataset_t *aaaa)
180 #ifdef USE_GETADDRINFO
181 dns_rdataset_t *rdataset;
182 dns_rdata_t rdata = DNS_RDATA_INIT;
183 struct addrinfo hints, *ai, *cur;
184 char namebuf[DNS_NAME_FORMATSIZE + 1];
185 char ownerbuf[DNS_NAME_FORMATSIZE];
186 char addrbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123")];
187 isc_boolean_t answer = ISC_TRUE;
188 isc_boolean_t match;
189 const char *type;
190 void *ptr = NULL;
191 int result;
193 REQUIRE(a == NULL || !dns_rdataset_isassociated(a) ||
194 a->type == dns_rdatatype_a);
195 REQUIRE(aaaa == NULL || !dns_rdataset_isassociated(aaaa) ||
196 aaaa->type == dns_rdatatype_aaaa);
197 memset(&hints, 0, sizeof(hints));
198 hints.ai_flags = AI_CANONNAME;
199 hints.ai_family = PF_UNSPEC;
200 hints.ai_socktype = SOCK_STREAM;
201 hints.ai_protocol = IPPROTO_TCP;
203 dns_name_format(name, namebuf, sizeof(namebuf) - 1);
205 * Turn off search.
207 if (dns_name_countlabels(name) > 1U)
208 strcat(namebuf, ".");
209 dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
211 result = getaddrinfo(namebuf, NULL, &hints, &ai);
212 dns_name_format(name, namebuf, sizeof(namebuf) - 1);
213 switch (result) {
214 case 0:
216 * Work around broken getaddrinfo() implementations that
217 * fail to set ai_canonname on first entry.
219 cur = ai;
220 while (cur != NULL && cur->ai_canonname == NULL &&
221 cur->ai_next != NULL)
222 cur = cur->ai_next;
223 if (cur != NULL && cur->ai_canonname != NULL &&
224 strcasecmp(cur->ai_canonname, namebuf) != 0 &&
225 !logged(namebuf, ERR_IS_CNAME)) {
226 dns_zone_log(zone, ISC_LOG_ERROR,
227 "%s/NS '%s' (out of zone) "
228 "is a CNAME '%s' (illegal)",
229 ownerbuf, namebuf,
230 cur->ai_canonname);
231 /* XXX950 make fatal for 9.5.0 */
232 /* answer = ISC_FALSE; */
233 add(namebuf, ERR_IS_CNAME);
235 break;
236 case EAI_NONAME:
237 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
238 case EAI_NODATA:
239 #endif
240 if (!logged(namebuf, ERR_NO_ADDRESSES)) {
241 dns_zone_log(zone, ISC_LOG_ERROR,
242 "%s/NS '%s' (out of zone) "
243 "has no addresses records (A or AAAA)",
244 ownerbuf, namebuf);
245 add(namebuf, ERR_NO_ADDRESSES);
247 /* XXX950 make fatal for 9.5.0 */
248 return (ISC_TRUE);
250 default:
251 if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
252 dns_zone_log(zone, ISC_LOG_WARNING,
253 "getaddrinfo(%s) failed: %s",
254 namebuf, gai_strerror(result));
255 add(namebuf, ERR_LOOKUP_FAILURE);
257 return (ISC_TRUE);
259 if (a == NULL || aaaa == NULL)
260 return (answer);
262 * Check that all glue records really exist.
264 if (!dns_rdataset_isassociated(a))
265 goto checkaaaa;
266 result = dns_rdataset_first(a);
267 while (result == ISC_R_SUCCESS) {
268 dns_rdataset_current(a, &rdata);
269 match = ISC_FALSE;
270 for (cur = ai; cur != NULL; cur = cur->ai_next) {
271 if (cur->ai_family != AF_INET)
272 continue;
273 ptr = &((struct sockaddr_in *)(cur->ai_addr))->sin_addr;
274 if (memcmp(ptr, rdata.data, rdata.length) == 0) {
275 match = ISC_TRUE;
276 break;
279 if (!match && !logged(namebuf, ERR_EXTRA_A)) {
280 dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' "
281 "extra GLUE A record (%s)",
282 ownerbuf, namebuf,
283 inet_ntop(AF_INET, rdata.data,
284 addrbuf, sizeof(addrbuf)));
285 add(namebuf, ERR_EXTRA_A);
286 /* XXX950 make fatal for 9.5.0 */
287 /* answer = ISC_FALSE; */
289 dns_rdata_reset(&rdata);
290 result = dns_rdataset_next(a);
293 checkaaaa:
294 if (!dns_rdataset_isassociated(aaaa))
295 goto checkmissing;
296 result = dns_rdataset_first(aaaa);
297 while (result == ISC_R_SUCCESS) {
298 dns_rdataset_current(aaaa, &rdata);
299 match = ISC_FALSE;
300 for (cur = ai; cur != NULL; cur = cur->ai_next) {
301 if (cur->ai_family != AF_INET6)
302 continue;
303 ptr = &((struct sockaddr_in6 *)(cur->ai_addr))->sin6_addr;
304 if (memcmp(ptr, rdata.data, rdata.length) == 0) {
305 match = ISC_TRUE;
306 break;
309 if (!match && !logged(namebuf, ERR_EXTRA_AAAA)) {
310 dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' "
311 "extra GLUE AAAA record (%s)",
312 ownerbuf, namebuf,
313 inet_ntop(AF_INET6, rdata.data,
314 addrbuf, sizeof(addrbuf)));
315 add(namebuf, ERR_EXTRA_AAAA);
316 /* XXX950 make fatal for 9.5.0. */
317 /* answer = ISC_FALSE; */
319 dns_rdata_reset(&rdata);
320 result = dns_rdataset_next(aaaa);
323 checkmissing:
325 * Check that all addresses appear in the glue.
327 if (!logged(namebuf, ERR_MISSING_GLUE)) {
328 isc_boolean_t missing_glue = ISC_FALSE;
329 for (cur = ai; cur != NULL; cur = cur->ai_next) {
330 switch (cur->ai_family) {
331 case AF_INET:
332 rdataset = a;
333 ptr = &((struct sockaddr_in *)(cur->ai_addr))->sin_addr;
334 type = "A";
335 break;
336 case AF_INET6:
337 rdataset = aaaa;
338 ptr = &((struct sockaddr_in6 *)(cur->ai_addr))->sin6_addr;
339 type = "AAAA";
340 break;
341 default:
342 continue;
344 match = ISC_FALSE;
345 if (dns_rdataset_isassociated(rdataset))
346 result = dns_rdataset_first(rdataset);
347 else
348 result = ISC_R_FAILURE;
349 while (result == ISC_R_SUCCESS && !match) {
350 dns_rdataset_current(rdataset, &rdata);
351 if (memcmp(ptr, rdata.data, rdata.length) == 0)
352 match = ISC_TRUE;
353 dns_rdata_reset(&rdata);
354 result = dns_rdataset_next(rdataset);
356 if (!match) {
357 dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' "
358 "missing GLUE %s record (%s)",
359 ownerbuf, namebuf, type,
360 inet_ntop(cur->ai_family, ptr,
361 addrbuf, sizeof(addrbuf)));
362 /* XXX950 make fatal for 9.5.0. */
363 /* answer = ISC_FALSE; */
364 missing_glue = ISC_TRUE;
367 if (missing_glue)
368 add(namebuf, ERR_MISSING_GLUE);
370 freeaddrinfo(ai);
371 return (answer);
372 #else
373 return (ISC_TRUE);
374 #endif
377 static isc_boolean_t
378 checkmx(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner) {
379 #ifdef USE_GETADDRINFO
380 struct addrinfo hints, *ai, *cur;
381 char namebuf[DNS_NAME_FORMATSIZE + 1];
382 char ownerbuf[DNS_NAME_FORMATSIZE];
383 int result;
384 int level = ISC_LOG_ERROR;
385 isc_boolean_t answer = ISC_TRUE;
387 memset(&hints, 0, sizeof(hints));
388 hints.ai_flags = AI_CANONNAME;
389 hints.ai_family = PF_UNSPEC;
390 hints.ai_socktype = SOCK_STREAM;
391 hints.ai_protocol = IPPROTO_TCP;
393 dns_name_format(name, namebuf, sizeof(namebuf) - 1);
395 * Turn off search.
397 if (dns_name_countlabels(name) > 1U)
398 strcat(namebuf, ".");
399 dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
401 result = getaddrinfo(namebuf, NULL, &hints, &ai);
402 dns_name_format(name, namebuf, sizeof(namebuf) - 1);
403 switch (result) {
404 case 0:
406 * Work around broken getaddrinfo() implementations that
407 * fail to set ai_canonname on first entry.
409 cur = ai;
410 while (cur != NULL && cur->ai_canonname == NULL &&
411 cur->ai_next != NULL)
412 cur = cur->ai_next;
413 if (cur != NULL && cur->ai_canonname != NULL &&
414 strcasecmp(cur->ai_canonname, namebuf) != 0) {
415 if ((zone_options & DNS_ZONEOPT_WARNMXCNAME) != 0)
416 level = ISC_LOG_WARNING;
417 if ((zone_options & DNS_ZONEOPT_IGNOREMXCNAME) == 0) {
418 if (!logged(namebuf, ERR_IS_MXCNAME)) {
419 dns_zone_log(zone, level,
420 "%s/MX '%s' (out of zone)"
421 " is a CNAME '%s' "
422 "(illegal)",
423 ownerbuf, namebuf,
424 cur->ai_canonname);
425 add(namebuf, ERR_IS_MXCNAME);
427 if (level == ISC_LOG_ERROR)
428 answer = ISC_FALSE;
431 freeaddrinfo(ai);
432 return (answer);
434 case EAI_NONAME:
435 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
436 case EAI_NODATA:
437 #endif
438 if (!logged(namebuf, ERR_NO_ADDRESSES)) {
439 dns_zone_log(zone, ISC_LOG_ERROR,
440 "%s/MX '%s' (out of zone) "
441 "has no addresses records (A or AAAA)",
442 ownerbuf, namebuf);
443 add(namebuf, ERR_NO_ADDRESSES);
445 /* XXX950 make fatal for 9.5.0. */
446 return (ISC_TRUE);
448 default:
449 if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
450 dns_zone_log(zone, ISC_LOG_WARNING,
451 "getaddrinfo(%s) failed: %s",
452 namebuf, gai_strerror(result));
453 add(namebuf, ERR_LOOKUP_FAILURE);
455 return (ISC_TRUE);
457 #else
458 return (ISC_TRUE);
459 #endif
462 static isc_boolean_t
463 checksrv(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner) {
464 #ifdef USE_GETADDRINFO
465 struct addrinfo hints, *ai, *cur;
466 char namebuf[DNS_NAME_FORMATSIZE + 1];
467 char ownerbuf[DNS_NAME_FORMATSIZE];
468 int result;
469 int level = ISC_LOG_ERROR;
470 isc_boolean_t answer = ISC_TRUE;
472 memset(&hints, 0, sizeof(hints));
473 hints.ai_flags = AI_CANONNAME;
474 hints.ai_family = PF_UNSPEC;
475 hints.ai_socktype = SOCK_STREAM;
476 hints.ai_protocol = IPPROTO_TCP;
478 dns_name_format(name, namebuf, sizeof(namebuf) - 1);
480 * Turn off search.
482 if (dns_name_countlabels(name) > 1U)
483 strcat(namebuf, ".");
484 dns_name_format(owner, ownerbuf, sizeof(ownerbuf));
486 result = getaddrinfo(namebuf, NULL, &hints, &ai);
487 dns_name_format(name, namebuf, sizeof(namebuf) - 1);
488 switch (result) {
489 case 0:
491 * Work around broken getaddrinfo() implementations that
492 * fail to set ai_canonname on first entry.
494 cur = ai;
495 while (cur != NULL && cur->ai_canonname == NULL &&
496 cur->ai_next != NULL)
497 cur = cur->ai_next;
498 if (cur != NULL && cur->ai_canonname != NULL &&
499 strcasecmp(cur->ai_canonname, namebuf) != 0) {
500 if ((zone_options & DNS_ZONEOPT_WARNSRVCNAME) != 0)
501 level = ISC_LOG_WARNING;
502 if ((zone_options & DNS_ZONEOPT_IGNORESRVCNAME) == 0) {
503 if (!logged(namebuf, ERR_IS_SRVCNAME)) {
504 dns_zone_log(zone, level, "%s/SRV '%s'"
505 " (out of zone) is a "
506 "CNAME '%s' (illegal)",
507 ownerbuf, namebuf,
508 cur->ai_canonname);
509 add(namebuf, ERR_IS_SRVCNAME);
511 if (level == ISC_LOG_ERROR)
512 answer = ISC_FALSE;
515 freeaddrinfo(ai);
516 return (answer);
518 case EAI_NONAME:
519 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
520 case EAI_NODATA:
521 #endif
522 if (!logged(namebuf, ERR_NO_ADDRESSES)) {
523 dns_zone_log(zone, ISC_LOG_ERROR,
524 "%s/SRV '%s' (out of zone) "
525 "has no addresses records (A or AAAA)",
526 ownerbuf, namebuf);
527 add(namebuf, ERR_NO_ADDRESSES);
529 /* XXX950 make fatal for 9.5.0. */
530 return (ISC_TRUE);
532 default:
533 if (!logged(namebuf, ERR_LOOKUP_FAILURE)) {
534 dns_zone_log(zone, ISC_LOG_WARNING,
535 "getaddrinfo(%s) failed: %s",
536 namebuf, gai_strerror(result));
537 add(namebuf, ERR_LOOKUP_FAILURE);
539 return (ISC_TRUE);
541 #else
542 return (ISC_TRUE);
543 #endif
546 isc_result_t
547 setup_logging(isc_mem_t *mctx, FILE *errout, isc_log_t **logp) {
548 isc_logdestination_t destination;
549 isc_logconfig_t *logconfig = NULL;
550 isc_log_t *log = NULL;
552 RUNTIME_CHECK(isc_log_create(mctx, &log, &logconfig) == ISC_R_SUCCESS);
553 isc_log_registercategories(log, categories);
554 isc_log_setcontext(log);
555 dns_log_init(log);
556 dns_log_setcontext(log);
557 cfg_log_init(log);
559 destination.file.stream = errout;
560 destination.file.name = NULL;
561 destination.file.versions = ISC_LOG_ROLLNEVER;
562 destination.file.maximum_size = 0;
563 RUNTIME_CHECK(isc_log_createchannel(logconfig, "stderr",
564 ISC_LOG_TOFILEDESC,
565 ISC_LOG_DYNAMIC,
566 &destination, 0) == ISC_R_SUCCESS);
567 RUNTIME_CHECK(isc_log_usechannel(logconfig, "stderr",
568 NULL, NULL) == ISC_R_SUCCESS);
570 *logp = log;
571 return (ISC_R_SUCCESS);
574 /*% load the zone */
575 isc_result_t
576 load_zone(isc_mem_t *mctx, const char *zonename, const char *filename,
577 dns_masterformat_t fileformat, const char *classname,
578 dns_zone_t **zonep)
580 isc_result_t result;
581 dns_rdataclass_t rdclass;
582 isc_textregion_t region;
583 isc_buffer_t buffer;
584 dns_fixedname_t fixorigin;
585 dns_name_t *origin;
586 dns_zone_t *zone = NULL;
588 REQUIRE(zonep == NULL || *zonep == NULL);
590 if (debug)
591 fprintf(stderr, "loading \"%s\" from \"%s\" class \"%s\"\n",
592 zonename, filename, classname);
594 CHECK(dns_zone_create(&zone, mctx));
596 dns_zone_settype(zone, dns_zone_master);
598 isc_buffer_init(&buffer, zonename, strlen(zonename));
599 isc_buffer_add(&buffer, strlen(zonename));
600 dns_fixedname_init(&fixorigin);
601 origin = dns_fixedname_name(&fixorigin);
602 CHECK(dns_name_fromtext(origin, &buffer, dns_rootname, 0, NULL));
603 CHECK(dns_zone_setorigin(zone, origin));
604 CHECK(dns_zone_setdbtype(zone, 1, (const char * const *) dbtype));
605 CHECK(dns_zone_setfile2(zone, filename, fileformat));
607 DE_CONST(classname, region.base);
608 region.length = strlen(classname);
609 CHECK(dns_rdataclass_fromtext(&rdclass, &region));
611 dns_zone_setclass(zone, rdclass);
612 dns_zone_setoption(zone, zone_options, ISC_TRUE);
613 dns_zone_setoption(zone, DNS_ZONEOPT_NOMERGE, nomerge);
614 if (docheckmx)
615 dns_zone_setcheckmx(zone, checkmx);
616 if (docheckns)
617 dns_zone_setcheckns(zone, checkns);
618 if (dochecksrv)
619 dns_zone_setchecksrv(zone, checksrv);
621 CHECK(dns_zone_load(zone));
622 if (zonep != NULL) {
623 *zonep = zone;
624 zone = NULL;
627 cleanup:
628 if (zone != NULL)
629 dns_zone_detach(&zone);
630 return (result);
633 /*% dump the zone */
634 isc_result_t
635 dump_zone(const char *zonename, dns_zone_t *zone, const char *filename,
636 dns_masterformat_t fileformat, const dns_master_style_t *style)
638 isc_result_t result;
639 FILE *output = stdout;
641 if (debug) {
642 if (filename != NULL && strcmp(filename, "-") != 0)
643 fprintf(stderr, "dumping \"%s\" to \"%s\"\n",
644 zonename, filename);
645 else
646 fprintf(stderr, "dumping \"%s\"\n", zonename);
649 if (filename != NULL && strcmp(filename, "-") != 0) {
650 result = isc_stdio_open(filename, "w+", &output);
652 if (result != ISC_R_SUCCESS) {
653 fprintf(stderr, "could not open output "
654 "file \"%s\" for writing\n", filename);
655 return (ISC_R_FAILURE);
659 result = dns_zone_dumptostream2(zone, output, fileformat, style);
661 if (output != stdout)
662 (void)isc_stdio_close(output);
664 return (result);