chiark / gitweb /
src/types.c, regress/: Use checklabel hook to parse PTR query domains.
[adns.git] / regress / hplayback.c
1 #include <assert.h>
2 #include <string.h>
3 #include <errno.h>
4 #include <stdlib.h>
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <netinet/in.h>
8 #include <arpa/inet.h>
9 #include <sys/time.h>
10 #include <unistd.h>
11 #include <fcntl.h>
12 #include "harness.h"
13 static FILE *Tinputfile, *Treportfile;
14 static vbuf vb2;
15 extern void Tshutdown(void) {
16   adns__vbuf_free(&vb2);
17 }
18 static void Tensurereportfile(void) {
19   const char *fdstr;
20   int fd;
21   if (Treportfile) return;
22   Treportfile= stderr;
23   fdstr= getenv("ADNS_TEST_REPORT_FD"); if (!fdstr) return;
24   fd= atoi(fdstr);
25   Treportfile= fdopen(fd,"a"); if (!Treportfile) Tfailed("fdopen ADNS_TEST_REPORT_FD");
26 }
27 static void Psyntax(const char *where) {
28   fprintf(stderr,"adns test harness: syntax error in test log input file: %s\n",where);
29   exit(-1);
30 }
31 static void Pcheckinput(void) {
32   if (ferror(Tinputfile)) Tfailed("read test log input file");
33   if (feof(Tinputfile)) Psyntax("eof at syscall reply");
34 }
35 void Tensurerecordfile(void) {
36   const char *fdstr;
37   int fd;
38   int chars;
39   unsigned long sec, usec;
40   if (Tinputfile) return;
41   Tinputfile= stdin;
42   fdstr= getenv("ADNS_TEST_IN_FD");
43   if (fdstr) {
44     fd= atoi(fdstr);
45     Tinputfile= fdopen(fd,"r"); if (!Tinputfile) Tfailed("fdopen ADNS_TEST_IN_FD");
46   }
47   setvbuf(Tinputfile,0,_IONBF,0);
48   if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
49   fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
50   chars= -1;
51   sscanf(vb2.buf," start %lu.%lu%n",&sec,&usec,&chars);
52   if (chars==-1) Psyntax("start time invalid");
53   currenttime.tv_sec= sec;
54   currenttime.tv_usec= usec;
55   if (vb2.buf[chars] != '\n') Psyntax("not newline after start time");
56 }
57 static void Parg(const char *argname) {
58   int l;
59   if (vb2.buf[vb2.used++] != ' ') Psyntax("not a space before argument");
60   l= strlen(argname);
61   if (memcmp(vb2.buf+vb2.used,argname,l)) Psyntax("argument name wrong");
62   vb2.used+= l;
63   if (vb2.buf[vb2.used++] != '=') Psyntax("not = after argument name");
64 }
65 static int Pstring_maybe(const char *string) {
66   int l;
67   l= strlen(string);
68   if (memcmp(vb2.buf+vb2.used,string,l)) return 0;
69   vb2.used+= l;
70   return 1;
71 }
72 static void Pstring(const char *string, const char *emsg) {
73   if (Pstring_maybe(string)) return;
74   Psyntax(emsg);
75 }
76 static int Perrno(const char *stuff) {
77   const struct Terrno *te;
78   int r;
79   char *ep;
80   for (te= Terrnos; te->n && strcmp(te->n,stuff); te++);
81   if (te->n) return te->v;
82   r= strtoul(stuff+2,&ep,10);
83   if (*ep) Psyntax("errno value not recognised, not numeric");
84   return r;
85 }
86 static void P_updatetime(void) {
87   int chars;
88   unsigned long sec, usec;
89   if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
90   fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
91   chars= -1;
92   sscanf(vb2.buf," +%lu.%lu%n",&sec,&usec,&chars);
93   if (chars==-1) Psyntax("update time invalid");
94   currenttime.tv_sec+= sec;
95   currenttime.tv_usec+= usec;
96   if (currenttime.tv_usec > 1000000) {
97     currenttime.tv_sec++;
98     currenttime.tv_usec -= 1000000;
99   }
100   if (vb2.buf[chars] != '\n') Psyntax("not newline after update time");
101 }
102 static void Pfdset(fd_set *set, int max) {
103   int r, c;
104   char *ep;
105   if (vb2.buf[vb2.used++] != '[') Psyntax("fd set start not [");
106   FD_ZERO(set);
107   if (vb2.buf[vb2.used] == ']') { vb2.used++; return; }
108   for (;;) {
109     r= strtoul(vb2.buf+vb2.used,&ep,10);
110     if (r>=max) Psyntax("fd set member > max");
111     if (ep == (char*)vb2.buf+vb2.used) Psyntax("empty entry in fd set");
112     FD_SET(r,set);
113     vb2.used= ep - (char*)vb2.buf;
114     c= vb2.buf[vb2.used++];
115     if (c == ']') break;
116     if (c != ',') Psyntax("fd set separator not ,");
117   }
118 }
119 #ifdef HAVE_POLL
120 static int Ppollfdevents(void) {
121   int events;
122   if (Pstring_maybe("0")) return 0;
123   events= 0;
124   if (Pstring_maybe("POLLIN")) {
125     events |= POLLIN;
126     if (!Pstring_maybe("|")) return events;
127   }
128   if (Pstring_maybe("POLLOUT")) {
129     events |= POLLOUT;
130     if (!Pstring_maybe("|")) return events;
131   }
132   Pstring("POLLPRI","pollfdevents PRI?");
133   return events;
134 }
135 static void Ppollfds(struct pollfd *fds, int nfds) {
136   int i;
137   char *ep;
138   const char *comma= "";
139   if (vb2.buf[vb2.used++] != '[') Psyntax("pollfds start not [");
140   for (i=0; i<nfds; i++) {
141     Pstring("{fd=","{fd= in pollfds");
142     fds->fd= strtoul(vb2.buf+vb2.used,&ep,10);
143     vb2.used= ep - (char*)vb2.buf;    
144     Pstring(", events=",", events= in pollfds");
145     fds->events= Ppollfdevents();
146     Pstring(", revents=",", revents= in pollfds");
147     fds->revents= Ppollfdevents();
148     Pstring("}","} in pollfds");
149     Pstring(comma,"separator in pollfds");
150     comma= ", ";
151   }
152   if (vb2.buf[vb2.used++] != ']') Psyntax("pollfds end not ]");
153 }
154 #endif
155 static void Paddr(struct sockaddr *addr, int *lenr) {
156   struct sockaddr_in *sa= (struct sockaddr_in*)addr;
157   char *p, *ep;
158   long ul;
159   assert(*lenr >= sizeof(*sa));
160   p= strchr(vb2.buf+vb2.used,':');
161   if (!p) Psyntax("no port on address");
162   *p++= 0;
163   memset(sa,0,sizeof(*sa));
164   sa->sin_family= AF_INET;
165   if (!inet_aton(vb2.buf+vb2.used,&sa->sin_addr)) Psyntax("invalid address");
166   ul= strtoul(p,&ep,10);
167   if (*ep && *ep != ' ') Psyntax("invalid port (bad syntax)");
168   if (ul >= 65536) Psyntax("port too large");
169   sa->sin_port= htons(ul);
170   *lenr= sizeof(*sa);
171   vb2.used= ep - (char*)vb2.buf;
172 }
173 static int Pbytes(byte *buf, int maxlen) {
174   static const char hexdigits[]= "0123456789abcdef";
175   int c, v, done;
176   const char *pf;
177   done= 0;
178   for (;;) {
179     c= getc(Tinputfile); Pcheckinput();
180     if (c=='\n' || c==' ' || c=='\t') continue;
181     if (c=='.') break;
182     pf= strchr(hexdigits,c); if (!pf) Psyntax("invalid first hex digit");
183     v= (pf-hexdigits)<<4;
184     c= getc(Tinputfile); Pcheckinput();
185     pf= strchr(hexdigits,c); if (!pf) Psyntax("invalid second hex digit");
186     v |= (pf-hexdigits);
187     if (maxlen<=0) Psyntax("buffer overflow in bytes");
188     *buf++= v;
189     maxlen--; done++;
190   }
191   for (;;) {
192     c= getc(Tinputfile); Pcheckinput();
193     if (c=='\n') return done;
194   }
195 }
196 void Q_vb(void) {
197   const char *nl;
198   Tensurerecordfile();
199   if (!adns__vbuf_ensure(&vb2,vb.used+2)) Tnomem();
200   fread(vb2.buf,1,vb.used+2,Tinputfile);
201   if (feof(Tinputfile)) {
202     fprintf(stderr,"adns test harness: input ends prematurely; program did:\n %.*s\n",
203            vb.used,vb.buf);
204     exit(-1);
205   }
206   Pcheckinput();
207   if (vb2.buf[0] != ' ') Psyntax("not space before call");
208   if (memcmp(vb.buf,vb2.buf+1,vb.used) ||
209       vb2.buf[vb.used+1] != '\n') {
210     fprintf(stderr,
211             "adns test harness: program did unexpected:\n %.*s\n"
212             "was expecting:\n %.*s\n",
213             vb.used,vb.buf, vb.used,vb2.buf+1);
214     exit(1);
215   }
216   Tensurereportfile();
217   nl= memchr(vb.buf,'\n',vb.used);
218   fprintf(Treportfile," %.*s\n", (int)(nl ? nl - (const char*)vb.buf : vb.used), vb.buf);
219 }
220 int Hselect(    int max , fd_set *rfds , fd_set *wfds , fd_set *efds , struct timeval *to       ) {
221  int r, amtread;
222  char *ep;
223  Qselect(       max , rfds , wfds , efds , to   );
224  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
225  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
226  Tensurereportfile();
227  fprintf(Treportfile,"%s",vb2.buf);
228  amtread= strlen(vb2.buf);
229  if (amtread<=0 || vb2.buf[--amtread]!='\n')
230   Psyntax("badly formed line");
231  vb2.buf[amtread]= 0;
232  if (memcmp(vb2.buf," select=",8)) Psyntax("syscall reply mismatch");
233  if (vb2.buf[8] == 'E') {
234   int e;
235   e= Perrno(vb2.buf+8);
236   P_updatetime();
237   errno= e;
238   return -1;
239  }
240   r= strtoul(vb2.buf+8,&ep,10);
241   if (*ep && *ep!=' ') Psyntax("return value not E* or positive number");
242   vb2.used= ep - (char*)vb2.buf;
243         Parg("rfds"); Pfdset(rfds,max); 
244         Parg("wfds"); Pfdset(wfds,max); 
245         Parg("efds"); Pfdset(efds,max); 
246  assert(vb2.used <= amtread);
247  if (vb2.used != amtread) Psyntax("junk at end of line");
248  P_updatetime();
249  return r;
250 }
251 #ifdef HAVE_POLL
252 int Hpoll(      struct pollfd *fds , int nfds , int timeout     ) {
253  int r, amtread;
254  char *ep;
255  Qpoll( fds , nfds , timeout    );
256  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
257  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
258  Tensurereportfile();
259  fprintf(Treportfile,"%s",vb2.buf);
260  amtread= strlen(vb2.buf);
261  if (amtread<=0 || vb2.buf[--amtread]!='\n')
262   Psyntax("badly formed line");
263  vb2.buf[amtread]= 0;
264  if (memcmp(vb2.buf," poll=",6)) Psyntax("syscall reply mismatch");
265  if (vb2.buf[6] == 'E') {
266   int e;
267   e= Perrno(vb2.buf+6);
268   P_updatetime();
269   errno= e;
270   return -1;
271  }
272   r= strtoul(vb2.buf+6,&ep,10);
273   if (*ep && *ep!=' ') Psyntax("return value not E* or positive number");
274   vb2.used= ep - (char*)vb2.buf;
275         Parg("fds"); Ppollfds(fds,nfds); 
276  assert(vb2.used <= amtread);
277  if (vb2.used != amtread) Psyntax("junk at end of line");
278  P_updatetime();
279  return r;
280 }
281 #endif
282 int Hsocket(    int domain , int type , int protocol    ) {
283  int r, amtread;
284  char *ep;
285         Tmust("socket","domain",domain==AF_INET); 
286   Tmust("socket","type",type==SOCK_STREAM || type==SOCK_DGRAM); 
287  Qsocket(        type   );
288  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
289  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
290  Tensurereportfile();
291  fprintf(Treportfile,"%s",vb2.buf);
292  amtread= strlen(vb2.buf);
293  if (amtread<=0 || vb2.buf[--amtread]!='\n')
294   Psyntax("badly formed line");
295  vb2.buf[amtread]= 0;
296  if (memcmp(vb2.buf," socket=",8)) Psyntax("syscall reply mismatch");
297  if (vb2.buf[8] == 'E') {
298   int e;
299   e= Perrno(vb2.buf+8);
300   P_updatetime();
301   errno= e;
302   return -1;
303  }
304   r= strtoul(vb2.buf+8,&ep,10);
305   if (*ep && *ep!=' ') Psyntax("return value not E* or positive number");
306   vb2.used= ep - (char*)vb2.buf;
307  assert(vb2.used <= amtread);
308  if (vb2.used != amtread) Psyntax("junk at end of line");
309  P_updatetime();
310  return r;
311 }
312 int Hfcntl(     int fd , int cmd , ...  ) {
313  int r, amtread;
314         va_list al; long arg; 
315   Tmust("fcntl","cmd",cmd==F_SETFL || cmd==F_GETFL);
316   if (cmd == F_SETFL) {
317     va_start(al,cmd); arg= va_arg(al,long); va_end(al);
318   } else {
319     arg= 0;
320   } 
321  Qfcntl(        fd , cmd , arg  );
322  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
323  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
324  Tensurereportfile();
325  fprintf(Treportfile,"%s",vb2.buf);
326  amtread= strlen(vb2.buf);
327  if (amtread<=0 || vb2.buf[--amtread]!='\n')
328   Psyntax("badly formed line");
329  vb2.buf[amtread]= 0;
330  if (memcmp(vb2.buf," fcntl=",7)) Psyntax("syscall reply mismatch");
331  if (vb2.buf[7] == 'E') {
332   int e;
333   e= Perrno(vb2.buf+7);
334   P_updatetime();
335   errno= e;
336   return -1;
337  }
338   r= 0;
339   if (cmd == F_GETFL) {
340     if (!memcmp(vb2.buf+7,"O_NONBLOCK|...",14)) {
341       r= O_NONBLOCK;
342       vb2.used= 7+14;
343     } else if (!memcmp(vb2.buf+7,"~O_NONBLOCK&...",15)) {
344       vb2.used= 7+15;
345     } else {
346       Psyntax("fcntl flags not O_NONBLOCK|... or ~O_NONBLOCK&...");
347     }
348   } else if (cmd == F_SETFL) {
349   if (memcmp(vb2.buf+7,"OK",2)) Psyntax("success/fail not E* or OK");
350   vb2.used= 7+2;
351   r= 0;
352   } else {
353     Psyntax("fcntl not F_GETFL or F_SETFL");
354   }
355  assert(vb2.used <= amtread);
356  if (vb2.used != amtread) Psyntax("junk at end of line");
357  P_updatetime();
358  return r;
359 }
360 int Hconnect(   int fd , const struct sockaddr *addr , int addrlen      ) {
361  int r, amtread;
362  Qconnect(      fd , addr , addrlen     );
363  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
364  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
365  Tensurereportfile();
366  fprintf(Treportfile,"%s",vb2.buf);
367  amtread= strlen(vb2.buf);
368  if (amtread<=0 || vb2.buf[--amtread]!='\n')
369   Psyntax("badly formed line");
370  vb2.buf[amtread]= 0;
371  if (memcmp(vb2.buf," connect=",9)) Psyntax("syscall reply mismatch");
372  if (vb2.buf[9] == 'E') {
373   int e;
374   e= Perrno(vb2.buf+9);
375   P_updatetime();
376   errno= e;
377   return -1;
378  }
379   if (memcmp(vb2.buf+9,"OK",2)) Psyntax("success/fail not E* or OK");
380   vb2.used= 9+2;
381   r= 0;
382  assert(vb2.used <= amtread);
383  if (vb2.used != amtread) Psyntax("junk at end of line");
384  P_updatetime();
385  return r;
386 }
387 int Hbind(      int fd , const struct sockaddr *addr , int addrlen      ) {
388  int r, amtread;
389  Qbind( fd , addr , addrlen     );
390  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
391  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
392  Tensurereportfile();
393  fprintf(Treportfile,"%s",vb2.buf);
394  amtread= strlen(vb2.buf);
395  if (amtread<=0 || vb2.buf[--amtread]!='\n')
396   Psyntax("badly formed line");
397  vb2.buf[amtread]= 0;
398  if (memcmp(vb2.buf," bind=",6)) Psyntax("syscall reply mismatch");
399  if (vb2.buf[6] == 'E') {
400   int e;
401   e= Perrno(vb2.buf+6);
402   P_updatetime();
403   errno= e;
404   return -1;
405  }
406   if (memcmp(vb2.buf+6,"OK",2)) Psyntax("success/fail not E* or OK");
407   vb2.used= 6+2;
408   r= 0;
409  assert(vb2.used <= amtread);
410  if (vb2.used != amtread) Psyntax("junk at end of line");
411  P_updatetime();
412  return r;
413 }
414 int Hlisten(    int fd , int backlog    ) {
415  int r, amtread;
416  Qlisten(       fd , backlog    );
417  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
418  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
419  Tensurereportfile();
420  fprintf(Treportfile,"%s",vb2.buf);
421  amtread= strlen(vb2.buf);
422  if (amtread<=0 || vb2.buf[--amtread]!='\n')
423   Psyntax("badly formed line");
424  vb2.buf[amtread]= 0;
425  if (memcmp(vb2.buf," listen=",8)) Psyntax("syscall reply mismatch");
426  if (vb2.buf[8] == 'E') {
427   int e;
428   e= Perrno(vb2.buf+8);
429   P_updatetime();
430   errno= e;
431   return -1;
432  }
433   if (memcmp(vb2.buf+8,"OK",2)) Psyntax("success/fail not E* or OK");
434   vb2.used= 8+2;
435   r= 0;
436  assert(vb2.used <= amtread);
437  if (vb2.used != amtread) Psyntax("junk at end of line");
438  P_updatetime();
439  return r;
440 }
441 int Hclose(     int fd  ) {
442  int r, amtread;
443  Qclose(        fd      );
444  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
445  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
446  Tensurereportfile();
447  fprintf(Treportfile,"%s",vb2.buf);
448  amtread= strlen(vb2.buf);
449  if (amtread<=0 || vb2.buf[--amtread]!='\n')
450   Psyntax("badly formed line");
451  vb2.buf[amtread]= 0;
452  if (memcmp(vb2.buf," close=",7)) Psyntax("syscall reply mismatch");
453  if (vb2.buf[7] == 'E') {
454   int e;
455   e= Perrno(vb2.buf+7);
456   P_updatetime();
457   errno= e;
458   return -1;
459  }
460   if (memcmp(vb2.buf+7,"OK",2)) Psyntax("success/fail not E* or OK");
461   vb2.used= 7+2;
462   r= 0;
463  assert(vb2.used <= amtread);
464  if (vb2.used != amtread) Psyntax("junk at end of line");
465  P_updatetime();
466  return r;
467 }
468 int Hsendto(    int fd , const void *msg , int msglen , unsigned int flags , const struct sockaddr *addr , int addrlen  ) {
469  int r, amtread;
470  char *ep;
471         Tmust("sendto","flags",flags==0); 
472  Qsendto(       fd , msg , msglen , addr , addrlen      );
473  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
474  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
475  Tensurereportfile();
476  fprintf(Treportfile,"%s",vb2.buf);
477  amtread= strlen(vb2.buf);
478  if (amtread<=0 || vb2.buf[--amtread]!='\n')
479   Psyntax("badly formed line");
480  vb2.buf[amtread]= 0;
481  if (memcmp(vb2.buf," sendto=",8)) Psyntax("syscall reply mismatch");
482  if (vb2.buf[8] == 'E') {
483   int e;
484   e= Perrno(vb2.buf+8);
485   P_updatetime();
486   errno= e;
487   return -1;
488  }
489   r= strtoul(vb2.buf+8,&ep,10);
490   if (*ep && *ep!=' ') Psyntax("return value not E* or positive number");
491   vb2.used= ep - (char*)vb2.buf;
492  assert(vb2.used <= amtread);
493  if (vb2.used != amtread) Psyntax("junk at end of line");
494  P_updatetime();
495  return r;
496 }
497 int Hrecvfrom(  int fd , void *buf , int buflen , unsigned int flags , struct sockaddr *addr , int *addrlen     ) {
498  int r, amtread;
499         Tmust("recvfrom","flags",flags==0); 
500         Tmust("recvfrom","*addrlen",*addrlen>=sizeof(struct sockaddr_in)); 
501  Qrecvfrom(     fd , buflen , *addrlen  );
502  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
503  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
504  Tensurereportfile();
505  fprintf(Treportfile,"%s",vb2.buf);
506  amtread= strlen(vb2.buf);
507  if (amtread<=0 || vb2.buf[--amtread]!='\n')
508   Psyntax("badly formed line");
509  vb2.buf[amtread]= 0;
510  if (memcmp(vb2.buf," recvfrom=",10)) Psyntax("syscall reply mismatch");
511  if (vb2.buf[10] == 'E') {
512   int e;
513   e= Perrno(vb2.buf+10);
514   P_updatetime();
515   errno= e;
516   return -1;
517  }
518   if (memcmp(vb2.buf+10,"OK",2)) Psyntax("success/fail not E* or OK");
519   vb2.used= 10+2;
520   r= 0;
521         Parg("addr"); Paddr(addr,addrlen); 
522  assert(vb2.used <= amtread);
523  if (vb2.used != amtread) Psyntax("junk at end of line");
524         r= Pbytes(buf,buflen); 
525  P_updatetime();
526  return r;
527 }
528 int Hread(      int fd , void *buf , size_t buflen      ) {
529  int r, amtread;
530  Qread( fd , buflen     );
531  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
532  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
533  Tensurereportfile();
534  fprintf(Treportfile,"%s",vb2.buf);
535  amtread= strlen(vb2.buf);
536  if (amtread<=0 || vb2.buf[--amtread]!='\n')
537   Psyntax("badly formed line");
538  vb2.buf[amtread]= 0;
539  if (memcmp(vb2.buf," read=",6)) Psyntax("syscall reply mismatch");
540  if (vb2.buf[6] == 'E') {
541   int e;
542   e= Perrno(vb2.buf+6);
543   P_updatetime();
544   errno= e;
545   return -1;
546  }
547   if (memcmp(vb2.buf+6,"OK",2)) Psyntax("success/fail not E* or OK");
548   vb2.used= 6+2;
549   r= 0;
550  assert(vb2.used <= amtread);
551  if (vb2.used != amtread) Psyntax("junk at end of line");
552         r= Pbytes(buf,buflen); 
553  P_updatetime();
554  return r;
555 }
556 int Hwrite(     int fd , const void *buf , size_t len   ) {
557  int r, amtread;
558  char *ep;
559  Qwrite(        fd , buf , len  );
560  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
561  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
562  Tensurereportfile();
563  fprintf(Treportfile,"%s",vb2.buf);
564  amtread= strlen(vb2.buf);
565  if (amtread<=0 || vb2.buf[--amtread]!='\n')
566   Psyntax("badly formed line");
567  vb2.buf[amtread]= 0;
568  if (memcmp(vb2.buf," write=",7)) Psyntax("syscall reply mismatch");
569  if (vb2.buf[7] == 'E') {
570   int e;
571   e= Perrno(vb2.buf+7);
572   P_updatetime();
573   errno= e;
574   return -1;
575  }
576   r= strtoul(vb2.buf+7,&ep,10);
577   if (*ep && *ep!=' ') Psyntax("return value not E* or positive number");
578   vb2.used= ep - (char*)vb2.buf;
579  assert(vb2.used <= amtread);
580  if (vb2.used != amtread) Psyntax("junk at end of line");
581  P_updatetime();
582  return r;
583 }