/* darkstattype.c - Program to decode darkstat's dumpfile. $Ximalas$ Tested on FreeBSD/amd64 stable/9 r263290 with clang 3.3. Copyright © 2014, Trond Endrestøl All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include const char *progname = NULL; const char *filename = NULL; FILE *file = NULL; bool follow_specification = false; int main(int argc, char **argv) { void show_usage(int exitcode); void show_version(void); void decode_file(void); int i; progname = argv[0]; opterr = 0; while ( (i = getopt(argc, argv, "fhv")) != -1) { switch (i) { case 'f': follow_specification = !follow_specification; break; case 'h': show_usage(EXIT_SUCCESS); break; case 'v': show_version(); break; case '?': /*FALLTHROUGH*/ default: fprintf(stderr, "%s: illegal option -%c\n\n", progname, optopt); show_usage(EXIT_FAILURE); break; } // switch } // while argc -= optind; argv += optind; if (argv[0] == NULL) { fprintf(stderr, "%s: missing filename\n\n", progname); show_usage(EXIT_FAILURE); } // if filename = argv[0]; decode_file(); return EXIT_SUCCESS; } // main() void show_usage(int exitcode) { fprintf((exitcode == EXIT_SUCCESS) ? stdout : stderr, "Usage: %s [-f] [-h] [-v] filename\n" " E.g.: %s darkstat.db\n\n" "Options:\n" "-f\tToggle follow strict specification, default is false.\n" "-h\tShow this help message and exit.\n" "-v\tShow version and copyright and exit.\n", progname, progname); exit(exitcode); } // show_usage() void show_version(void) { puts("darkstattype 1.0"); puts("$Ximalas$"); puts(""); puts("Copyright © 2014, Trond Endrestøl "); puts("All rights reserved."); puts(""); puts("Redistribution and use in source and binary forms, with or without"); puts("modification, are permitted provided that the following conditions are met:"); puts(""); puts("1. Redistributions of source code must retain the above copyright notice, this"); puts(" list of conditions and the following disclaimer."); puts("2. Redistributions in binary form must reproduce the above copyright notice,"); puts(" this list of conditions and the following disclaimer in the documentation"); puts(" and/or other materials provided with the distribution."); puts(""); puts("THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND"); puts("ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED"); puts("WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE"); puts("DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR"); puts("ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES"); puts("(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;"); puts("LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND"); puts("ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT"); puts("(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS"); puts("SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."); exit(EXIT_SUCCESS); } // show_version() /* With clang 3.3 on FreeBSD/amd64 stable/9 r263290: char = 1 byte = 8 bits short = 2 bytes = 16 bits int = 4 bytes = 32 bits long = 8 bytes = 64 bits */ unsigned char read8u(void); signed char read8s(void); unsigned short read16u(void); signed short read16s(void); unsigned int read32u(void); signed int read32s(void); unsigned long read64u(void); signed long read64s(void); void indent(void); void exdent(void); void print_indentation(void); void print_time_t(time_t t); void decode_file(void) { void decode_host_db_v1(void); void decode_graph_db_v1(void); unsigned int fileheader; unsigned int sectionheader; unsigned int i; if ( (file = fopen(filename, "rb")) == NULL) { fprintf(stderr, "%s: fopen(\"%s\") = %s (%d)\n", progname, filename, strerror(errno), errno); exit(EXIT_FAILURE); } // if #define FILE_HEADER_V1 0xDA314159U if ( (fileheader = read32u()) != FILE_HEADER_V1) { // not darkstat export format fprintf(stderr, "%s:%s:%ld: file header = 0x%x, not 0x%x\n", progname, filename, ftell(file), fileheader, FILE_HEADER_V1); exit(EXIT_FAILURE); } // if printf("File header 0x%x\n", fileheader); // Possible section header for host_db v1 and later graph_db v1. indent(); #define HOST_DB_V1 0xDA485301U #define GRAPH_DB_V1 0xDA475201U for (i = 0; i < 2; i++) { if ( (sectionheader = read32u()) == HOST_DB_V1) { print_indentation(); printf("Section header host_db v1 0x%x\n", sectionheader); decode_host_db_v1(); } // if else if (sectionheader == GRAPH_DB_V1) { print_indentation(); printf("Section header graph_db v1 0x%x\n", sectionheader); decode_graph_db_v1(); } // else if else { fprintf(stderr, "%s:%s:%ld: unknown section header = 0x%x, neither 0x%x nor 0x%x\n", progname, filename, ftell(file), sectionheader, HOST_DB_V1, GRAPH_DB_V1); exit(EXIT_FAILURE); } // else } // for exdent(); } // decode_file() void decode_host_db_v1(void) { void decode_host_header_v1(void); void decode_host_header_v2(void); void decode_host_header_v3(void); unsigned int hostcount; unsigned int i; indent(); hostcount = read32u(); print_indentation(); printf("Host count %u\n", hostcount); for (i = 0; i < hostcount; i++) { unsigned int hostheader; print_indentation(); printf("Host #%u of %u:\n", i + 1, hostcount); indent(); #define HOST_HEADER_V3 0x48535403U #define HOST_HEADER_V2 0x48535402U #define HOST_HEADER_V1 0x48535401U if ( (hostheader = read32u()) == HOST_HEADER_V3) { // host header v3 print_indentation(); printf("Host header v3 0x%x\n", hostheader); decode_host_header_v3(); } // if else if (hostheader == HOST_HEADER_V2) { // host header v2 print_indentation(); printf("Host header v2 0x%x\n", hostheader); decode_host_header_v2(); } // else if else if (hostheader == HOST_HEADER_V1) { // host header v1 print_indentation(); printf("Host header v1 0x%x\n", hostheader); decode_host_header_v1(); } // else if else { // unknown host header version fprintf(stderr, "%s:%s:%ld: unknown host header = 0x%x, neither 0x%x nor 0x%x nor 0x%x\n", progname, filename, ftell(file), hostheader, HOST_HEADER_V3, HOST_HEADER_V2, HOST_HEADER_V1); exit(EXIT_FAILURE); } // else exdent(); } // for exdent(); } // decode_host_db_v1() void decode_protos_data(void); void decode_tcp_data(void); void decode_udp_data(void); void decode_host_header_v1(void) { unsigned char ipv4address[4]; unsigned char macaddress[6]; unsigned char hostnamelen; unsigned char hostname[256]; unsigned long bytesin; unsigned long bytesout; unsigned char protosdata; unsigned char tcpdata; unsigned char udpdata; unsigned char i; indent(); ipv4address[0] = read8u(); ipv4address[1] = read8u(); ipv4address[2] = read8u(); ipv4address[3] = read8u(); print_indentation(); printf("IPv4 address %d.%d.%d.%d\n", ipv4address[0], ipv4address[1], ipv4address[2], ipv4address[3]); macaddress[0] = read8u(); macaddress[1] = read8u(); macaddress[2] = read8u(); macaddress[3] = read8u(); macaddress[4] = read8u(); macaddress[5] = read8u(); print_indentation(); printf("MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", macaddress[0], macaddress[1], macaddress[2], macaddress[3], macaddress[4], macaddress[5]); hostnamelen = read8u(); print_indentation(); printf("Hostname length %d\n", hostnamelen); for (i = 0; i < hostnamelen; i++) { hostname[i] = read8u(); } // for hostname[i] = '\0'; print_indentation(); printf("Hostname %s\n", hostname); bytesin = read64u(); print_indentation(); printf("Bytes in %lu\n", bytesin); bytesout = read64u(); print_indentation(); printf("Bytes out %lu\n", bytesout); if ( (protosdata = read8u()) != 'P') { // missing protos data fprintf(stderr, "%s:%s:%ld: expecting character P, not %c\n", progname, filename, ftell(file), protosdata); exit(EXIT_FAILURE); } // if decode_protos_data(); if ( (tcpdata = read8u()) != 'T') { // missing tcp data fprintf(stderr, "%s:%s:%ld: expecting character T, not %c\n", progname, filename, ftell(file), tcpdata); exit(EXIT_FAILURE); } // if decode_tcp_data(); if ( (udpdata = read8u()) != 'U') { // missing udp data fprintf(stderr, "%s:%s:%ld: expecting character U, not %c\n", progname, filename, ftell(file), udpdata); exit(EXIT_FAILURE); } // if decode_udp_data(); exdent(); } // decode_host_header_v1 void decode_host_header_v2(void) { unsigned char ipv4address[4]; unsigned char macaddress[6]; signed long lastseen; unsigned char hostnamelen; unsigned char hostname[256]; unsigned long bytesin; unsigned long bytesout; unsigned char protosdata; unsigned char tcpdata; unsigned char udpdata; unsigned char i; indent(); ipv4address[0] = read8u(); ipv4address[1] = read8u(); ipv4address[2] = read8u(); ipv4address[3] = read8u(); print_indentation(); printf("IPv4 address %d.%d.%d.%d\n", ipv4address[0], ipv4address[1], ipv4address[2], ipv4address[3]); if (follow_specification == true) { macaddress[0] = read8u(); macaddress[1] = read8u(); macaddress[2] = read8u(); macaddress[3] = read8u(); macaddress[4] = read8u(); macaddress[5] = read8u(); print_indentation(); printf("MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", macaddress[0], macaddress[1], macaddress[2], macaddress[3], macaddress[4], macaddress[5]); lastseen = read64s(); print_indentation(); printf("Last seen 0x%lx = %ld = ", lastseen, lastseen); print_time_t(lastseen); puts(""); } // if else { lastseen = read64s(); print_indentation(); printf("Last seen 0x%lx = %ld = ", lastseen, lastseen); print_time_t(lastseen); puts(""); macaddress[0] = read8u(); macaddress[1] = read8u(); macaddress[2] = read8u(); macaddress[3] = read8u(); macaddress[4] = read8u(); macaddress[5] = read8u(); print_indentation(); printf("MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", macaddress[0], macaddress[1], macaddress[2], macaddress[3], macaddress[4], macaddress[5]); } // else hostnamelen = read8u(); print_indentation(); printf("Hostname length %d\n", hostnamelen); for (i = 0; i < hostnamelen; i++) { hostname[i] = read8u(); } // for hostname[i] = '\0'; print_indentation(); printf("Hostname %s\n", hostname); bytesin = read64u(); print_indentation(); printf("Bytes in %lu\n", bytesin); bytesout = read64u(); print_indentation(); printf("Bytes out %lu\n", bytesout); if ( (protosdata = read8u()) != 'P') { // missing protos data fprintf(stderr, "%s:%s:%ld: expecting character P, not %c\n", progname, filename, ftell(file), protosdata); exit(EXIT_FAILURE); } // if decode_protos_data(); if ( (tcpdata = read8u()) != 'T') { // missing tcp data fprintf(stderr, "%s:%s:%ld: expecting character T, not %c\n", progname, filename, ftell(file), tcpdata); exit(EXIT_FAILURE); } // if decode_tcp_data(); if ( (udpdata = read8u()) != 'U') { // missing udp data fprintf(stderr, "%s:%s:%ld: expecting character U, not %c\n", progname, filename, ftell(file), udpdata); exit(EXIT_FAILURE); } // if decode_udp_data(); exdent(); } // decode_host_header_v2 void decode_host_header_v3(void) { unsigned char addressfamily; unsigned char ipv4address[4]; unsigned short ipv6address[8]; unsigned char macaddress[6]; signed long lastseen; unsigned char hostnamelen; unsigned char hostname[256]; unsigned long bytesin; unsigned long bytesout; unsigned char protosdata; unsigned char tcpdata; unsigned char udpdata; unsigned char i; indent(); if ( (addressfamily = read8u()) == 0x04) { // IPv4 address print_indentation(); printf("IPv4 address family (0x%02x)\n", addressfamily); ipv4address[0] = read8u(); ipv4address[1] = read8u(); ipv4address[2] = read8u(); ipv4address[3] = read8u(); print_indentation(); printf("IPv4 address %d.%d.%d.%d\n", ipv4address[0], ipv4address[1], ipv4address[2], ipv4address[3]); } // if else if (addressfamily == 0x06) { // IPv6 address print_indentation(); printf("IPv6 address family (0x%02x)\n", addressfamily); ipv6address[ 0] = read16u(); ipv6address[ 1] = read16u(); ipv6address[ 2] = read16u(); ipv6address[ 3] = read16u(); ipv6address[ 4] = read16u(); ipv6address[ 5] = read16u(); ipv6address[ 6] = read16u(); ipv6address[ 7] = read16u(); print_indentation(); printf("IPv6 address %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", ipv6address[ 0], ipv6address[ 1], ipv6address[ 2], ipv6address[ 3], ipv6address[ 4], ipv6address[ 5], ipv6address[ 6], ipv6address[ 7]); } // else if else { // unknown address family fprintf(stderr, "%s:%s:%ld: unknown address family = 0x%x, neither 0x%x nor 0x%x\n", progname, filename, ftell(file), addressfamily, 0x04, 0x06); exit(EXIT_FAILURE); } // else if (follow_specification == true) { macaddress[0] = read8u(); macaddress[1] = read8u(); macaddress[2] = read8u(); macaddress[3] = read8u(); macaddress[4] = read8u(); macaddress[5] = read8u(); print_indentation(); printf("MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", macaddress[0], macaddress[1], macaddress[2], macaddress[3], macaddress[4], macaddress[5]); lastseen = read64s(); print_indentation(); printf("Last seen 0x%lx = %ld = ", lastseen, lastseen); print_time_t(lastseen); puts(""); } // if else { lastseen = read64s(); print_indentation(); printf("Last seen 0x%lx = %ld = ", lastseen, lastseen); print_time_t(lastseen); puts(""); macaddress[0] = read8u(); macaddress[1] = read8u(); macaddress[2] = read8u(); macaddress[3] = read8u(); macaddress[4] = read8u(); macaddress[5] = read8u(); print_indentation(); printf("MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", macaddress[0], macaddress[1], macaddress[2], macaddress[3], macaddress[4], macaddress[5]); } // else hostnamelen = read8u(); print_indentation(); printf("Hostname length %d\n", hostnamelen); for (i = 0; i < hostnamelen; i++) { hostname[i] = read8u(); } // for hostname[i] = '\0'; print_indentation(); printf("Hostname %s\n", hostname); bytesin = read64u(); print_indentation(); printf("Bytes in %lu\n", bytesin); bytesout = read64u(); print_indentation(); printf("Bytes out %lu\n", bytesout); if ( (protosdata = read8u()) != 'P') { // missing protos data fprintf(stderr, "%s:%s:%ld: expecting character P, not %c\n", progname, filename, ftell(file), protosdata); exit(EXIT_FAILURE); } // if decode_protos_data(); if ( (tcpdata = read8u()) != 'T') { // missing tcp data fprintf(stderr, "%s:%s:%ld: expecting character T, not %c\n", progname, filename, ftell(file), tcpdata); exit(EXIT_FAILURE); } // if decode_tcp_data(); if ( (udpdata = read8u()) != 'U') { // missing udp data fprintf(stderr, "%s:%s:%ld: expecting character U, not %c\n", progname, filename, ftell(file), udpdata); exit(EXIT_FAILURE); } // if decode_udp_data(); exdent(); } // decode_host_header_v3 void decode_protos_data(void) { unsigned char ipprotocount; unsigned char u; ipprotocount = read8u(); print_indentation(); printf("IP Proto count %d\n", ipprotocount); indent(); for (u = 0; u < ipprotocount; u++) { unsigned char proto; unsigned long in; unsigned long out; print_indentation(); printf("Protocol #%u of %u:\n", u + 1, ipprotocount); proto = read8u(); indent(); print_indentation(); printf("Protocol 0x%02x\n", proto); in = read64u(); print_indentation(); printf("In %lu\n", in); out = read64u(); print_indentation(); printf("Out %lu\n", out); exdent(); } // for exdent(); } // decode_protos_data(); void decode_tcp_data(void) { unsigned char tcpprotocount; unsigned short i; tcpprotocount = read16u(); print_indentation(); printf("TCP proto count %d\n", tcpprotocount); indent(); for (i = 0; i < tcpprotocount; i++) { unsigned short port; unsigned long syn; unsigned long in; unsigned long out; port = read16u(); print_indentation(); printf("Port %d:\n", port); syn = read64u(); indent(); print_indentation(); printf("SYN %lu\n", syn); in = read64u(); print_indentation(); printf("In %lu\n", in); out = read64u(); print_indentation(); printf("Out %lu\n", out); exdent(); } // for exdent(); } // decode_tcp_data() void decode_udp_data(void) { unsigned char udpprotocount; unsigned short i; udpprotocount = read16u(); print_indentation(); printf("UDP proto count %d\n", udpprotocount); indent(); for (i = 0; i < udpprotocount; i++) { unsigned short port; unsigned long in; unsigned long out; port = read16u(); print_indentation(); printf("Port %d:\n", port); in = read64u(); indent(); print_indentation(); printf("In %lu\n", in); out = read64u(); print_indentation(); printf("Out %lu\n", out); exdent(); } // for exdent(); } // decode_udp_data() void decode_graph_db_v1(void) { signed long lasttime; unsigned int i; lasttime = read64s(); indent(); print_indentation(); printf("Last time 0x%lx = %ld = ", lasttime, lasttime); print_time_t(lasttime); puts(""); for (i = 0; i < 4; i++) { unsigned char nbars; unsigned char idxlastbar; unsigned int j; print_indentation(); printf("Graph #%d of 4:\n", i + 1); nbars = read8u(); indent(); print_indentation(); printf("Number of bars %u\n", nbars); idxlastbar = read8u(); print_indentation(); printf("Index of last bar %u\n", idxlastbar); indent(); for (j = 0; j < idxlastbar; j++) { unsigned long in; unsigned long out; print_indentation(); printf("Bar #%u of %u:\n", j + 1, idxlastbar); in = read64u(); indent(); print_indentation(); printf("In %lu\n", in); out = read64u(); print_indentation(); printf("Out %lu\n", out); exdent(); } // for exdent(); exdent(); } // for exdent(); } // decode_graph_db_v1() void handle_file_error(void); unsigned char read8u(void) { size_t r; unsigned char v; //fprintf(stderr, "%s: sizeof(unsigned char) = %ld\n", progname, sizeof(v)); if ( (r = fread((void *)&v, sizeof(v), 1, file)) != 1) { handle_file_error(); } // if return v; } // read8u() signed char read8s(void) { size_t r; signed char v; //fprintf(stderr, "%s: sizeof(signed char) = %ld\n", progname, sizeof(v)); if ( (r = fread((void *)&v, sizeof(v), 1, file)) != 1) { handle_file_error(); } // if return v; } // read8s() #ifdef __LITTLE_ENDIAN__ #include #endif unsigned short read16u(void) { size_t r; unsigned short v; //fprintf(stderr, "%s: sizeof(unsigned short) = %ld\n", progname, sizeof(v)); if ( (r = fread((void *)&v, sizeof(v), 1, file)) != 1) { handle_file_error(); } // if #ifdef __LITTLE_ENDIAN__ v = ntohs(v); #endif return v; } // read16u() signed short read16s(void) { size_t r; signed short v; //fprintf(stderr, "%s: sizeof(signed short) = %ld\n", progname, sizeof(v)); if ( (r = fread((void *)&v, sizeof(v), 1, file)) != 1) { handle_file_error(); } // if #ifdef __LITTLE_ENDIAN__ v = ntohs(v); #endif return v; } // read16s() unsigned int read32u(void) { size_t r; unsigned int v; //fprintf(stderr, "%s: sizeof(unsigned int) = %ld\n", progname, sizeof(v)); if ( (r = fread((void *)&v, sizeof(v), 1, file)) != 1) { handle_file_error(); } // if #ifdef __LITTLE_ENDIAN__ v = ntohl(v); #endif return v; } // read32u() signed int read32s(void) { size_t r; signed int v; //fprintf(stderr, "%s: sizeof(signed int) = %ld\n", progname, sizeof(v)); if ( (r = fread((void *)&v, sizeof(v), 1, file)) != 1) { handle_file_error(); } // if #ifdef __LITTLE_ENDIAN__ v = ntohl(v); #endif return v; } // read32s() unsigned long read64u(void) { size_t r; unsigned long v; #ifdef __LITTLE_ENDIAN__ unsigned long tmp; unsigned int *p1 = (unsigned int *)&v; unsigned int *p2 = (unsigned int *)&tmp; #endif //fprintf(stderr, "%s: sizeof(unsigned long) = %ld\n", progname, sizeof(v)); if ( (r = fread((void *)&v, sizeof(v), 1, file)) != 1) { handle_file_error(); } // if #ifdef __LITTLE_ENDIAN__ p2[1] = ntohl(p1[0]); p2[0] = ntohl(p1[1]); v = tmp; #endif return v; } // read64u() signed long read64s(void) { size_t r; signed long v; #ifdef __LITTLE_ENDIAN__ signed long tmp; signed int *p1 = (signed int *)&v; signed int *p2 = (signed int *)&tmp; #endif //fprintf(stderr, "%s: sizeof(signed long) = %ld\n", progname, sizeof(v)); if ( (r = fread((void *)&v, sizeof(v), 1, file)) != 1) { handle_file_error(); } // if #ifdef __LITTLE_ENDIAN__ p2[1] = ntohl(p1[0]); p2[0] = ntohl(p1[1]); v = tmp; #endif return v; } // read64s() void handle_file_error(void) { int saved_errno = errno; if (feof(file) != 0) { fprintf(stderr, "%s:%s:%ld: premature end-of-file\n", progname, filename, ftell(file)); exit(EXIT_FAILURE); } // if if (ferror(file) != 0) { fprintf(stderr, "%s:%s:%ld: file error, errno = %s (%d)\n", progname, filename, ftell(file), strerror(saved_errno), saved_errno); exit(EXIT_FAILURE); } // if } // handle_file_error() signed long long indentation = 0LL; void indent(void) { indentation += 2LL; } // indent() void exdent(void) { indentation -= 2LL; if (indentation < 0LL) { indentation = 0LL; }// if } // exdent() void print_indentation(void) { signed long long i; for (i = 0; i < indentation; i++) { putchar(' '); } // for } // print_indentation() void print_time_t(time_t t) { struct tm *stm; char buffer[1024]; stm = gmtime(&t); // ISO 8601 format if (strftime(buffer, sizeof(buffer), "%Y-%m-%dT%H:%M:%S%z", stm) == 0) { int saved_errno = errno; fprintf(stderr, "%s:%s:%ld: strftime() error, errno = %s (%d)\n", progname, filename, ftell(file), strerror(saved_errno), saved_errno); exit(EXIT_FAILURE); } // if fputs(buffer, stdout); } // print_time_t() // darkstattype.c