1218799Snwhitehorn/* xfr-inspect - list the contents and inspect an zone transfer XFR file 2218799Snwhitehorn * By W.C.A. Wijngaards 3218799Snwhitehorn * Copyright 2017, NLnet Labs. 4257842Sdteske * BSD, see LICENSE. 5218799Snwhitehorn */ 6218799Snwhitehorn 7218799Snwhitehorn#include "config.h" 8218799Snwhitehorn#include "util.h" 9218799Snwhitehorn#include "buffer.h" 10218799Snwhitehorn#include "packet.h" 11218799Snwhitehorn#include "rdata.h" 12218799Snwhitehorn#include "namedb.h" 13218799Snwhitehorn#include "difffile.h" 14218799Snwhitehorn#include <stdio.h> 15218799Snwhitehorn#include <errno.h> 16218799Snwhitehorn#include <string.h> 17218799Snwhitehorn#include <stdlib.h> 18218799Snwhitehorn#include <unistd.h> 19218799Snwhitehorn#include <ctype.h> 20218799Snwhitehorn 21218799Snwhitehorn/** verbosity for inspect */ 22218799Snwhitehornstatic int v = 0; 23218799Snwhitehorn/** shorthand for ease */ 24218799Snwhitehorn#ifdef ULL 25218799Snwhitehorn#undef ULL 26218799Snwhitehorn#endif 27218799Snwhitehorn#define ULL (unsigned long long) 28218799Snwhitehorn 29257842Sdteske/** print usage text */ 30257842Sdteskestatic void 31218799Snwhitehornusage(void) 32257842Sdteske{ 33257842Sdteske printf("usage: xfr-inspect [options] file\n"); 34285679Sallanjude printf(" -h this help\n"); 35218799Snwhitehorn printf(" -v increase verbosity: " 36257842Sdteske "with -v(list chunks), -vv(inside chunks)\n"); 37257842Sdteske printf(" -l list contents of transfer\n"); 38218799Snwhitehorn} 39269653Sthompsa 40269653Sthompsastatic int 41269653Sthompsaxi_diff_read_64(FILE *in, uint64_t* result) 42269653Sthompsa{ 43220088Snwhitehorn if (fread(result, sizeof(*result), 1, in) == 1) { 44220088Snwhitehorn return 1; 45218799Snwhitehorn } else { 46218799Snwhitehorn return 0; 47269653Sthompsa } 48218799Snwhitehorn} 49225637Snwhitehorn 50218799Snwhitehornstatic int 51218799Snwhitehornxi_diff_read_32(FILE *in, uint32_t* result) 52218799Snwhitehorn{ 53218799Snwhitehorn if (fread(result, sizeof(*result), 1, in) == 1) { 54218799Snwhitehorn *result = ntohl(*result); 55285679Sallanjude return 1; 56285732Sallanjude } else { 57285679Sallanjude return 0; 58285679Sallanjude } 59285679Sallanjude} 60285679Sallanjude 61285679Sallanjudestatic int 62285679Sallanjudexi_diff_read_8(FILE *in, uint8_t* result) 63285679Sallanjude{ 64285679Sallanjude if (fread(result, sizeof(*result), 1, in) == 1) { 65285679Sallanjude return 1; 66285679Sallanjude } else { 67285679Sallanjude return 0; 68285679Sallanjude } 69285679Sallanjude} 70285679Sallanjude 71285679Sallanjudestatic int 72285679Sallanjudexi_diff_read_str(FILE* in, char* buf, size_t len) 73285679Sallanjude{ 74285679Sallanjude uint32_t disklen; 75285679Sallanjude if(!xi_diff_read_32(in, &disklen)) 76285679Sallanjude return 0; 77285679Sallanjude if(disklen >= len) 78285679Sallanjude return 0; 79285679Sallanjude if(fread(buf, disklen, 1, in) != 1) 80285679Sallanjude return 0; 81285679Sallanjude buf[disklen] = 0; 82285679Sallanjude return 1; 83285679Sallanjude} 84285679Sallanjude 85285679Sallanjude 86285679Sallanjude/** inspect header of xfr file, return num_parts */ 87285679Sallanjudestatic int 88285679Sallanjudeinspect_header(FILE* in) 89285679Sallanjude{ 90285679Sallanjude char zone_buf[3072]; 91285679Sallanjude char patname_buf[2048]; 92285679Sallanjude 93285679Sallanjude uint32_t old_serial, new_serial, num_parts, type; 94285679Sallanjude uint64_t time_end_0, time_start_0; 95285679Sallanjude uint32_t time_end_1, time_start_1; 96285679Sallanjude uint8_t committed; 97285679Sallanjude 98285679Sallanjude time_t time_end, time_start; 99285679Sallanjude 100285679Sallanjude if(!xi_diff_read_32(in, &type)) { 101285679Sallanjude printf("could not read type, file short\n"); 102285679Sallanjude fclose(in); 103257842Sdteske exit(1); 104218799Snwhitehorn } 105257842Sdteske if(type != DIFF_PART_XFRF) { 106257842Sdteske printf("type: %x (BAD FILE TYPE)\n", type); 107218799Snwhitehorn fclose(in); 108218799Snwhitehorn exit(1); 109218799Snwhitehorn } 110218799Snwhitehorn if(!xi_diff_read_8(in, &committed) || 111218799Snwhitehorn !xi_diff_read_32(in, &num_parts) || 112218799Snwhitehorn !xi_diff_read_64(in, &time_end_0) || 113218799Snwhitehorn !xi_diff_read_32(in, &time_end_1) || 114269653Sthompsa !xi_diff_read_32(in, &old_serial) || 115218799Snwhitehorn !xi_diff_read_32(in, &new_serial) || 116219615Snwhitehorn !xi_diff_read_64(in, &time_start_0) || 117219615Snwhitehorn !xi_diff_read_32(in, &time_start_1) || 118293223Sgjb !xi_diff_read_str(in, zone_buf, sizeof(zone_buf)) || 119293223Sgjb !xi_diff_read_str(in, patname_buf, sizeof(patname_buf))) { 120218947Snwhitehorn printf("diff file bad commit part, file too short"); 121219615Snwhitehorn fclose(in); 122241902Sdteske exit(1); 123241902Sdteske } 124241902Sdteske time_end = (time_t)time_end_0; 125241902Sdteske time_start = (time_t)time_start_0; 126241902Sdteske 127241902Sdteske /* printf("type: %x\n", (int)type); */ 128219615Snwhitehorn printf("committed: %d (%s)\n", (int)committed, 129219615Snwhitehorn committed?"yes":"no"); 130219615Snwhitehorn printf("num_parts: %d\n", (int)num_parts); 131219615Snwhitehorn printf("time_end: %d.%6.6d %s", (int)time_end_0, 132218947Snwhitehorn (int)time_end_1, ctime(&time_end)); 133293223Sgjb printf("old_serial: %u\n", (unsigned)old_serial); 134218799Snwhitehorn printf("new_serial: %u\n", (unsigned)new_serial); 135218799Snwhitehorn printf("time_start: %d.%6.6d %s", (int)time_start_0, 136218799Snwhitehorn (int)time_start_1, ctime(&time_start)); 137218799Snwhitehorn printf("zone: %s\n", zone_buf); 138293223Sgjb printf("patname: %s\n", patname_buf); 139293223Sgjb 140218799Snwhitehorn return num_parts; 141218799Snwhitehorn} 142293223Sgjb 143220080Snwhitehorn/** print records in packet */ 144218799Snwhitehornstatic void 145220080Snwhitehornprint_records(region_type* region, buffer_type* pkt, int num, int qsection) 146293223Sgjb{ 147218799Snwhitehorn domain_table_type* table; 148218799Snwhitehorn int i; 149218799Snwhitehorn rr_type* rr; 150218799Snwhitehorn region_type* tmpregion = region_create(xalloc, free); 151220088Snwhitehorn buffer_type* tmpbuf; 152220080Snwhitehorn if(!tmpregion) { 153220834Snwhitehorn printf("out of memory\n"); 154220080Snwhitehorn return; 155220080Snwhitehorn } 156269653Sthompsa tmpbuf = buffer_create(region, QIOBUFSZ); 157220080Snwhitehorn if(!tmpbuf) { 158220080Snwhitehorn printf("out of memory\n"); 159220080Snwhitehorn return; 160259572Sdteske } 161218799Snwhitehorn table = domain_table_create(tmpregion); 162218799Snwhitehorn if(!table) { 163285679Sallanjude printf("out of memory\n"); 164285679Sallanjude return; 165285679Sallanjude } 166285679Sallanjude 167285679Sallanjude for(i=0; i<num; ++i) { 168285679Sallanjude rr = packet_read_rr(region, table, pkt, qsection); 169285679Sallanjude if(!rr) { 170285679Sallanjude printf("; cannot read rr %d\n", i); 171285679Sallanjude return; 172285679Sallanjude } 173285679Sallanjude if(qsection) { 174285732Sallanjude printf("%s", dname_to_string(domain_dname(rr->owner), 175285732Sallanjude NULL)); 176285732Sallanjude printf("\t%s", rrclass_to_string(rr->klass)); 177285732Sallanjude if(rr->type == TYPE_IXFR) 178285732Sallanjude printf("\tIXFR\n"); 179285732Sallanjude else if(rr->type == TYPE_AXFR) 180285732Sallanjude printf("\tAXFR\n"); 181285732Sallanjude else printf("\t%s\n", rrtype_to_string(rr->type)); 182285679Sallanjude } else { 183285679Sallanjude if(!print_rr(stdout, NULL, rr, tmpregion, tmpbuf)) { 184285679Sallanjude printf("; cannot print rr %d\n", i); 185302320Sallanjude } 186285679Sallanjude } 187285679Sallanjude } 188285679Sallanjude region_destroy(tmpregion); 189285679Sallanjude} 190285679Sallanjude 191285679Sallanjude/** inspect packet (IXFR or AXFR) */ 192285679Sallanjudestatic void 193285679Sallanjudeinspect_packet(region_type* region, buffer_type* pkt) 194285679Sallanjude{ 195285679Sallanjude printf("\n"); 196285679Sallanjude if(buffer_limit(pkt) < QHEADERSZ) { 197285679Sallanjude printf("packet too short\n"); 198302320Sallanjude return; 199285679Sallanjude } 200285679Sallanjude printf("; id=%4.4x ; flags%s%s%s%s%s%s%s%s ; rcode %s ; opcode %d\n", 201285679Sallanjude ID(pkt), QR(pkt)?" QR":"", AA(pkt)?" AA":"", TC(pkt)?" TC":"", 202285679Sallanjude RD(pkt)?" RD":"", RA(pkt)?" RA":"", Z(pkt)?" Z":"", 203285679Sallanjude AD(pkt)?" AD":"", CD(pkt)?" CD":"", rcode2str(RCODE(pkt)), 204285679Sallanjude OPCODE(pkt)); 205285679Sallanjude printf("; qdcount %d ; ancount %d ; nscount %d ; arcount %d\n", 206285679Sallanjude QDCOUNT(pkt), ANCOUNT(pkt), NSCOUNT(pkt), ARCOUNT(pkt)); 207285679Sallanjude buffer_skip(pkt, QHEADERSZ); 208285679Sallanjude 209287843Sallanjude if(QDCOUNT(pkt) != 0) { 210287843Sallanjude printf("; QUESTION SECTION\n"); 211287843Sallanjude print_records(region, pkt, QDCOUNT(pkt), 1); 212287843Sallanjude } 213287843Sallanjude if(ANCOUNT(pkt) != 0) { 214287843Sallanjude printf("; ANSWER SECTION\n"); 215287843Sallanjude print_records(region, pkt, ANCOUNT(pkt), 0); 216287843Sallanjude } 217287843Sallanjude if(NSCOUNT(pkt) != 0) { 218287843Sallanjude printf("; AUTHORITY SECTION\n"); 219287843Sallanjude print_records(region, pkt, NSCOUNT(pkt), 0); 220287843Sallanjude } 221287843Sallanjude if(ARCOUNT(pkt) != 0) { 222285679Sallanjude printf("; ADDITIONAL SECTION\n"); 223285732Sallanjude print_records(region, pkt, ARCOUNT(pkt), 0); 224285732Sallanjude } 225285732Sallanjude} 226285732Sallanjude 227285732Sallanjude/** inspect part of xfr file */ 228285732Sallanjudestatic void 229287843Sallanjudeinspect_part(FILE* in, int partnum) 230285732Sallanjude{ 231285732Sallanjude uint32_t pkttype, msglen, msglen2; 232285732Sallanjude region_type* region; 233285732Sallanjude buffer_type* packet; 234285732Sallanjude region = region_create(xalloc, free); 235285732Sallanjude if(!region) { 236285732Sallanjude printf("out of memory\n"); 237285732Sallanjude fclose(in); 238285732Sallanjude exit(1); 239285732Sallanjude } 240287843Sallanjude packet = buffer_create(region, QIOBUFSZ); 241287843Sallanjude if(!xi_diff_read_32(in, &pkttype)) { 242287843Sallanjude printf("cannot read part %d\n", partnum); 243287843Sallanjude fclose(in); 244287843Sallanjude exit(1); 245287843Sallanjude } 246287843Sallanjude if(pkttype != DIFF_PART_XXFR) { 247287843Sallanjude printf("bad part %d: not type XXFR\n", partnum); 248287843Sallanjude fclose(in); 249287843Sallanjude exit(1); 250287843Sallanjude } 251287843Sallanjude if(!xi_diff_read_32(in, &msglen)) { 252287843Sallanjude printf("bad part %d: not msglen, file too short\n", partnum); 253285732Sallanjude fclose(in); 254285679Sallanjude exit(1); 255285679Sallanjude } 256256343Sdteske if(msglen < QHEADERSZ || msglen > QIOBUFSZ) { 257271553Snwhitehorn printf("bad part %d: msglen %u (too short or too long)\n", 258271553Snwhitehorn partnum, (unsigned)msglen); 259256343Sdteske fclose(in); 260218799Snwhitehorn exit(1); 261256343Sdteske } 262256343Sdteske if(fread(buffer_begin(packet), msglen, 1, in) != 1) { 263256343Sdteske printf("bad part %d: short packet, file too short, %s\n", 264271567Snwhitehorn partnum, strerror(errno)); 265256343Sdteske fclose(in); 266256343Sdteske exit(1); 267256343Sdteske } 268256343Sdteske if(!xi_diff_read_32(in, &msglen2)) { 269256343Sdteske printf("bad part %d: cannot read msglen2, file too short\n", partnum); 270256343Sdteske fclose(in); 271256343Sdteske exit(1); 272256343Sdteske } 273256343Sdteske if(v==0) { 274259570Sdteske region_destroy(region); 275256343Sdteske return; 276256343Sdteske } 277256343Sdteske 278271553Snwhitehorn printf("\n"); 279269653Sthompsa /* printf("type : %x\n", pkttype); */ 280269653Sthompsa printf("part : %d\n", partnum); 281218799Snwhitehorn printf("msglen : %u\n", (unsigned)msglen); 282256343Sdteske printf("msglen2 : %u (%s)\n", (unsigned)msglen2, 283218799Snwhitehorn (msglen==msglen2)?"ok":"wrong"); 284218799Snwhitehorn 285222425Snwhitehorn if(v>=2) { 286218799Snwhitehorn buffer_set_limit(packet, msglen); 287256343Sdteske inspect_packet(region, packet); 288257842Sdteske } 289257842Sdteske 290269653Sthompsa region_destroy(region); 291257842Sdteske} 292269653Sthompsa 293257842Sdteske/** inspect parts of xfr file */ 294269653Sthompsastatic void 295218799Snwhitehorninspect_parts(FILE* in, int num) 296271553Snwhitehorn{ 297269653Sthompsa int i; 298269653Sthompsa for(i=0; i<num; i++) { 299256343Sdteske inspect_part(in, i); 300218799Snwhitehorn } 301269653Sthompsa} 302218799Snwhitehorn 303218799Snwhitehorn/** inspect trail of xfr file */ 304218799Snwhitehornstatic void 305218799Snwhitehorninspect_trail(FILE* in) 306218799Snwhitehorn{ 307293223Sgjb char log_buf[5120]; 308218799Snwhitehorn if(!xi_diff_read_str(in, log_buf, sizeof(log_buf))) { 309218799Snwhitehorn printf("bad trail: cannot read log string\n"); 310219528Snwhitehorn fclose(in); 311269653Sthompsa exit(1); 312218799Snwhitehorn } 313218799Snwhitehorn printf("\n"); 314218799Snwhitehorn printf("log: %s\n", log_buf); 315220088Snwhitehorn} 316220080Snwhitehorn 317223897Snwhitehorn/** inspect contents of xfr file */ 318225637Snwhitehornstatic void 319293223Sgjbinspect_file(char* fname) 320218799Snwhitehorn{ 321218799Snwhitehorn FILE* in; 322218799Snwhitehorn int num; 323225637Snwhitehorn log_init("udb-inspect"); 324293223Sgjb if(!(in=fopen(fname, "r"))) { 325293223Sgjb printf("cannot open %s: %s\n", fname, strerror(errno)); 326293223Sgjb exit(1); 327293223Sgjb } 328293223Sgjb printf("file: %s\n", fname); 329293223Sgjb num = inspect_header(in); 330293223Sgjb inspect_parts(in, num); 331293223Sgjb inspect_trail(in); 332293223Sgjb fclose(in); 333293223Sgjb} 334293223Sgjb 335293223Sgjb/** list header of xfr file, return num_parts */ 336293223Sgjbstatic int 337293223Sgjblist_header(FILE* in) 338293223Sgjb{ 339293223Sgjb char zone_buf[3072]; 340293223Sgjb char patname_buf[2048]; 341293223Sgjb 342293223Sgjb uint32_t old_serial, new_serial, num_parts, type; 343293223Sgjb uint64_t time_end_0, time_start_0; 344293223Sgjb uint32_t time_end_1, time_start_1; 345293223Sgjb uint8_t committed; 346293223Sgjb 347293223Sgjb time_t time_end, time_start; 348293223Sgjb 349293223Sgjb if(!xi_diff_read_32(in, &type)) { 350293223Sgjb printf("could not read type, file short\n"); 351293223Sgjb fclose(in); 352293223Sgjb exit(1); 353293223Sgjb } 354293223Sgjb if(type != DIFF_PART_XFRF) { 355293223Sgjb printf("type: %x (BAD FILE TYPE)\n", type); 356293223Sgjb fclose(in); 357293223Sgjb exit(1); 358293223Sgjb } 359218799Snwhitehorn if(!xi_diff_read_8(in, &committed) || 360218799Snwhitehorn !xi_diff_read_32(in, &num_parts) || 361218799Snwhitehorn !xi_diff_read_64(in, &time_end_0) || 362293223Sgjb !xi_diff_read_32(in, &time_end_1) || 363293223Sgjb !xi_diff_read_32(in, &old_serial) || 364293223Sgjb !xi_diff_read_32(in, &new_serial) || 365293223Sgjb !xi_diff_read_64(in, &time_start_0) || 366293223Sgjb !xi_diff_read_32(in, &time_start_1) || 367293223Sgjb !xi_diff_read_str(in, zone_buf, sizeof(zone_buf)) || 368293223Sgjb !xi_diff_read_str(in, patname_buf, sizeof(patname_buf))) { 369293223Sgjb printf("diff file bad commit part, file too short"); 370293223Sgjb fclose(in); 371293223Sgjb exit(1); 372293223Sgjb } 373293223Sgjb time_end = (time_t)time_end_0; 374293223Sgjb time_start = (time_t)time_start_0; 375293223Sgjb 376293223Sgjb /* printf("; type: %x\n", (int)type); */ 377293223Sgjb printf("; committed: %d (%s)\n", (int)committed, 378269653Sthompsa committed?"yes":"no"); 379269653Sthompsa printf("; num_parts: %d\n", (int)num_parts); 380269653Sthompsa printf("; time_end: %d.%6.6d %s", (int)time_end_0, 381218799Snwhitehorn (int)time_end_1, ctime(&time_end)); 382218799Snwhitehorn printf("; old_serial: %u\n", (unsigned)old_serial); 383218799Snwhitehorn printf("; new_serial: %u\n", (unsigned)new_serial); 384218799Snwhitehorn printf("; time_start: %d.%6.6d %s", (int)time_start_0, 385218799Snwhitehorn (int)time_start_1, ctime(&time_start)); 386218799Snwhitehorn printf("; zone: %s\n", zone_buf); 387218799Snwhitehorn printf("; patname: %s\n", patname_buf); 388303447Srobak 389218799Snwhitehorn return num_parts; 390218799Snwhitehorn} 391218799Snwhitehorn 392218799Snwhitehorn/** list packet (IXFR or AXFR) */ 393218799Snwhitehornstatic void 394218799Snwhitehornlist_packet(region_type* region, buffer_type* pkt, int partnum) 395218799Snwhitehorn{ 396218799Snwhitehorn if(buffer_limit(pkt) < QHEADERSZ) { 397218799Snwhitehorn printf("packet too short\n"); 398228194Snwhitehorn return; 399226507Skensmith } 400218799Snwhitehorn buffer_skip(pkt, QHEADERSZ); 401218799Snwhitehorn 402218799Snwhitehorn if(partnum == 0 && QDCOUNT(pkt) == 1) { 403218799Snwhitehorn /* print query AXFR or IXFR */ 404218799Snwhitehorn printf("; "); 405303447Srobak print_records(region, pkt, QDCOUNT(pkt), 1); 406218799Snwhitehorn } 407228194Snwhitehorn if(ANCOUNT(pkt) != 0) { 408218799Snwhitehorn print_records(region, pkt, ANCOUNT(pkt), 0); 409218799Snwhitehorn } 410218799Snwhitehorn} 411218799Snwhitehorn 412218799Snwhitehorn/** list part of xfr file */ 413218799Snwhitehornstatic void 414218799Snwhitehornlist_part(FILE* in, int partnum) 415218799Snwhitehorn{ 416218799Snwhitehorn uint32_t pkttype, msglen, msglen2; 417218799Snwhitehorn region_type* region; 418218799Snwhitehorn buffer_type* packet; 419218799Snwhitehorn region = region_create(xalloc, free); 420218799Snwhitehorn if(!region) { 421218799Snwhitehorn printf("out of memory\n"); 422218799Snwhitehorn fclose(in); 423218799Snwhitehorn exit(1); 424218799Snwhitehorn } 425218799Snwhitehorn packet = buffer_create(region, QIOBUFSZ); 426218799Snwhitehorn if(!xi_diff_read_32(in, &pkttype)) { 427218799Snwhitehorn printf("cannot read part %d\n", partnum); 428218799Snwhitehorn fclose(in); 429218799Snwhitehorn exit(1); 430218799Snwhitehorn } 431303447Srobak if(pkttype != DIFF_PART_XXFR) { 432303447Srobak printf("bad part %d: not type XXFR\n", partnum); 433303447Srobak fclose(in); 434303447Srobak exit(1); 435218799Snwhitehorn } 436218799Snwhitehorn if(!xi_diff_read_32(in, &msglen)) { 437218799Snwhitehorn printf("bad part %d: not msglen, file too short\n", partnum); 438218799Snwhitehorn fclose(in); 439223897Snwhitehorn exit(1); 440223897Snwhitehorn } 441223897Snwhitehorn if(msglen < QHEADERSZ || msglen > QIOBUFSZ) { 442223897Snwhitehorn printf("bad part %d: msglen %u (too short or too long)\n", 443218799Snwhitehorn partnum, (unsigned)msglen); 444218799Snwhitehorn fclose(in); 445218799Snwhitehorn exit(1); 446218799Snwhitehorn } 447218799Snwhitehorn if(fread(buffer_begin(packet), msglen, 1, in) != 1) { 448218799Snwhitehorn printf("bad part %d: short packet, file too short, %s\n", 449218799Snwhitehorn partnum, strerror(errno)); 450269653Sthompsa fclose(in); 451218799Snwhitehorn exit(1); 452218799Snwhitehorn } 453218799Snwhitehorn if(!xi_diff_read_32(in, &msglen2)) { 454218799Snwhitehorn printf("bad part %d: cannot read msglen2, file too short\n", partnum); 455218799Snwhitehorn fclose(in); 456218799Snwhitehorn exit(1); 457218799Snwhitehorn } 458228194Snwhitehorn 459271552Snwhitehorn buffer_set_limit(packet, msglen); 460271552Snwhitehorn list_packet(region, packet, partnum); 461228194Snwhitehorn region_destroy(region); 462228194Snwhitehorn} 463232531Snwhitehorn 464228194Snwhitehorn/** list parts of xfr file */ 465228194Snwhitehornstatic void 466228194Snwhitehornlist_parts(FILE* in, int num) 467228194Snwhitehorn{ 468228194Snwhitehorn int i; 469256338Sdes for(i=0; i<num; i++) { 470256338Sdes list_part(in, i); 471256338Sdes } 472257842Sdteske} 473218799Snwhitehorn 474257842Sdteske/** list contents of xfr file */ 475257842Sdteskestatic void 476257842Sdteskelist_file(char* fname) 477{ 478 FILE* in; 479 int num; 480 log_init("udb-inspect"); 481 if(!(in=fopen(fname, "r"))) { 482 printf("cannot open %s: %s\n", fname, strerror(errno)); 483 exit(1); 484 } 485 num = list_header(in); 486 list_parts(in, num); 487 488 fclose(in); 489} 490 491/** getopt global, in case header files fail to declare it. */ 492extern int optind; 493/** getopt global, in case header files fail to declare it. */ 494extern char* optarg; 495 496/** 497 * main program. Set options given commandline arguments. 498 * @param argc: number of commandline arguments. 499 * @param argv: array of commandline arguments. 500 * @return: exit status of the program. 501 */ 502int 503main(int argc, char* argv[]) 504{ 505 int c, list=0; 506 while( (c=getopt(argc, argv, "hlv")) != -1) { 507 switch(c) { 508 case 'l': 509 list=1; 510 break; 511 case 'v': 512 v++; 513 break; 514 default: 515 case 'h': 516 usage(); 517 return 1; 518 } 519 } 520 argc -= optind; 521 argv += optind; 522 if(argc != 1) { 523 usage(); 524 return 1; 525 } 526 if(list) list_file(argv[0]); 527 else inspect_file(argv[0]); 528 529 return 0; 530} 531