text: /*
   * nsd-checkzone.c -- nsd-checkzone(8) checks zones for syntax errors
   *
   * Copyright (c) 2013, NLnet Labs. All rights reserved.
   *
   * See LICENSE for the license.
   *
   */
  
  #include "config.h"
  
  #include <assert.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <time.h>
  #include <unistd.h>
  #include <errno.h>
  
  #include "nsd.h"
  #include "options.h"
  #include "util.h"
  #include "zonec.h"
  #include "ixfr.h"
  #include "ixfrcreate.h"
  #include "difffile.h"
  
  struct nsd nsd;
  
  /*
   * Print the help text.
   *
   */
  static void
  usage (void)
  {
  	fprintf(stderr, "Usage: nsd-checkzone [-p] <zone name> <zone file>\n");
  	fprintf(stderr, "\t-p\tprint the zone if the zone is ok\n");
  	fprintf(stderr, "\t-i <old zone file>\tcreate an IXFR from the differences between the\n\t\told zone file and the new zone file. Writes to \n\t\t<zonefile>.ixfr and renames other <zonefile>.ixfr files to\n\t\t<zonefile>.ixfr.num+1.\n");
  	fprintf(stderr, "\t-n <ixfr number>\tnumber of IXFR versions to store, at most.\n\t\tdefault %d.\n", (int)IXFR_NUMBER_DEFAULT);
  	fprintf(stderr, "\t-s <ixfr size>\tsize of IXFR to store, at most. default %d.\n", (int)IXFR_SIZE_DEFAULT);
  	fprintf(stderr, "Version %s. Report bugs to <%s>.\n",
  		PACKAGE_VERSION, PACKAGE_BUGREPORT);
  }
  
  static void
  check_zone(struct nsd* nsd, const char* name, const char* fname, FILE *out,
  	const char* oldzone, uint32_t ixfr_number, uint64_t ixfr_size)
  {
  	const dname_type* dname;
  	zone_options_type* zo;
  	zone_type* zone;
  	unsigned errors;
  	struct ixfr_create* ixfrcr = NULL;
  
  	/* init*/
  	nsd->db = namedb_open("", nsd->options);
  	dname = dname_parse(nsd->options->region, name);
  	if(!dname) {
  		/* parse failure */
  		error("cannot parse zone name '%s'", name);
  	}
  	zo = zone_options_create(nsd->options->region);
  	memset(zo, 0, sizeof(*zo));
  	zo->node.key = dname;
  	zo->name = name;
  	zone = namedb_zone_create(nsd->db, dname, zo);
  
  	if(oldzone) {
  		errors = zonec_read(name, oldzone, zone);
  		if(errors > 0) {
  			printf("zone %s file %s has %u errors\n", name, oldzone, errors);
  			exit(1);
  		}
  		ixfrcr = ixfr_create_start(zone, fname, ixfr_size, 1);
  		if(!ixfrcr) {
  			error("out of memory");
  		}
  		delete_zone_rrs(nsd->db, zone);
  	}
  
  	/* read the zone */
  	errors = zonec_read(name, fname, zone);
  	if(errors > 0) {
  		printf("zone %s file %s has %u errors\n", name, fname, errors);
  		ixfr_create_cancel(ixfrcr);
  #ifdef MEMCLEAN /* otherwise, the OS collects memory pages */
  		namedb_close(nsd->db);
  		region_destroy(nsd->options->region);
  #endif
  		exit(1);
  	}
  	if(ixfrcr) {
  		if(!ixfr_create_perform(ixfrcr, zone, 0, nsd, fname,
  			ixfr_number)) {
  #ifdef MEMCLEAN /* otherwise, the OS collects memory pages */
  			namedb_close(nsd->db);
  			region_destroy(nsd->options->region);
  			ixfr_create_free(ixfrcr);
  #endif
  			error("could not create IXFR");
  		}
  		printf("zone %s created IXFR %s.ixfr\n", name, fname);
  		ixfr_create_free(ixfrcr);
  	}
  	if (out) {
  		print_rrs(out, zone);
  		printf("; ");
  	}
  	printf("zone %s is ok\n", name);
  	namedb_close(nsd->db);
  }
  
  /* dummy functions to link */
  int writepid(struct nsd * ATTR_UNUSED(nsd))
  {
  	        return 0;
  }
  void unlinkpid(const char * ATTR_UNUSED(file))
  {
  }
  void bind8_stats(struct nsd * ATTR_UNUSED(nsd))
  {
  }
  
  void sig_handler(int ATTR_UNUSED(sig))
  {
  }
  
  extern char *optarg;
  extern int optind;
  
  int
  main(int argc, char *argv[])
  {
  	/* Scratch variables... */
  	int c;
  	int print_zone = 0;
  	uint32_t ixfr_number = IXFR_NUMBER_DEFAULT;
  	uint64_t ixfr_size = IXFR_SIZE_DEFAULT;
  	char* oldzone = NULL;
  	struct nsd nsd;
  	memset(&nsd, 0, sizeof(nsd));
  
  	log_init("nsd-checkzone");
  
  	/* Parse the command line... */
  	while ((c = getopt(argc, argv, "hi:n:ps:")) != -1) {
  		switch (c) {
  		case 'h':
  			usage();
  			exit(0);
  		case 'i':
  			oldzone = optarg;
  			break;
  		case 'n':
  			ixfr_number = (uint32_t)atoi(optarg);
  			break;
  		case 'p':
  			print_zone = 1;
  			break;
  		case 's':
  			ixfr_size = (uint64_t)atoi(optarg);
  			break;
  		case '?':
  		default:
  			usage();
  			exit(1);
  		}
  	}
  	argc -= optind;
  	argv += optind;
  
  	/* Commandline parse error */
  	if (argc != 2) {
  		fprintf(stderr, "wrong number of arguments.\n");
  		usage();
  		exit(1);
  	}
  
  	nsd.options = nsd_options_create(region_create_custom(xalloc, free,
  		DEFAULT_CHUNK_SIZE, DEFAULT_LARGE_OBJECT_SIZE,
  		DEFAULT_INITIAL_CLEANUP_SIZE, 1));
  	if (verbosity == 0)
  		verbosity = nsd.options->verbosity;
  
  	check_zone(&nsd, argv[0], argv[1], print_zone ? stdout : NULL,
  		oldzone, ixfr_number, ixfr_size);
  	region_destroy(nsd.options->region);
  	/* yylex_destroy(); but, not available in all versions of flex */
  
  	exit(0);
  }
  