1 /*------------------------------------------------------------------------------
2  *
3  * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4  * The YADIFA TM software product is provided under the BSD 3-clause license:
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  *        * Redistributions of source code must retain the above copyright
11  *          notice, this list of conditions and the following disclaimer.
12  *        * Redistributions in binary form must reproduce the above copyright
13  *          notice, this list of conditions and the following disclaimer in the
14  *          documentation and/or other materials provided with the distribution.
15  *        * Neither the name of EURid nor the names of its contributors may be
16  *          used to endorse or promote products derived from this software
17  *          without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  *------------------------------------------------------------------------------
32  *
33  */
34 
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <fcntl.h>
40 
41 #include <dnscore/fdtools.h>
42 #include <dnscore/dns_resource_record.h>
43 #include <dnscore/file_input_stream.h>
44 #include <dnscore/file_output_stream.h>
45 #include <dnscore/buffer_input_stream.h>
46 #include <dnscore/buffer_output_stream.h>
47 
48 #define JOURNAL_CJF_BASE 1
49 
50 #include <dnsdb/zdb.h>
51 #include <dnsdb/zdb_utils.h>
52 #include <dnsdb/journal-cjf-common.h>
53 #include <dnsdb/journal-cjf-page-cache.h>
54 #include <dnsdb/journal-jnl.h>
55 #include <dnsdb/rrsig.h>
56 #include <dnscore/logger_channel_stream.h>
57 
58 #define MODE_JNL 0
59 #define MODE_CJF 1
60 #define MODE_AXFR 2
61 
62 static bool g_dump = FALSE;
63 static bool g_generate_update_files = FALSE;
64 static bool g_clean_mode = FALSE;
65 static int g_mode = MODE_JNL;
66 
67 static const char *default_channel = "stdout default";
68 
69 struct logger_name_handle_s
70 {
71     const char *name;
72     logger_handle **handlep;
73 };
74 
75 static const struct logger_name_handle_s logger_name_handles[] =
76     {
77         {"system", &g_system_logger},
78         {"database", &g_database_logger},
79         {NULL, NULL}
80     };
81 
82 static void
config_logger_setdefault()83 config_logger_setdefault()
84 {
85     logger_start();
86 
87     output_stream stdout_os;
88     logger_channel *stdout_channel;
89 
90     fd_output_stream_attach(&stdout_os, dup_ex(1));
91     stdout_channel = logger_channel_alloc();
92     logger_channel_stream_open(&stdout_os, FALSE, stdout_channel);
93     logger_channel_register(default_channel, stdout_channel);
94 
95     for(const struct logger_name_handle_s *name_handle = logger_name_handles; name_handle->name != NULL; name_handle++)
96     {
97         logger_handle_create(name_handle->name, name_handle->handlep);
98 #if !DEBUG
99         logger_handle_add_channel(name_handle->name, MSG_PROD_MASK, default_channel);
100 #else
101         logger_handle_add_channel(name_handle->name, MSG_ALL_MASK, default_channel);
102 #endif
103     }
104 
105 #if DEBUG
106     log_debug("logging to stdout");
107 #endif
108 }
109 
cjf_read_page_hdr(int fd,off_t ofs,journal_cjf_page_tbl_header * page)110 static int cjf_read_page_hdr(int fd, off_t ofs, journal_cjf_page_tbl_header *page)
111 {
112     off_t pos = lseek(fd, ofs, SEEK_SET);
113     if(pos != ofs)
114     {
115         return -1;
116     }
117 
118     ssize_t n = readfully(fd, page, JOURNAL_CJF_PAGE_HEADER_SIZE);
119     if(n != JOURNAL_CJF_PAGE_HEADER_SIZE)
120     {
121         return -2;
122     }
123 
124     return 1;
125 }
126 
127 struct journal_cjf_page
128 {
129     journal_cjf_page_tbl_header hdr;
130     journal_cjf_page_tbl_item item[0x200];
131     u32 pos;
132     u32 end;
133     u32 serial_from;
134     u32 serial_to;
135 };
136 typedef struct journal_cjf_page journal_cjf_page;
137 
cjf_scan_page(int fd,u32 ofs)138 static int cjf_scan_page(int fd, u32 ofs)
139 {
140     static const u8 PAGE_MAGIC_ARRAY[4] = {'P', 'A', 'G', 'E'};
141     u8 tmp[512];
142 
143     off_t pos = lseek(fd, ofs, SEEK_SET);
144 
145     if(pos != ofs)
146     {
147         formatln("; could not seek position %u: %r", ofs, ERRNO_ERROR);
148         return -1;
149     }
150 
151     int o = 0;
152 
153     for(;;)
154     {
155         int n = read(fd, tmp, sizeof(tmp));
156         if(n < 0)
157         {
158             if(errno != EINTR)
159             {
160                 return -1;
161             }
162 
163             continue;
164         }
165         if(n == 0)
166         {
167             return -2;
168         }
169 
170         for(int i = 0; i < n; ++i)
171         {
172             char c  = (char)tmp[i];
173             if(c != PAGE_MAGIC_ARRAY[o])
174             {
175                 o = 0;
176             }
177             else
178             {
179                 ++o;
180                 if(o == 4)
181                 {
182                     return pos + i - 3;
183                 }
184             }
185         }
186 
187         pos += n;
188     }
189 }
190 
cjf_read_page(int fd,u32 ofs,journal_cjf_page ** out_page)191 static int cjf_read_page(int fd, u32 ofs, journal_cjf_page **out_page)
192 {
193     journal_cjf_page_tbl_header hdr;
194 
195     if(cjf_read_page_hdr(fd, ofs, &hdr) > 0)
196     {
197         if(hdr.magic == CJF_PAGE_MAGIC)
198         {
199             formatln("; page @%u=%x", ofs, ofs);
200             formatln(";   next: @%u=%x,", hdr.next_page_offset, hdr.next_page_offset);
201             formatln(";   end : @%u=%x", hdr.stream_end_offset, hdr.stream_end_offset);
202             formatln(";   item: %u/%u", hdr.count, hdr.size);
203 
204             if(hdr.size > 0x200)
205             {
206                 formatln("; page size is most likely wrong");
207                 return -3;
208             }
209 
210             if(hdr.count > hdr.size)
211             {
212                 formatln("; item count is most likely wrong");
213                 return -4;
214             }
215 
216             journal_cjf_page *page;
217             MALLOC_OR_DIE(journal_cjf_page*, page, sizeof(journal_cjf_page), GENERIC_TAG);
218             page->hdr = hdr;
219             page->pos = ofs;
220             ssize_t item_size = CJF_SECTION_INDEX_SLOT_SIZE * hdr.size;
221             ssize_t n = readfully(fd, &page->item, item_size);
222             if(n != item_size)
223             {
224                 free(page);
225                 formatln("; could not read page: expected %lli but got %lli", item_size, n);
226                 return -5;
227             }
228 
229             u32 e = lseek(fd, 0, SEEK_CUR);
230             u32 l = hdr.stream_end_offset;
231 
232             if((hdr.count > 0) && (page->item[0].stream_file_offset != e))
233             {
234                 formatln("; page @%u=%x: item[%3i] starts at %u=%x when %u=%x was expected", ofs, ofs, 0, page->item[0].stream_file_offset, page->item[0].stream_file_offset, e, e);
235             }
236 
237             for(u16 i = 0; i < hdr.count; ++i)
238             {
239                 u32 o = page->item[i].stream_file_offset;
240                 /*
241                 if(o >= e)
242                 {
243                     formatln("page @%u=%x: item[%3i] starts at %u=%x when %u=%x was expected", ofs, ofs, i, o, o, e, e);
244                 }
245                 */
246                 if(o > l)
247                 {
248                     formatln("; page @%u=%x: item[%3i] ends at %u=%x after %u=%x limit", ofs, ofs, i, o, o, l, l);
249                 }
250             }
251 
252             for(u16 i = 1; i < hdr.count; ++i)
253             {
254                 if(serial_ge(page->item[i - 1].ends_with_serial, page->item[i].ends_with_serial))
255                 {
256                     formatln("; page @%u=%x: item[%3i] serial = %u <= %u", ofs, ofs, i, page->item[i].ends_with_serial, page->item[i - 1].ends_with_serial);
257                 }
258             }
259 
260             *out_page = page;
261 
262             return 1; // page makes sense
263         }
264         else
265         {
266             formatln("; page @%u=%x has wrong magic", ofs, ofs);
267             return -4;
268         }
269     }
270 
271     return -5;
272 }
273 
cjf_read_page_records(int fd,journal_cjf_page * page)274 static int cjf_read_page_records(int fd, journal_cjf_page *page)
275 {
276     off_t exp = page->pos + JOURNAL_CJF_PAGE_HEADER_SIZE + CJF_SECTION_INDEX_SLOT_SIZE * page->hdr.size;
277     off_t pos = lseek(fd, exp, SEEK_SET);
278 
279     if(pos != exp)
280     {
281         return -1;
282     }
283 
284     // read all records and match them to the page data
285 
286     input_stream fis;
287     input_stream bis;
288     ya_result ret;
289 
290     fd_input_stream_attach(&fis, fd);
291     buffer_input_stream_init(&bis, &fis, 4096);
292     dns_resource_record rr;
293     dns_resource_record_init(&rr);
294 
295     int soa_count = 0;
296     int line_count = -1;
297     u32 serial;
298     u32 serial_from = 0;
299     u32 serial_to = 0;
300     ya_result return_value = ERROR;
301 
302     for(;;)
303     {
304         if((ret = dns_resource_record_read(&rr, &bis)) <= 0)
305         {
306             // no more record (error or end of stream)
307             if(g_dump)
308             {
309                 formatln("$");
310             }
311             break;
312         }
313 
314         if(soa_count == 0)
315         {
316             if(rr.tctr.qtype != TYPE_SOA)
317             {
318                 formatln("; page @%u=%x record stream does not start by an SOA (%{dnsrr})", page->pos, page->pos, &rr);
319                 break;
320             }
321         }
322 
323         if(line_count >= page->hdr.count)
324         {
325             formatln("; page @%u=%x line %i @%u=%x successfully scanned a record %{dnsrr} outside of line bounds", page->pos, page->pos, line_count, pos, pos, &rr);
326         }
327 
328         if(rr.tctr.qtype == TYPE_SOA)
329         {
330             ya_result err = rr_soa_get_serial(rr.rdata, rr.rdata_size, &serial);
331             if(FAIL(err))
332             {
333                 formatln("; page @%u=%x line %i @%u=%x could not get serial from first SOA: %r", page->pos, page->pos, line_count, pos, pos, err);
334                 break;
335             }
336 
337             ++soa_count;
338 
339             if((soa_count & 1) != 0)
340             {
341                 ++line_count;
342 
343                 if(line_count < page->hdr.count)
344                 {
345                     // odd
346                     u32 e = page->item[line_count].stream_file_offset;
347 
348                     if(e != pos)
349                     {
350                         formatln("; page @%u=%x line %i @%u=%x does not start at the expected position %u=%x", page->pos, page->pos, line_count, pos, pos, e, e);
351                     }
352 
353                     serial_from = serial;
354 
355                     if(line_count > 0)
356                     {
357                         if(serial_from != serial_to)
358                         {
359                             formatln("; page @%u=%x line %i @%u=%x serial %u does not match previous serial %u", page->pos, page->pos, line_count, pos, pos, serial_from, serial_to);
360                         }
361                     }
362                     else
363                     {
364                         page->serial_from = serial_from;
365                     }
366                 }
367                 else
368                 {
369                     formatln("; page @%u=%x line %i @%u=%x successfully scanned an SOA %{dnsrr} outside of line bounds", page->pos, page->pos, line_count, pos, pos, &rr);
370                 }
371             }
372             else
373             {
374                 // even
375 
376                 serial_to = serial;
377 
378                 page->serial_to = serial_to;
379 
380                 if(line_count < page->hdr.count)
381                 {
382                     return_value = SUCCESS;
383 
384                     if(serial_ge(serial_from, serial_to))
385                     {
386                         formatln("; page @%u=%x line %i @%u=%x serial %u not follow previous serial %u", page->pos, page->pos, line_count, pos, pos, serial_from, serial_to);
387                     }
388 
389                     if(serial_to != page->item[line_count].ends_with_serial)
390                     {
391                         formatln("; page @%u=%x line %i @%u=%x serial %u not end at expected value %u", page->pos, page->pos, line_count, pos, pos, serial_from, serial_to);
392                     }
393                 }
394                 else
395                 {
396                     formatln("; page @%u=%x line %i @%u=%x successfully scanned an SOA %{dnsrr} outside of line bounds", page->pos, page->pos, line_count, pos, pos, &rr);
397                 }
398             }
399         }
400 
401         if(g_dump)
402         {
403             rdata_desc rdatadesc={rr.tctr.qtype, rr.rdata_size, rr.rdata};
404 
405             formatln("%c | %{dnsname} %i %{dnstype} %{dnsclass} %{rdatadesc}",
406                     (soa_count&1)?'-':'+',
407                     rr.name,
408                     ntohl(rr.tctr.ttl),
409                     &rr.tctr.qtype,
410                     &rr.tctr.qclass,
411                     &rdatadesc);
412 
413             // formatln("%c | %{dnsrr}", (soa_count&1)?'-':'+', &rr);
414         }
415 
416         pos += ret;
417     }
418 
419     page->end = pos;
420 
421     formatln("; page @%u=%x streams covering serials %u to %u ended at position %u", page->pos, page->pos, page->serial_from, page->serial_to, page->end);
422 
423     dns_resource_record_clear(&rr);
424 
425     fd_input_stream_detach(buffer_input_stream_get_filtered(&bis));
426     input_stream_close(&bis);
427 
428     return return_value;
429 }
430 
431 #define PAGES_MAX 256
432 
433 struct journal_cjf_page_tbl_entry
434 {
435     journal_cjf_page_tbl_header hdr;
436     int group;
437 };
438 
439 typedef struct journal_cjf_page_tbl_entry journal_cjf_page_tbl_entry;
440 
cjf_scan(const char * name)441 static int cjf_scan(const char *name)
442 {
443     int fd;
444     cjf_header hdr;
445 
446     fd = open_ex(name, O_RDONLY);
447 
448     if(fd < 0)
449     {
450         return -1;
451     }
452 
453     formatln("; '%s' opened", name);
454 
455     s64 size = filesize(name);
456     if(size <= (s64)CJF_HEADER_REAL_SIZE)
457     {
458         close_ex(fd);
459         return -2;
460     }
461 
462     ssize_t n = readfully(fd, &hdr, CJF_HEADER_REAL_SIZE);
463 
464     if(n != CJF_HEADER_REAL_SIZE)
465     {
466         close_ex(fd);
467         return -3;
468     }
469 
470     if(hdr.magic_plus_version != CJF_CJF0_MAGIC)
471     {
472         close_ex(fd);
473         return -4;
474     }
475 
476     formatln("; serial from %u to %u", hdr.serial_begin, hdr.serial_end);
477     formatln("; first page starts at %u", hdr.first_index_offset);
478     formatln("; page index starts at %u", hdr.table_index_offset);
479     formatln("; last SOA starts at %u", hdr.last_soa_offset);
480     formatln("; the last page ends before %u", hdr.last_page_offset_next);
481 
482     if(hdr.flags & JOURNAL_CFJ_FLAGS_OTHER_ENDIAN)
483     {
484         println("; other-endian: 1");
485         close_ex(fd);
486         return -5;
487     }
488     if(hdr.flags & JOURNAL_CFJ_FLAGS_MY_ENDIAN)
489     {
490         println("; my-endian: 1");
491     }
492     if(hdr.flags & JOURNAL_CFJ_FLAGS_NOT_EMPTY)
493     {
494         println("; empty: 1");
495     }
496     if(hdr.flags & JOURNAL_CFJ_FLAGS_DIRTY)
497     {
498         println("; dirty: 1");
499     }
500     if(hdr.flags & JOURNAL_CFJ_FLAGS_UNINITIALISED)
501     {
502         println("; not-initialised: 1");
503     }
504 
505     // read a page, scan the records.
506 
507     u32 page_ofs = CJF_HEADER_REAL_SIZE;
508 
509     journal_cjf_page *page;
510 
511     for(;;)
512     {
513         if(cjf_read_page(fd, page_ofs, &page) >= 0)
514         {
515             // got a page
516             // scan the records and match them to the page
517 
518             if(ISOK(cjf_read_page_records(fd, page)))
519             {
520                 page_ofs = page->end;
521             }
522             else
523             {
524                 // try to scan page from just after
525                 ++page_ofs;
526             }
527         }
528         else
529         {
530             // broken page
531             // try to find the next magic "PAGE" in the file
532 
533             int next = cjf_scan_page(fd, page_ofs + 1);
534             if(next > 0)
535             {
536                 formatln("; page candidate at %u=%x", next, next);
537                 page_ofs = next;
538             }
539             else
540             {
541                 formatln("; no more page candidate found");
542                 break;
543             }
544         }
545     }
546 
547     close_ex(fd);
548 
549     return 0;
550 }
551 
552 static void
axfr_scan(const char * filename)553 axfr_scan(const char *filename)
554 {
555     input_stream is;
556     ya_result ret;
557 
558     dns_resource_record rr;
559 
560     if(FAIL(ret = file_input_stream_open(&is, filename)))
561     {
562         formatln("; %s: %r", filename, ret);
563         return;
564     }
565 
566     buffer_input_stream_init(&is, &is, 4096);
567 
568     dns_resource_record_init(&rr);
569 
570     for(int i = 0;; ++i)
571     {
572         if((ret = dns_resource_record_read(&rr, &is)) <= 0)
573         {
574             if(ret < 0)
575             {
576                 formatln("; %s: record %i: %r", filename, i, ret);
577             }
578             break;
579         }
580 
581         if((rr.tctr.qtype == TYPE_SOA) && (i > 0))
582         {
583             continue;
584         }
585 
586         formatln("%{dnszrr}", &rr);
587     }
588 
589     dns_resource_record_clear(&rr);
590 }
591 
592 static void
jnl_scan(const char * filepath)593 jnl_scan(const char *filepath)
594 {
595     journal *jnl = NULL;
596     const char *filename = strrchr(filepath, '/');
597     input_stream is;
598     size_t filename_len;
599     dns_resource_record rr;
600     dns_resource_record last_soa_rr;
601     ya_result ret;
602     u32 serial_from = 0;
603     u32 serial_to = 0;
604     u32 update_file_index = 0;
605     output_stream fos;
606     bool fos_ready = FALSE;
607 
608     u8 origin[MAX_DOMAIN_LENGTH];
609 
610     if(filename == NULL)
611     {
612         filename = filepath;
613     }
614     else
615     {
616         ++filename;
617     }
618 
619     filename_len = strlen(filename);
620     if(filename_len < 5)
621     {
622         formatln("; jnl: '%s' name is too small to parse", filepath);
623         return;
624     }
625 
626     if(FAIL(ret = cstr_to_dnsname_with_check_len(origin, filename, filename_len - 4)))
627     {
628         formatln("; jnl: '%s' cannot be parsed for origin: %r", filepath, ret);
629         return;
630     }
631 
632     if(FAIL(ret = journal_jnl_open_file(&jnl, filepath, origin, FALSE)))
633     {
634         formatln("; jnl: '%s' file cannot be opened as a journal: %r", filepath, ret);
635         return;
636     }
637 
638     ++jnl->rc;
639 
640     if(FAIL(ret = journal_get_serial_range(jnl, &serial_from, &serial_to)))
641     {
642         formatln("; jnl: '%s' file cannot get serial range: %r", filepath, ret);
643         return;
644     }
645 
646     dns_resource_record_init(&rr);
647 
648     formatln("; jnl: '%s' serial range: %u to %u", filepath, serial_from, serial_to);
649 
650     if(FAIL(ret = journal_get_ixfr_stream_at_serial(jnl, serial_from, &is, &rr)))
651     {
652         formatln("; jnl: '%s' file cannot read from its announced first serial %i : %r", filepath, serial_from, ret);
653         return;
654     }
655 
656     if(g_clean_mode)
657     {
658         dns_resource_record_init(&last_soa_rr);
659         ret = journal_get_last_soa(jnl, &last_soa_rr);
660         formatln("%{dnsrr}", &last_soa_rr);
661     }
662 
663     char mode = '+';
664 
665     for(;;)
666     {
667         ret = dns_resource_record_read(&rr, &is);
668 
669         if(ret <= 0)
670         {
671             if(FAIL(ret))
672             {
673                 formatln("; jnl: '%s' failed to read next record: %r", filepath,  ret);
674             }
675             else
676             {
677                 formatln("; jnl: '%s' end of file", filepath);
678             }
679 
680             break;
681         }
682 
683         if(rr.tctr.qtype == TYPE_SOA)
684         {
685             mode ^= ('+'^'-');
686 
687             if(g_generate_update_files)
688             {
689                 if(mode == '+')
690                 {
691                     if(fos_ready)
692                     {
693                         osformatln(&fos, "show\nsend");
694                         output_stream_close(&fos);
695                         fos_ready = FALSE;
696                     }
697                 }
698             }
699         }
700 
701         if(g_clean_mode)
702         {
703             formatln("%{dnsrr}", &rr);
704         }
705         else
706         {
707             formatln("%c %{dnsrr}", mode, &rr);
708         }
709 
710         if(g_generate_update_files)
711         {
712             switch(rr.tctr.qtype)
713             {
714                 case TYPE_SOA:
715                 case TYPE_NSEC:
716                 case TYPE_NSEC3:
717                 case TYPE_NSEC3PARAM:
718                 {
719                     break;
720                 }
721                 default:
722                 {
723                     if(mode == '-')
724                     {
725                         if(rr.tctr.qtype != TYPE_RRSIG)
726                         {
727                             if(!fos_ready)
728                             {
729                                 char name[280];
730                                 snformat(name, sizeof(name), "%{dnsname}..update-%08i.txt", origin, update_file_index++);
731                                 file_output_stream_create(&fos, name, 0644);
732                                 buffer_output_stream_init(&fos, &fos, 4096);
733                                 osformatln(&fos, "zone %{dnsname}\nclass IN\nttl 86400", origin);
734                                 fos_ready = TRUE;
735                             }
736 
737                             osformatln(&fos, "update del %{dnsrr}", &rr);
738                         }
739                     }
740                     else
741                     {
742                         if((rr.tctr.qtype != TYPE_RRSIG) || ((rr.tctr.qtype == TYPE_RRSIG) && (rrsig_get_type_covered_from_rdata(rr.rdata, rr.rdata_size) == TYPE_DNSKEY)))
743                         {
744                             if(!fos_ready)
745                             {
746                                 char name[280];
747                                 snformat(name, sizeof(name), "%{dnsname}..update-%08i.txt", origin, update_file_index++);
748                                 file_output_stream_create(&fos, name, 0644);
749                                 buffer_output_stream_init(&fos, &fos, 4096);
750                                 osformatln(&fos, "zone %{dnsname}\nclass IN\nttl 86400", origin);
751                                 fos_ready = TRUE;
752                             }
753 
754                             osformatln(&fos, "update add %{dnsrr}", &rr);
755                         }
756                     }
757 
758                     break;
759                 }
760             }
761         }
762     }
763 
764     if(g_clean_mode)
765     {
766         formatln("%{dnsrr}", &last_soa_rr);
767         dns_resource_record_finalize(&last_soa_rr);
768     }
769 
770     dns_resource_record_finalize(&rr);
771 
772     journal_release(jnl);
773 
774     formatln("; jnl: '%s' released", filepath);
775 }
776 
777 /*
778  *
779  */
main(int argc,char ** argv)780 int main(int argc, char** argv)
781 {
782     dnscore_init();
783     zdb_init();
784 
785     config_logger_setdefault();
786 
787     for(int i = 1; i < argc; ++i)
788     {
789         if(strcmp(argv[i], "-dump") == 0)
790         {
791             g_dump = TRUE;
792             continue;
793         }
794 
795         if(strcmp(argv[i], "-axfr") == 0)
796         {
797             g_mode = MODE_AXFR;
798             continue;
799         }
800 
801         if(strcmp(argv[i], "-cjf") == 0)
802         {
803             g_mode = MODE_CJF;
804             continue;
805         }
806 
807         if(strcmp(argv[i], "-jnl") == 0)
808         {
809             g_mode = MODE_JNL;
810             continue;
811         }
812 
813         if(strcmp(argv[i], "-clean") == 0)
814         {
815             g_clean_mode= TRUE;
816             continue;
817         }
818 
819         if(strcmp(argv[i], "-genupdate") == 0)
820         {
821             g_generate_update_files = TRUE;
822             continue;
823         }
824 
825         switch(g_mode)
826         {
827             case MODE_JNL:
828             {
829                 formatln("scanning '%s' (jnl)", argv[i]);
830                 jnl_scan(argv[i]);
831                 break;
832             }
833             case MODE_CJF:
834             {
835                 formatln("scanning '%s' (cjf)", argv[i]);
836                 cjf_scan(argv[i]);
837                 break;
838             }
839             case MODE_AXFR:
840             {
841                 axfr_scan(argv[i]);
842                 break;
843             }
844         }
845 
846     }
847 
848     zdb_finalize();
849     dnscore_finalize();
850     return (EXIT_SUCCESS);
851 }
852