Download | Plain Text | Line Numbers
/* dnscache-compact.c
diet -Os gcc -s -o dnscache-compact dnscache-compact.c -Wall -W -lowfat
http://riemann.fmi.uni-sofia.bg/
or in ./djbdns-1.05/ with:
./compile dnscache-compact.c
./load dnscache-compact buffer.a byte.a libtai.a unix.a dns.a alloc.a
I recommend using the second method (Nikola Vladov).
*/
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <signal.h>
#include <time.h>
#include <errno.h>
#include "str.h"
#include "case.h"
#include "tai.h"
#include "buffer.h"
#include "uint32.h"
#include "dns.h"
#include "scan.h"
void die(int n, const char *s1, const char *s2, const char *s3) {
if (s1) buffer_puts(buffer_2, s1);
if (s2) buffer_puts(buffer_2, s2);
if (s3) buffer_puts(buffer_2, s3);
buffer_puts(buffer_2, "\n");
buffer_flush(buffer_2);
_exit(n);
}
char **convert_hosts(int argc, char **argv) {
char **hh,**h,**a,*q;
if (!(hh = malloc((argc+1) * sizeof (char *))))
die(111, "malloc ", "error", 0);
for(q=0,h=hh,a=argv; *a; a++)
if (dns_domain_fromdot(&q, *a, str_len(*a)))
{*h++=q; q=0;}
return hh;
}
void dumpandwait(unsigned long pid, char *fn) {
struct stat st;
time_t mtime=0;
struct timespec ts = {0, 100000000}; /* 0.1s */
int i;
if (!stat(fn, &st)) mtime = st.st_mtime;
if (kill(pid,SIGALRM))
die(111, "unable to kill dnscache: ", "SIGALRM", 0);
for (i=0; i<60; i++) { /* 6-7 sec */
if (!stat(fn, &st))
if (mtime != st.st_mtime) return;
nanosleep(&ts, 0);
}
die(111, "timeout waiting for dnscache to dump", 0,0);
}
int main(int argc, char **argv) {
unsigned long flagkill = 0;
uint32 pos, len;
uint32 keylen;
uint32 datalen;
uint32 out;
struct tai now;
struct tai expire;
char buf[8192];
char *p,**hosts=0;
int fd,i;
buffer b= BUFFER_INIT((int (*)(int, const char *, unsigned int))write,
-1 , buf, sizeof buf);
if (argc>1 && argv[1][0] == '-') {
if (!scan_ulong(argv[1]+1, &flagkill) || flagkill <= 1)
die(111, "bad pid: ", argv[1]+1, 0);
argc--; argv++;
}
if (argc<4)
die(1,"usage: dnscache-compact [-pid] data new.tmp "
"new [key1] [key2] ...",0,0);
if (flagkill) dumpandwait(flagkill, argv[1]);
if ((fd=open(argv[1],O_RDONLY)) == -1)
die(21, argv[1], ": open ", "error");
if ((len=lseek(fd,0,SEEK_END)) == (uint32)-1)
die(21, argv[1], ": lseek ", "error");
if ((p=mmap(0,len,PROT_READ,MAP_SHARED,fd,0))==MAP_FAILED)
die(21, "mmap ", "error", 0);
close(fd);
if ((b.fd=open(argv[2],O_WRONLY|O_CREAT|O_TRUNC, 0644))==-1)
die(22, argv[2], ": open ", "error");
argc -= 4;
if (argc) hosts = convert_hosts(argc, argv+4);
tai_now(&now);
pos = 0;
while (pos+16 <= len) {
uint32_unpack(p + pos, &keylen);
uint32_unpack(p + pos + 4, &datalen);
tai_unpack(p + pos + 8, &expire);
out = 16 + keylen + datalen;
if (pos + out > len) goto die;
if (!tai_less(&expire,&now)) {
for (i=0; i<argc; i++) {
if (p[pos + 15 + keylen] == 0 &&
!case_diffb(hosts[i], keylen-2, p + pos + 18))
goto skip;
}
if (buffer_put(&b, p + pos, out)) goto die;
}
skip:
pos += out;
continue;
die:
munmap(p,len);
close (b.fd); unlink(argv[2]);
die(1, "input/output ", "error", 0);
}
if (buffer_flush(&b)) goto die;
if (pos != len) goto die;
if (fsync(b.fd) || close(b.fd)) goto die;
munmap(p,len);
if (rename(argv[2],argv[3])) goto die;
if (flagkill)
if (kill(flagkill,SIGHUP))
die(111, "unable to kill dnscache: ", "SIGHUP", 0);
return 0;
}