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