chiark / gitweb /
+ * Call Tensurerecordfile in Hgettimeofday (Tensurerecordfile was
[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   int r;
198   const char *nl;
199   Tensurerecordfile();
200   if (!adns__vbuf_ensure(&vb2,vb.used+2)) Tnomem();
201   r= fread(vb2.buf,1,vb.used+2,Tinputfile);
202   if (feof(Tinputfile)) {
203     fprintf(stderr,"adns test harness: input ends prematurely; program did:\n %.*s\n",
204            vb.used,vb.buf);
205     exit(-1);
206   }
207   Pcheckinput();
208   if (vb2.buf[0] != ' ') Psyntax("not space before call");
209   if (memcmp(vb.buf,vb2.buf+1,vb.used) ||
210       vb2.buf[vb.used+1] != '\n') {
211     fprintf(stderr,
212             "adns test harness: program did unexpected:\n %.*s\n"
213             "was expecting:\n %.*s\n",
214             vb.used,vb.buf, vb.used,vb2.buf+1);
215     exit(1);
216   }
217   Tensurereportfile();
218   nl= memchr(vb.buf,'\n',vb.used);
219   fprintf(Treportfile," %.*s\n", (int)(nl ? nl - (const char*)vb.buf : vb.used), vb.buf);
220 }
221 int Hselect(    int max , fd_set *rfds , fd_set *wfds , fd_set *efds , struct timeval *to       ) {
222  int r, amtread;
223  char *ep;
224  Qselect(       max , rfds , wfds , efds , to   );
225  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
226  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
227  Tensurereportfile();
228  fprintf(Treportfile,"%s",vb2.buf);
229  amtread= strlen(vb2.buf);
230  if (amtread<=0 || vb2.buf[--amtread]!='\n')
231   Psyntax("badly formed line");
232  vb2.buf[amtread]= 0;
233  if (memcmp(vb2.buf," select=",8)) Psyntax("syscall reply mismatch");
234  if (vb2.buf[8] == 'E') {
235   int e;
236   e= Perrno(vb2.buf+8);
237   P_updatetime();
238   errno= e;
239   return -1;
240  }
241   r= strtoul(vb2.buf+8,&ep,10);
242   if (*ep && *ep!=' ') Psyntax("return value not E* or positive number");
243   vb2.used= ep - (char*)vb2.buf;
244         Parg("rfds"); Pfdset(rfds,max); 
245         Parg("wfds"); Pfdset(wfds,max); 
246         Parg("efds"); Pfdset(efds,max); 
247  assert(vb2.used <= amtread);
248  if (vb2.used != amtread) Psyntax("junk at end of line");
249  P_updatetime();
250  return r;
251 }
252 #ifdef HAVE_POLL
253 int Hpoll(      struct pollfd *fds , int nfds , int timeout     ) {
254  int r, amtread;
255  char *ep;
256  Qpoll( fds , nfds , timeout    );
257  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
258  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
259  Tensurereportfile();
260  fprintf(Treportfile,"%s",vb2.buf);
261  amtread= strlen(vb2.buf);
262  if (amtread<=0 || vb2.buf[--amtread]!='\n')
263   Psyntax("badly formed line");
264  vb2.buf[amtread]= 0;
265  if (memcmp(vb2.buf," poll=",6)) Psyntax("syscall reply mismatch");
266  if (vb2.buf[6] == 'E') {
267   int e;
268   e= Perrno(vb2.buf+6);
269   P_updatetime();
270   errno= e;
271   return -1;
272  }
273   r= strtoul(vb2.buf+6,&ep,10);
274   if (*ep && *ep!=' ') Psyntax("return value not E* or positive number");
275   vb2.used= ep - (char*)vb2.buf;
276         Parg("fds"); Ppollfds(fds,nfds); 
277  assert(vb2.used <= amtread);
278  if (vb2.used != amtread) Psyntax("junk at end of line");
279  P_updatetime();
280  return r;
281 }
282 #endif
283 int Hsocket(    int domain , int type , int protocol    ) {
284  int r, amtread;
285  char *ep;
286         Tmust("socket","domain",domain==AF_INET); 
287   Tmust("socket","type",type==SOCK_STREAM || type==SOCK_DGRAM); 
288  Qsocket(        type   );
289  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
290  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
291  Tensurereportfile();
292  fprintf(Treportfile,"%s",vb2.buf);
293  amtread= strlen(vb2.buf);
294  if (amtread<=0 || vb2.buf[--amtread]!='\n')
295   Psyntax("badly formed line");
296  vb2.buf[amtread]= 0;
297  if (memcmp(vb2.buf," socket=",8)) Psyntax("syscall reply mismatch");
298  if (vb2.buf[8] == 'E') {
299   int e;
300   e= Perrno(vb2.buf+8);
301   P_updatetime();
302   errno= e;
303   return -1;
304  }
305   r= strtoul(vb2.buf+8,&ep,10);
306   if (*ep && *ep!=' ') Psyntax("return value not E* or positive number");
307   vb2.used= ep - (char*)vb2.buf;
308  assert(vb2.used <= amtread);
309  if (vb2.used != amtread) Psyntax("junk at end of line");
310  P_updatetime();
311  return r;
312 }
313 int Hfcntl(     int fd , int cmd , ...  ) {
314  int r, amtread;
315         va_list al; long arg; 
316   Tmust("fcntl","cmd",cmd==F_SETFL || cmd==F_GETFL);
317   if (cmd == F_SETFL) {
318     va_start(al,cmd); arg= va_arg(al,long); va_end(al);
319   } else {
320     arg= 0;
321   } 
322  Qfcntl(        fd , cmd , arg  );
323  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
324  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
325  Tensurereportfile();
326  fprintf(Treportfile,"%s",vb2.buf);
327  amtread= strlen(vb2.buf);
328  if (amtread<=0 || vb2.buf[--amtread]!='\n')
329   Psyntax("badly formed line");
330  vb2.buf[amtread]= 0;
331  if (memcmp(vb2.buf," fcntl=",7)) Psyntax("syscall reply mismatch");
332  if (vb2.buf[7] == 'E') {
333   int e;
334   e= Perrno(vb2.buf+7);
335   P_updatetime();
336   errno= e;
337   return -1;
338  }
339   r= 0;
340   if (cmd == F_GETFL) {
341     if (!memcmp(vb2.buf+7,"O_NONBLOCK|...",14)) {
342       r= O_NONBLOCK;
343       vb2.used= 7+14;
344     } else if (!memcmp(vb2.buf+7,"~O_NONBLOCK&...",15)) {
345       vb2.used= 7+15;
346     } else {
347       Psyntax("fcntl flags not O_NONBLOCK|... or ~O_NONBLOCK&...");
348     }
349   } else if (cmd == F_SETFL) {
350   if (memcmp(vb2.buf+7,"OK",2)) Psyntax("success/fail not E* or OK");
351   vb2.used= 7+2;
352   r= 0;
353   } else {
354     Psyntax("fcntl not F_GETFL or F_SETFL");
355   }
356  assert(vb2.used <= amtread);
357  if (vb2.used != amtread) Psyntax("junk at end of line");
358  P_updatetime();
359  return r;
360 }
361 int Hconnect(   int fd , const struct sockaddr *addr , int addrlen      ) {
362  int r, amtread;
363  Qconnect(      fd , addr , addrlen     );
364  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
365  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
366  Tensurereportfile();
367  fprintf(Treportfile,"%s",vb2.buf);
368  amtread= strlen(vb2.buf);
369  if (amtread<=0 || vb2.buf[--amtread]!='\n')
370   Psyntax("badly formed line");
371  vb2.buf[amtread]= 0;
372  if (memcmp(vb2.buf," connect=",9)) Psyntax("syscall reply mismatch");
373  if (vb2.buf[9] == 'E') {
374   int e;
375   e= Perrno(vb2.buf+9);
376   P_updatetime();
377   errno= e;
378   return -1;
379  }
380   if (memcmp(vb2.buf+9,"OK",2)) Psyntax("success/fail not E* or OK");
381   vb2.used= 9+2;
382   r= 0;
383  assert(vb2.used <= amtread);
384  if (vb2.used != amtread) Psyntax("junk at end of line");
385  P_updatetime();
386  return r;
387 }
388 int Hbind(      int fd , const struct sockaddr *addr , int addrlen      ) {
389  int r, amtread;
390  Qbind( fd , addr , addrlen     );
391  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
392  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
393  Tensurereportfile();
394  fprintf(Treportfile,"%s",vb2.buf);
395  amtread= strlen(vb2.buf);
396  if (amtread<=0 || vb2.buf[--amtread]!='\n')
397   Psyntax("badly formed line");
398  vb2.buf[amtread]= 0;
399  if (memcmp(vb2.buf," bind=",6)) Psyntax("syscall reply mismatch");
400  if (vb2.buf[6] == 'E') {
401   int e;
402   e= Perrno(vb2.buf+6);
403   P_updatetime();
404   errno= e;
405   return -1;
406  }
407   if (memcmp(vb2.buf+6,"OK",2)) Psyntax("success/fail not E* or OK");
408   vb2.used= 6+2;
409   r= 0;
410  assert(vb2.used <= amtread);
411  if (vb2.used != amtread) Psyntax("junk at end of line");
412  P_updatetime();
413  return r;
414 }
415 int Hlisten(    int fd , int backlog    ) {
416  int r, amtread;
417  Qlisten(       fd , backlog    );
418  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
419  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
420  Tensurereportfile();
421  fprintf(Treportfile,"%s",vb2.buf);
422  amtread= strlen(vb2.buf);
423  if (amtread<=0 || vb2.buf[--amtread]!='\n')
424   Psyntax("badly formed line");
425  vb2.buf[amtread]= 0;
426  if (memcmp(vb2.buf," listen=",8)) Psyntax("syscall reply mismatch");
427  if (vb2.buf[8] == 'E') {
428   int e;
429   e= Perrno(vb2.buf+8);
430   P_updatetime();
431   errno= e;
432   return -1;
433  }
434   if (memcmp(vb2.buf+8,"OK",2)) Psyntax("success/fail not E* or OK");
435   vb2.used= 8+2;
436   r= 0;
437  assert(vb2.used <= amtread);
438  if (vb2.used != amtread) Psyntax("junk at end of line");
439  P_updatetime();
440  return r;
441 }
442 int Hclose(     int fd  ) {
443  int r, amtread;
444  Qclose(        fd      );
445  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
446  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
447  Tensurereportfile();
448  fprintf(Treportfile,"%s",vb2.buf);
449  amtread= strlen(vb2.buf);
450  if (amtread<=0 || vb2.buf[--amtread]!='\n')
451   Psyntax("badly formed line");
452  vb2.buf[amtread]= 0;
453  if (memcmp(vb2.buf," close=",7)) Psyntax("syscall reply mismatch");
454  if (vb2.buf[7] == 'E') {
455   int e;
456   e= Perrno(vb2.buf+7);
457   P_updatetime();
458   errno= e;
459   return -1;
460  }
461   if (memcmp(vb2.buf+7,"OK",2)) Psyntax("success/fail not E* or OK");
462   vb2.used= 7+2;
463   r= 0;
464  assert(vb2.used <= amtread);
465  if (vb2.used != amtread) Psyntax("junk at end of line");
466  P_updatetime();
467  return r;
468 }
469 int Hsendto(    int fd , const void *msg , int msglen , unsigned int flags , const struct sockaddr *addr , int addrlen  ) {
470  int r, amtread;
471  char *ep;
472         Tmust("sendto","flags",flags==0); 
473  Qsendto(       fd , msg , msglen , addr , addrlen      );
474  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
475  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
476  Tensurereportfile();
477  fprintf(Treportfile,"%s",vb2.buf);
478  amtread= strlen(vb2.buf);
479  if (amtread<=0 || vb2.buf[--amtread]!='\n')
480   Psyntax("badly formed line");
481  vb2.buf[amtread]= 0;
482  if (memcmp(vb2.buf," sendto=",8)) Psyntax("syscall reply mismatch");
483  if (vb2.buf[8] == 'E') {
484   int e;
485   e= Perrno(vb2.buf+8);
486   P_updatetime();
487   errno= e;
488   return -1;
489  }
490   r= strtoul(vb2.buf+8,&ep,10);
491   if (*ep && *ep!=' ') Psyntax("return value not E* or positive number");
492   vb2.used= ep - (char*)vb2.buf;
493  assert(vb2.used <= amtread);
494  if (vb2.used != amtread) Psyntax("junk at end of line");
495  P_updatetime();
496  return r;
497 }
498 int Hrecvfrom(  int fd , void *buf , int buflen , unsigned int flags , struct sockaddr *addr , int *addrlen     ) {
499  int r, amtread;
500         Tmust("recvfrom","flags",flags==0); 
501         Tmust("recvfrom","*addrlen",*addrlen>=sizeof(struct sockaddr_in)); 
502  Qrecvfrom(     fd , buflen , *addrlen  );
503  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
504  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
505  Tensurereportfile();
506  fprintf(Treportfile,"%s",vb2.buf);
507  amtread= strlen(vb2.buf);
508  if (amtread<=0 || vb2.buf[--amtread]!='\n')
509   Psyntax("badly formed line");
510  vb2.buf[amtread]= 0;
511  if (memcmp(vb2.buf," recvfrom=",10)) Psyntax("syscall reply mismatch");
512  if (vb2.buf[10] == 'E') {
513   int e;
514   e= Perrno(vb2.buf+10);
515   P_updatetime();
516   errno= e;
517   return -1;
518  }
519   if (memcmp(vb2.buf+10,"OK",2)) Psyntax("success/fail not E* or OK");
520   vb2.used= 10+2;
521   r= 0;
522         Parg("addr"); Paddr(addr,addrlen); 
523  assert(vb2.used <= amtread);
524  if (vb2.used != amtread) Psyntax("junk at end of line");
525         r= Pbytes(buf,buflen); 
526  P_updatetime();
527  return r;
528 }
529 int Hread(      int fd , void *buf , size_t buflen      ) {
530  int r, amtread;
531  Qread( fd , buflen     );
532  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
533  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
534  Tensurereportfile();
535  fprintf(Treportfile,"%s",vb2.buf);
536  amtread= strlen(vb2.buf);
537  if (amtread<=0 || vb2.buf[--amtread]!='\n')
538   Psyntax("badly formed line");
539  vb2.buf[amtread]= 0;
540  if (memcmp(vb2.buf," read=",6)) Psyntax("syscall reply mismatch");
541  if (vb2.buf[6] == 'E') {
542   int e;
543   e= Perrno(vb2.buf+6);
544   P_updatetime();
545   errno= e;
546   return -1;
547  }
548   if (memcmp(vb2.buf+6,"OK",2)) Psyntax("success/fail not E* or OK");
549   vb2.used= 6+2;
550   r= 0;
551  assert(vb2.used <= amtread);
552  if (vb2.used != amtread) Psyntax("junk at end of line");
553         r= Pbytes(buf,buflen); 
554  P_updatetime();
555  return r;
556 }
557 int Hwrite(     int fd , const void *buf , size_t len   ) {
558  int r, amtread;
559  char *ep;
560  Qwrite(        fd , buf , len  );
561  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
562  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
563  Tensurereportfile();
564  fprintf(Treportfile,"%s",vb2.buf);
565  amtread= strlen(vb2.buf);
566  if (amtread<=0 || vb2.buf[--amtread]!='\n')
567   Psyntax("badly formed line");
568  vb2.buf[amtread]= 0;
569  if (memcmp(vb2.buf," write=",7)) Psyntax("syscall reply mismatch");
570  if (vb2.buf[7] == 'E') {
571   int e;
572   e= Perrno(vb2.buf+7);
573   P_updatetime();
574   errno= e;
575   return -1;
576  }
577   r= strtoul(vb2.buf+7,&ep,10);
578   if (*ep && *ep!=' ') Psyntax("return value not E* or positive number");
579   vb2.used= ep - (char*)vb2.buf;
580  assert(vb2.used <= amtread);
581  if (vb2.used != amtread) Psyntax("junk at end of line");
582  P_updatetime();
583  return r;
584 }