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