release
[hcoop/zz_old/debian/djbdns.git] / pickdns-data.c
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
24 void nomem(void)
25 {
26 strerr_die2x(111,FATAL,"out of memory");
27 }
28
29 void 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
47 struct address {
48 char *name;
49 unsigned int namelen;
50 char ip[4];
51 char location[2];
52 } ;
53
54 int 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
66 void 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
95 GEN_ALLOC_typedef(address_alloc,struct address,s,len,a)
96 GEN_ALLOC_readyplus(address_alloc,struct address,s,len,a,i,n,x,30,address_alloc_readyplus)
97 GEN_ALLOC_append(address_alloc,struct address,s,len,a,i,n,x,30,address_alloc_readyplus,address_alloc_append)
98
99 static address_alloc x;
100
101 int fd;
102 buffer b;
103 char bspace[1024];
104
105 int fdcdb;
106 struct cdb_make cdb;
107 static stralloc key;
108 static stralloc result;
109
110 static stralloc line;
111 int match = 1;
112 unsigned long linenum = 0;
113
114 #define NUMFIELDS 3
115 static stralloc f[NUMFIELDS];
116
117 char strnum[FMT_ULONG];
118
119 void 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 }
124 void die_datatmp(void)
125 {
126 strerr_die2sys(111,FATAL,"unable to create data.tmp: ");
127 }
128
129 int 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 }