summaryrefslogtreecommitdiffstats
path: root/tests/libzscanner/zscanner-tool.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/libzscanner/zscanner-tool.c')
-rw-r--r--tests/libzscanner/zscanner-tool.c251
1 files changed, 251 insertions, 0 deletions
diff --git a/tests/libzscanner/zscanner-tool.c b/tests/libzscanner/zscanner-tool.c
new file mode 100644
index 0000000..06b795c
--- /dev/null
+++ b/tests/libzscanner/zscanner-tool.c
@@ -0,0 +1,251 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <getopt.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "libzscanner/processing.h"
+#include "libzscanner/scanner.h"
+
+#define DEFAULT_MODE 1
+#define DEFAULT_CLASS 1
+#define DEFAULT_TTL 0
+
+static void *timestamp_worker(void *data)
+{
+ int *ret = (int *)data;
+ *ret = test_date_to_timestamp();
+ return NULL;
+}
+
+static void help(void)
+{
+ printf("\nZone scanner testing tool.\n"
+ "Usage: zscanner-tool [parameters] origin zonefile\n"
+ "\n"
+ "Parameters:\n"
+ " -m [0,1,2] Processing mode.\n"
+ " 0 Empty output.\n"
+ " 1 Debug output (DEFAULT).\n"
+ " 2 Test output.\n"
+ " -s State parsing mode.\n"
+ " -t Launch unit tests.\n"
+ " -h Print this help.\n");
+}
+
+static int time_test(void)
+{
+ pthread_t t1, t2, t3;
+ int ret1, ret2, ret3;
+
+ pthread_create(&t1, NULL, timestamp_worker, &ret1);
+ pthread_create(&t2, NULL, timestamp_worker, &ret2);
+ pthread_create(&t3, NULL, timestamp_worker, &ret3);
+
+ pthread_join(t1, NULL);
+ pthread_join(t2, NULL);
+ pthread_join(t3, NULL);
+
+ if (ret1 != 0 || ret2 != 0 || ret3 != 0) {
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+static int include(zs_scanner_t *s);
+
+static int state_parsing(zs_scanner_t *s)
+{
+ while (zs_parse_record(s) == 0) {
+ switch (s->state) {
+ case ZS_STATE_DATA:
+ if (s->process.record != NULL) {
+ s->process.record(s);
+ }
+ break;
+ case ZS_STATE_ERROR:
+ if (s->process.error != NULL) {
+ s->process.error(s);
+ }
+ if (s->error.fatal) {
+ return -1;
+ }
+ break;
+ case ZS_STATE_INCLUDE:
+ if (include(s) != 0) {
+ return -1;
+ }
+ break;
+ default:
+ return (s->error.counter == 0) ? 0 : -1;
+ }
+ }
+
+ return -1;
+}
+
+static int include(zs_scanner_t *s)
+{
+ zs_scanner_t *ss;
+ int ret = 0;
+
+ if ((ss = malloc(sizeof(zs_scanner_t))) == NULL ||
+ zs_init(ss, (char *)s->buffer, s->default_class, s->default_ttl) != 0 ||
+ zs_set_input_file(ss, (char *)(s->include_filename)) != 0 ||
+ zs_set_processing(ss, s->process.record, s->process.error, s->process.data) != 0 ||
+ state_parsing(ss) != 0) {
+ if (ss == NULL) {
+ s->error.code = ZS_ENOMEM;
+ } else if (ss->error.counter > 0) {
+ s->error.counter += ss->error.counter;
+ s->error.code = ZS_UNPROCESSED_INCLUDE;
+ } else {
+ s->error.code = ss->error.code;
+ }
+
+ if (s->process.error != NULL) {
+ s->buffer[0] = '\0'; // Clear unrelated content.
+ s->buffer_length = 0;
+ s->error.counter++;
+ s->error.fatal = true;
+ s->process.error(s);
+ }
+
+ ret = -1;
+ }
+
+ zs_deinit(ss);
+ free(ss);
+
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ int mode = DEFAULT_MODE, state = 0, test = 0;
+
+ // Command line long options.
+ struct option opts[] = {
+ { "mode", required_argument, NULL, 'm' },
+ { "state", no_argument, NULL, 's' },
+ { "test", no_argument, NULL, 't' },
+ { "help", no_argument, NULL, 'h' },
+ { NULL }
+ };
+
+ // Parsed command line arguments.
+ int opt = 0, li = 0;
+ while ((opt = getopt_long(argc, argv, "m:sth", opts, &li)) != -1) {
+ switch (opt) {
+ case 'm':
+ mode = atoi(optarg);
+ break;
+ case 's':
+ state = 1;
+ break;
+ case 't':
+ test = 1;
+ break;
+ case 'h':
+ help();
+ return EXIT_SUCCESS;
+ default:
+ help();
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (test == 1) {
+ return time_test();
+ }
+
+ // Check if there are 2 remaining non-options.
+ if (argc - optind != 2) {
+ help();
+ return EXIT_FAILURE;
+ }
+
+ const char *origin = argv[optind];
+ const char *zone_file = argv[optind + 1];
+
+ // Create a zone scanner.
+ zs_scanner_t *s = malloc(sizeof(zs_scanner_t));
+ if (s == NULL) {
+ printf("Scanner create error!\n");
+ return EXIT_FAILURE;
+ }
+ if (zs_init(s, origin, DEFAULT_CLASS, DEFAULT_TTL) != 0) {
+ printf("Scanner init error!\n");
+ free(s);
+ return EXIT_FAILURE;
+ }
+ if (zs_set_input_file(s, zone_file) != 0) {
+ printf("Scanner file error!\n");
+ zs_deinit(s);
+ free(s);
+ return EXIT_FAILURE;
+ }
+
+ // Set the processing mode.
+ int ret;
+ switch (mode) {
+ case 0:
+ ret = 0;
+ break;
+ case 1:
+ ret = zs_set_processing(s, debug_process_record, debug_process_error, NULL);
+ break;
+ case 2:
+ ret = zs_set_processing(s, test_process_record, test_process_error, NULL);
+ break;
+ default:
+ printf("Bad mode number!\n");
+ help();
+ return EXIT_FAILURE;
+ }
+ if (ret != 0) {
+ printf("Processing setup error!\n");
+ return EXIT_FAILURE;
+ }
+
+ // Parse the file.
+ ret = state ? state_parsing(s) : zs_parse_all(s);
+ if (ret == 0) {
+ if (mode == DEFAULT_MODE) {
+ printf("Zone file has been processed successfully\n");
+ }
+
+ zs_deinit(s);
+ free(s);
+ return EXIT_SUCCESS;
+ } else {
+ if (s->error.counter > 0 && mode == DEFAULT_MODE) {
+ printf("Zone processing has stopped with "
+ "%"PRIu64" warnings/errors!\n",
+ s->error.counter);
+ } else if (mode == DEFAULT_MODE) {
+ printf("%s\n", zs_strerror(s->error.code));
+ }
+
+ zs_deinit(s);
+ free(s);
+ return EXIT_FAILURE;
+ }
+}