Commit | Line | Data |
---|---|---|
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 | ||
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 | } |