release
[hcoop/zz_old/debian/djbdns.git] / pickdns-data.c
CommitLineData
dc0d77d7
CE
1#include <stdio.h>
2#include <sys/types.h>
3#include <sys/stat.h>
4#include <unistd.h>
5#include "buffer.h"
6#include "exit.h"
7#include "cdb_make.h"
8#include "open.h"
9#include "alloc.h"
10#include "gen_allocdefs.h"
11#include "stralloc.h"
12#include "getln.h"
13#include "case.h"
14#include "strerr.h"
15#include "str.h"
16#include "byte.h"
17#include "scan.h"
18#include "fmt.h"
19#include "ip4.h"
20#include "dns.h"
21
22#define FATAL "pickdns-data: fatal: "
23
24void nomem(void)
25{
26 strerr_die2x(111,FATAL,"out of memory");
27}
28
29void ipprefix_cat(stralloc *out,char *s)
30{
31 unsigned long u;
32 char ch;
33 unsigned int j;
34
35 for (;;)
36 if (*s == '.')
37 ++s;
38 else {
39 j = scan_ulong(s,&u);
40 if (!j) return;
41 s += j;
42 ch = u;
43 if (!stralloc_catb(out,&ch,1)) nomem();
44 }
45}
46
47struct address {
48 char *name;
49 unsigned int namelen;
50 char ip[4];
51 char location[2];
52} ;
53
54int address_diff(struct address *p,struct address *q)
55{
56 int r;
57
58 r = byte_diff(p->location,2,q->location);
59 if (r < 0) return -1;
60 if (r > 0) return 1;
61 if (p->namelen < q->namelen) return -1;
62 if (p->namelen > q->namelen) return 1;
63 return case_diffb(p->name,p->namelen,q->name);
64}
65
66void address_sort(struct address *z,unsigned int n)
67{
68 unsigned int i;
69 unsigned int j;
70 unsigned int p;
71 unsigned int q;
72 struct address t;
73
74 i = j = n;
75 --z;
76
77 while (j > 1) {
78 if (i > 1) { --i; t = z[i]; }
79 else { t = z[j]; z[j] = z[i]; --j; }
80 q = i;
81 while ((p = q * 2) < j) {
82 if (address_diff(&z[p + 1],&z[p]) >= 0) ++p;
83 z[q] = z[p]; q = p;
84 }
85 if (p == j) {
86 z[q] = z[p]; q = p;
87 }
88 while ((q > i) && (address_diff(&t,&z[p = q/2]) > 0)) {
89 z[q] = z[p]; q = p;
90 }
91 z[q] = t;
92 }
93}
94
95GEN_ALLOC_typedef(address_alloc,struct address,s,len,a)
96GEN_ALLOC_readyplus(address_alloc,struct address,s,len,a,i,n,x,30,address_alloc_readyplus)
97GEN_ALLOC_append(address_alloc,struct address,s,len,a,i,n,x,30,address_alloc_readyplus,address_alloc_append)
98
99static address_alloc x;
100
101int fd;
102buffer b;
103char bspace[1024];
104
105int fdcdb;
106struct cdb_make cdb;
107static stralloc key;
108static stralloc result;
109
110static stralloc line;
111int match = 1;
112unsigned long linenum = 0;
113
114#define NUMFIELDS 3
115static stralloc f[NUMFIELDS];
116
117char strnum[FMT_ULONG];
118
119void syntaxerror(const char *why)
120{
121 strnum[fmt_ulong(strnum,linenum)] = 0;
122 strerr_die4x(111,FATAL,"unable to parse data line ",strnum,why);
123}
124void die_datatmp(void)
125{
126 strerr_die2sys(111,FATAL,"unable to create data.tmp: ");
127}
128
129int main()
130{
131 struct address t;
132 int i;
133 int j;
134 int k;
135 char ch;
136
137 umask(022);
138
139 if (!address_alloc_readyplus(&x,0)) nomem();
140
141 fd = open_read("data");
142 if (fd == -1) strerr_die2sys(111,FATAL,"unable to open data: ");
143 buffer_init(&b,buffer_unixread,fd,bspace,sizeof bspace);
144
145 fdcdb = open_trunc("data.tmp");
146 if (fdcdb == -1) die_datatmp();
147 if (cdb_make_start(&cdb,fdcdb) == -1) die_datatmp();
148
149 while (match) {
150 ++linenum;
151 if (getln(&b,&line,&match,'\n') == -1)
152 strerr_die2sys(111,FATAL,"unable to read line: ");
153
154 while (line.len) {
155 ch = line.s[line.len - 1];
156 if ((ch != ' ') && (ch != '\t') && (ch != '\n')) break;
157 --line.len;
158 }
159 if (!line.len) continue;
160
161 j = 1;
162 for (i = 0;i < NUMFIELDS;++i) {
163 if (j >= line.len) {
164 if (!stralloc_copys(&f[i],"")) nomem();
165 }
166 else {
167 k = byte_chr(line.s + j,line.len - j,':');
168 if (!stralloc_copyb(&f[i],line.s + j,k)) nomem();
169 j += k + 1;
170 }
171 }
172
173 switch(line.s[0]) {
174 default:
175 syntaxerror(": unrecognized leading character");
176 case '#':
177 break;
178 case '-':
179 break;
180 case '+':
181 byte_zero(&t,sizeof t);
182 if (!dns_domain_fromdot(&t.name,f[0].s,f[0].len)) nomem();
183 t.namelen = dns_domain_length(t.name);
184 case_lowerb(t.name,t.namelen);
185 if (!stralloc_0(&f[1])) nomem();
186 if (!ip4_scan(f[1].s,t.ip)) syntaxerror(": malformed IP address");
187 if (!stralloc_0(&f[2])) nomem();
188 if (!stralloc_0(&f[2])) nomem();
189 byte_copy(t.location,2,f[2].s);
190 if (!address_alloc_append(&x,&t)) nomem();
191 break;
192 case '%':
193 if (!stralloc_0(&f[0])) nomem();
194 if (!stralloc_0(&f[0])) nomem();
195 if (!stralloc_copyb(&result,f[0].s,2)) nomem();
196 if (!stralloc_0(&f[1])) nomem();
197 if (!stralloc_copys(&key,"%")) nomem();
198 ipprefix_cat(&key,f[1].s);
199 if (cdb_make_add(&cdb,key.s,key.len,result.s,result.len) == -1)
200 die_datatmp();
201 break;
202 }
203 }
204
205 close(fd);
206 address_sort(x.s,x.len);
207
208 i = 0;
209 while (i < x.len) {
210 for (j = i + 1;j < x.len;++j)
211 if (address_diff(x.s + i,x.s + j))
212 break;
213 if (!stralloc_copys(&key,"+")) nomem();
214 if (!stralloc_catb(&key,x.s[i].location,2)) nomem();
215 if (!stralloc_catb(&key,x.s[i].name,x.s[i].namelen)) nomem();
216 if (!stralloc_copys(&result,"")) nomem();
217 while (i < j)
218 if (!stralloc_catb(&result,x.s[i++].ip,4)) nomem();
219 if (cdb_make_add(&cdb,key.s,key.len,result.s,result.len) == -1)
220 die_datatmp();
221 }
222
223 if (cdb_make_finish(&cdb) == -1) die_datatmp();
224 if (fsync(fdcdb) == -1) die_datatmp();
225 if (close(fdcdb) == -1) die_datatmp(); /* NFS stupidity */
226 if (rename("data.tmp","data.cdb") == -1)
227 strerr_die2sys(111,FATAL,"unable to move data.tmp to data.cdb: ");
228
229 _exit(0);
230}