18 #define FATAL "tinydns-edit: fatal: "
21 #define TTL_POSITIVE 86400
28 strerr_die1x(100,"tinydns-edit: usage: tinydns-edit data data.new add [ns|childns|host|alias|mx] domain a.b.c.d");
32 strerr_die2x(111,FATAL
,"out of memory");
36 strerr_die4sys(100,FATAL
,"tinydns-edit: fatal: unable to read ",fn
,": ");
40 strerr_die4sys(100,FATAL
,"tinydns-edit: fatal: unable to write ",fnnew
,": ");
59 static stralloc f
[NUMFIELDS
];
65 char strnum
[FMT_ULONG
];
67 static char *names
[26];
70 void put(const char *buf
,unsigned int len
)
72 if (buffer_putalign(&bnew
,buf
,len
) == -1) die_write();
75 int main(int argc
,char **argv
)
84 if (!*argv
) die_usage();
86 if (!*++argv
) die_usage();
89 if (!*++argv
) die_usage();
92 if (!*++argv
) die_usage();
93 if (str_diff(*argv
,"add")) die_usage();
95 if (!*++argv
) die_usage();
96 if (str_equal(*argv
,"ns")) mode
= '.';
97 else if (str_equal(*argv
,"childns")) mode
= '&';
98 else if (str_equal(*argv
,"host")) mode
= '=';
99 else if (str_equal(*argv
,"alias")) mode
= '+';
100 else if (str_equal(*argv
,"mx")) mode
= '@';
103 if (!*++argv
) die_usage();
104 if (!dns_domain_fromdot(&target
,*argv
,str_len(*argv
))) nomem();
106 if (!*++argv
) die_usage();
107 if (!ip4_scan(*argv
,targetip
)) die_usage();
112 if (fd
== -1) die_read();
113 if (fstat(fd
,&st
) == -1) die_read();
114 buffer_init(&b
,buffer_unixread
,fd
,bspace
,sizeof bspace
);
116 fdnew
= open_trunc(fnnew
);
117 if (fdnew
== -1) die_write();
118 if (fchmod(fdnew
,st
.st_mode
& 0644) == -1) die_write();
119 buffer_init(&bnew
,buffer_unixwrite
,fdnew
,bnewspace
,sizeof bnewspace
);
124 for (i
= 0;i
< 26;++i
) {
126 if (!stralloc_copyb(&f
[0],&ch
,1)) nomem();
127 if (!stralloc_cats(&f
[0],".ns.")) nomem();
128 if (!dns_domain_todot_cat(&f
[0],target
)) nomem();
129 if (!dns_domain_fromdot(&names
[i
],f
[0].s
,f
[0].len
)) nomem();
137 for (i
= 0;i
< 26;++i
) {
139 if (!stralloc_copyb(&f
[0],&ch
,1)) nomem();
140 if (!stralloc_cats(&f
[0],".mx.")) nomem();
141 if (!dns_domain_todot_cat(&f
[0],target
)) nomem();
142 if (!dns_domain_fromdot(&names
[i
],f
[0].s
,f
[0].len
)) nomem();
148 if (getln(&b
,&line
,&match
,'\n') == -1) die_read();
150 put(line
.s
,line
.len
);
151 if (line
.len
&& !match
) put("\n",1);
154 ch
= line
.s
[line
.len
- 1];
155 if ((ch
!= ' ') && (ch
!= '\t') && (ch
!= '\n')) break;
158 if (!line
.len
) continue;
159 if (line
.s
[0] == '#') continue;
162 for (i
= 0;i
< NUMFIELDS
;++i
) {
164 if (!stralloc_copys(&f
[i
],"")) nomem();
167 k
= byte_chr(line
.s
+ j
,line
.len
- j
,':');
168 if (!stralloc_copyb(&f
[i
],line
.s
+ j
,k
)) nomem();
175 if (line
.s
[0] == mode
) {
176 if (!dns_domain_fromdot(&d1
,f
[0].s
,f
[0].len
)) nomem();
177 if (dns_domain_equal(d1
,target
)) {
178 if (byte_chr(f
[2].s
,f
[2].len
,'.') >= f
[2].len
) {
179 if (!stralloc_cats(&f
[2],".ns.")) nomem();
180 if (!stralloc_catb(&f
[2],f
[0].s
,f
[0].len
)) nomem();
182 if (!dns_domain_fromdot(&d2
,f
[2].s
,f
[2].len
)) nomem();
183 if (!stralloc_0(&f
[3])) nomem();
184 if (!scan_ulong(f
[3].s
,&ttl
)) ttl
= TTL_NS
;
185 for (i
= 0;i
< 26;++i
)
186 if (dns_domain_equal(d2
,names
[i
])) {
195 if (line
.s
[0] == '=') {
196 if (!dns_domain_fromdot(&d1
,f
[0].s
,f
[0].len
)) nomem();
197 if (dns_domain_equal(d1
,target
))
198 strerr_die2x(100,FATAL
,"host name already used");
199 if (!stralloc_0(&f
[1])) nomem();
200 if (ip4_scan(f
[1].s
,ip
))
201 if (byte_equal(ip
,4,targetip
))
202 strerr_die2x(100,FATAL
,"IP address already used");
207 if (line
.s
[0] == '@') {
208 if (!dns_domain_fromdot(&d1
,f
[0].s
,f
[0].len
)) nomem();
209 if (dns_domain_equal(d1
,target
)) {
210 if (byte_chr(f
[2].s
,f
[2].len
,'.') >= f
[2].len
) {
211 if (!stralloc_cats(&f
[2],".mx.")) nomem();
212 if (!stralloc_catb(&f
[2],f
[0].s
,f
[0].len
)) nomem();
214 if (!dns_domain_fromdot(&d2
,f
[2].s
,f
[2].len
)) nomem();
215 if (!stralloc_0(&f
[4])) nomem();
216 if (!scan_ulong(f
[4].s
,&ttl
)) ttl
= TTL_POSITIVE
;
217 for (i
= 0;i
< 26;++i
)
218 if (dns_domain_equal(d2
,names
[i
])) {
228 if (!stralloc_copyb(&f
[0],&mode
,1)) nomem();
229 if (!dns_domain_todot_cat(&f
[0],target
)) nomem();
230 if (!stralloc_cats(&f
[0],":")) nomem();
231 if (!stralloc_catb(&f
[0],ipstr
,ip4_fmt(ipstr
,targetip
))) nomem();
233 case '.': case '&': case '@':
234 for (i
= 0;i
< 26;++i
)
238 strerr_die2x(100,FATAL
,"too many records for that domain");
240 if (!stralloc_cats(&f
[0],":")) nomem();
241 if (!stralloc_catb(&f
[0],&ch
,1)) nomem();
243 if (!stralloc_cats(&f
[0],":")) nomem();
246 if (!stralloc_cats(&f
[0],":")) nomem();
247 if (!stralloc_catb(&f
[0],strnum
,fmt_ulong(strnum
,ttl
))) nomem();
248 if (!stralloc_cats(&f
[0],"\n")) nomem();
249 put(f
[0].s
,f
[0].len
);
251 if (buffer_flush(&bnew
) == -1) die_write();
252 if (fsync(fdnew
) == -1) die_write();
253 if (close(fdnew
) == -1) die_write(); /* NFS dorks */
254 if (rename(fnnew
,fn
) == -1)
255 strerr_die6sys(111,FATAL
,"unable to move ",fnnew
," to ",fn
,": ");