Postfix3.3.1
vstream.c
[詳解]
1 /*++
2 /* NAME
3 /* vstream 3
4 /* SUMMARY
5 /* light-weight buffered I/O package
6 /* SYNOPSIS
7 /* #include <vstream.h>
8 /*
9 /* VSTREAM *vstream_fopen(path, flags, mode)
10 /* const char *path;
11 /* int flags;
12 /* mode_t mode;
13 /*
14 /* VSTREAM *vstream_fdopen(fd, flags)
15 /* int fd;
16 /* int flags;
17 /*
18 /* int vstream_fclose(stream)
19 /* VSTREAM *stream;
20 /*
21 /* int vstream_fdclose(stream)
22 /* VSTREAM *stream;
23 /*
24 /* VSTREAM *vstream_printf(format, ...)
25 /* const char *format;
26 /*
27 /* VSTREAM *vstream_fprintf(stream, format, ...)
28 /* VSTREAM *stream;
29 /* const char *format;
30 /*
31 /* int VSTREAM_GETC(stream)
32 /* VSTREAM *stream;
33 /*
34 /* int VSTREAM_PUTC(ch, stream)
35 /* int ch;
36 /*
37 /* int VSTREAM_GETCHAR(void)
38 /*
39 /* int VSTREAM_PUTCHAR(ch)
40 /* int ch;
41 /*
42 /* int vstream_ungetc(stream, ch)
43 /* VSTREAM *stream;
44 /* int ch;
45 /*
46 /* int vstream_fputs(str, stream)
47 /* const char *str;
48 /* VSTREAM *stream;
49 /*
50 /* off_t vstream_ftell(stream)
51 /* VSTREAM *stream;
52 /*
53 /* off_t vstream_fseek(stream, offset, whence)
54 /* VSTREAM *stream;
55 /* off_t offset;
56 /* int whence;
57 /*
58 /* int vstream_fflush(stream)
59 /* VSTREAM *stream;
60 /*
61 /* int vstream_fpurge(stream, direction)
62 /* VSTREAM *stream;
63 /* int direction;
64 /*
65 /* ssize_t vstream_fread(stream, buf, len)
66 /* VSTREAM *stream;
67 /* void *buf;
68 /* ssize_t len;
69 /*
70 /* ssize_t vstream_fwrite(stream, buf, len)
71 /* VSTREAM *stream;
72 /* const void *buf;
73 /* ssize_t len;
74 /*
75 /* void vstream_control(stream, name, ...)
76 /* VSTREAM *stream;
77 /* int name;
78 /*
79 /* int vstream_fileno(stream)
80 /* VSTREAM *stream;
81 /*
82 /* const ssize_t vstream_req_bufsize(stream)
83 /* VSTREAM *stream;
84 /*
85 /* void *vstream_context(stream)
86 /* VSTREAM *stream;
87 /*
88 /* int vstream_ferror(stream)
89 /* VSTREAM *stream;
90 /*
91 /* int vstream_ftimeout(stream)
92 /* VSTREAM *stream;
93 /*
94 /* int vstream_feof(stream)
95 /* VSTREAM *stream;
96 /*
97 /* int vstream_clearerr(stream)
98 /* VSTREAM *stream;
99 /*
100 /* const char *VSTREAM_PATH(stream)
101 /* VSTREAM *stream;
102 /*
103 /* char *vstream_vprintf(format, ap)
104 /* const char *format;
105 /* va_list *ap;
106 /*
107 /* char *vstream_vfprintf(stream, format, ap)
108 /* VSTREAM *stream;
109 /* const char *format;
110 /* va_list *ap;
111 /*
112 /* ssize_t vstream_bufstat(stream, command)
113 /* VSTREAM *stream;
114 /* int command;
115 /*
116 /* ssize_t vstream_peek(stream)
117 /* VSTREAM *stream;
118 /*
119 /* const char *vstream_peek_data(stream)
120 /* VSTREAM *stream;
121 /*
122 /* int vstream_setjmp(stream)
123 /* VSTREAM *stream;
124 /*
125 /* void vstream_longjmp(stream, val)
126 /* VSTREAM *stream;
127 /* int val;
128 /*
129 /* time_t vstream_ftime(stream)
130 /* VSTREAM *stream;
131 /*
132 /* struct timeval vstream_ftimeval(stream)
133 /* VSTREAM *stream;
134 /*
135 /* int vstream_rd_error(stream)
136 /* VSTREAM *stream;
137 /*
138 /* int vstream_wr_error(stream)
139 /* VSTREAM *stream;
140 /*
141 /* int vstream_rd_timeout(stream)
142 /* VSTREAM *stream;
143 /*
144 /* int vstream_wr_timeout(stream)
145 /* VSTREAM *stream;
146 /*
147 /* int vstream_fstat(stream, flags)
148 /* VSTREAM *stream;
149 /* int flags;
150 /* DESCRIPTION
151 /* The \fIvstream\fR module implements light-weight buffered I/O
152 /* similar to the standard I/O routines.
153 /*
154 /* The interface is implemented in terms of VSTREAM structure
155 /* pointers, also called streams. For convenience, three streams
156 /* are predefined: VSTREAM_IN, VSTREAM_OUT, and VSTREAM_ERR. These
157 /* streams are connected to the standard input, output and error
158 /* file descriptors, respectively.
159 /*
160 /* Although the interface is patterned after the standard I/O
161 /* library, there are some major differences:
162 /* .IP \(bu
163 /* File descriptors are not limited to the range 0..255. This
164 /* was reason #1 to write these routines in the first place.
165 /* .IP \(bu
166 /* The application can switch between reading and writing on
167 /* the same stream without having to perform a flush or seek
168 /* operation, and can change write position without having to
169 /* flush. This was reason #2. Upon position or direction change,
170 /* unread input is discarded, and unwritten output is flushed
171 /* automatically. Exception: with double-buffered streams, unread
172 /* input is not discarded upon change of I/O direction, and
173 /* output flushing is delayed until the read buffer must be refilled.
174 /* .IP \(bu
175 /* A bidirectional stream can read and write with the same buffer
176 /* and file descriptor, or it can have separate read/write
177 /* buffers and/or file descriptors.
178 /* .IP \(bu
179 /* No automatic flushing of VSTREAM_OUT upon program exit, or of
180 /* VSTREAM_ERR at any time. No unbuffered or line buffered modes.
181 /* This functionality may be added when it is really needed.
182 /* .PP
183 /* vstream_fopen() opens the named file and associates a buffered
184 /* stream with it. The \fIpath\fR, \fIflags\fR and \fImode\fR
185 /* arguments are passed on to the open(2) routine. The result is
186 /* a null pointer in case of problems. The \fIpath\fR argument is
187 /* copied and can be looked up with VSTREAM_PATH().
188 /*
189 /* vstream_fdopen() takes an open file and associates a buffered
190 /* stream with it. The \fIflags\fR argument specifies how the file
191 /* was opened. vstream_fdopen() either succeeds or never returns.
192 /*
193 /* vstream_fclose() closes the named buffered stream. The result
194 /* is 0 in case of success, VSTREAM_EOF in case of problems.
195 /* vstream_fclose() reports the same errors as vstream_ferror().
196 /*
197 /* vstream_fdclose() leaves the file(s) open but is otherwise
198 /* identical to vstream_fclose().
199 /*
200 /* vstream_fprintf() formats its arguments according to the
201 /* \fIformat\fR argument and writes the result to the named stream.
202 /* The result is the stream argument. It understands the s, c, d, u,
203 /* o, x, X, e, f and g format types, the l modifier, field width and
204 /* precision, sign, and padding with zeros or spaces. In addition,
205 /* vstream_fprintf() recognizes the %m format specifier and expands
206 /* it to the error message corresponding to the current value of the
207 /* global \fIerrno\fR variable.
208 /*
209 /* vstream_printf() performs formatted output to the standard output
210 /* stream.
211 /*
212 /* VSTREAM_GETC() reads the next character from the named stream.
213 /* The result is VSTREAM_EOF when end-of-file is reached or if a read
214 /* error was detected. VSTREAM_GETC() is an unsafe macro that
215 /* evaluates some arguments more than once.
216 /*
217 /* VSTREAM_GETCHAR() is an alias for VSTREAM_GETC(VSTREAM_IN).
218 /*
219 /* VSTREAM_PUTC() appends the specified character to the specified
220 /* stream. The result is the stored character, or VSTREAM_EOF in
221 /* case of problems. VSTREAM_PUTC() is an unsafe macro that
222 /* evaluates some arguments more than once.
223 /*
224 /* VSTREAM_PUTCHAR(c) is an alias for VSTREAM_PUTC(c, VSTREAM_OUT).
225 /*
226 /* vstream_ungetc() pushes back a character onto the specified stream
227 /* and returns the character, or VSTREAM_EOF in case of problems.
228 /* It is an error to push back before reading (or immediately after
229 /* changing the stream offset via vstream_fseek()). Upon successful
230 /* return, vstream_ungetc() clears the end-of-file stream flag.
231 /*
232 /* vstream_fputs() appends the given null-terminated string to the
233 /* specified buffered stream. The result is 0 in case of success,
234 /* VSTREAM_EOF in case of problems.
235 /*
236 /* vstream_ftell() returns the file offset for the specified stream,
237 /* -1 if the stream is connected to a non-seekable file.
238 /*
239 /* vstream_fseek() changes the file position for the next read or write
240 /* operation. Unwritten output is flushed. With unidirectional streams,
241 /* unread input is discarded. The \fIoffset\fR argument specifies the file
242 /* position from the beginning of the file (\fIwhence\fR is SEEK_SET),
243 /* from the current file position (\fIwhence\fR is SEEK_CUR), or from
244 /* the file end (SEEK_END). The result value is the file offset
245 /* from the beginning of the file, -1 in case of problems.
246 /*
247 /* vstream_fflush() flushes unwritten data to a file that was
248 /* opened in read-write or write-only mode.
249 /* vstream_fflush() returns 0 in case of success, VSTREAM_EOF in
250 /* case of problems. It is an error to flush a read-only stream.
251 /* vstream_fflush() reports the same errors as vstream_ferror().
252 /*
253 /* vstream_fpurge() discards the contents of the stream buffer.
254 /* If direction is VSTREAM_PURGE_READ, it discards unread data,
255 /* else if direction is VSTREAM_PURGE_WRITE, it discards unwritten
256 /* data. In the case of a double-buffered stream, if direction is
257 /* VSTREAM_PURGE_BOTH, it discards the content of both the read
258 /* and write buffers. vstream_fpurge() returns 0 in case of success,
259 /* VSTREAM_EOF in case of problems.
260 /*
261 /* vstream_fread() and vstream_fwrite() perform unformatted I/O
262 /* on the named stream. The result value is the number of bytes
263 /* transferred. A short count is returned in case of end-of-file
264 /* or error conditions.
265 /*
266 /* vstream_control() allows the user to fine tune the behavior of
267 /* the specified stream. The arguments are a list of macros with
268 /* zero or more arguments, terminated with CA_VSTREAM_CTL_END
269 /* which has none. The following lists the names and the types
270 /* of the corresponding value arguments.
271 /* .IP "CA_VSTREAM_CTL_READ_FN(ssize_t (*)(int, void *, size_t, int, void *))"
272 /* The argument specifies an alternative for the timed_read(3) function,
273 /* for example, a read function that performs decryption.
274 /* This function receives as arguments a file descriptor, buffer pointer,
275 /* buffer length, timeout value, and the VSTREAM's context value.
276 /* A timeout value <= 0 disables the time limit.
277 /* This function should return the positive number of bytes transferred,
278 /* 0 upon EOF, and -1 upon error with errno set appropriately.
279 /* .IP "CA_VSTREAM_CTL_WRITE_FN(ssize_t (*)(int, void *, size_t, int, void *))"
280 /* The argument specifies an alternative for the timed_write(3) function,
281 /* for example, a write function that performs encryption.
282 /* This function receives as arguments a file descriptor, buffer pointer,
283 /* buffer length, timeout value, and the VSTREAM's context value.
284 /* A timeout value <= 0 disables the time limit.
285 /* This function should return the positive number of bytes transferred,
286 /* and -1 upon error with errno set appropriately. Instead of -1 it may
287 /* also return 0, e.g., upon remote party-initiated protocol shutdown.
288 /* .IP "CA_VSTREAM_CTL_CONTEXT(void *)"
289 /* The argument specifies application context that is passed on to
290 /* the application-specified read/write routines. No copy is made.
291 /* .IP "CA_VSTREAM_CTL_PATH(const char *)"
292 /* Updates the stored pathname of the specified stream. The pathname
293 /* is copied.
294 /* .IP "CA_VSTREAM_CTL_DOUBLE (no arguments)"
295 /* Use separate buffers for reading and for writing. This prevents
296 /* unread input from being discarded upon change of I/O direction.
297 /* .IP "CA_VSTREAM_CTL_READ_FD(int)"
298 /* The argument specifies the file descriptor to be used for reading.
299 /* This feature is limited to double-buffered streams, and makes the
300 /* stream non-seekable.
301 /* .IP "CA_VSTREAM_CTL_WRITE_FD(int)"
302 /* The argument specifies the file descriptor to be used for writing.
303 /* This feature is limited to double-buffered streams, and makes the
304 /* stream non-seekable.
305 /* .IP "CA_VSTREAM_CTL_SWAP_FD(VSTREAM *)"
306 /* The argument specifies a VSTREAM pointer; the request swaps the
307 /* file descriptor members of the two streams. This feature is limited
308 /* to streams that are both double-buffered or both single-buffered.
309 /* .IP "CA_VSTREAM_CTL_DUPFD(int)"
310 /* The argument specifies a minimum file descriptor value. If
311 /* the actual stream's file descriptors are below the minimum,
312 /* reallocate the descriptors to the first free value greater
313 /* than or equal to the minimum. The VSTREAM_CTL_DUPFD macro
314 /* is defined only on systems with fcntl() F_DUPFD support.
315 /* .IP "CA_VSTREAM_CTL_WAITPID_FN(int (*)(pid_t, WAIT_STATUS_T *, int))"
316 /* A pointer to function that behaves like waitpid(). This information
317 /* is used by the vstream_pclose() routine.
318 /* .IP "CA_VSTREAM_CTL_TIMEOUT(int)"
319 /* The deadline for a descriptor to become readable in case of a read
320 /* request, or writable in case of a write request. Specify a value
321 /* of 0 to disable deadlines.
322 /* .IP "CA_VSTREAM_CTL_EXCEPT (no arguments)"
323 /* Enable exception handling with vstream_setjmp() and vstream_longjmp().
324 /* This involves allocation of additional memory that normally isn't
325 /* used.
326 /* .IP "CA_VSTREAM_CTL_BUFSIZE(ssize_t)"
327 /* Specify a non-default buffer size for the next read(2) or
328 /* write(2) operation, or zero to implement a no-op. Requests
329 /* to reduce the buffer size are silently ignored (i.e. any
330 /* positive value <= vstream_req_bufsize()). To get a buffer
331 /* size smaller than VSTREAM_BUFSIZE, make the VSTREAM_CTL_BUFSIZE
332 /* request before the first stream read or write operation
333 /* (i.e., vstream_req_bufsize() returns zero). Requests to
334 /* change a fixed-size buffer (i.e., VSTREAM_ERR) are not
335 /* allowed.
336 /*
337 /* NOTE: the vstream_*printf() routines may silently expand a
338 /* buffer, so that the result of some %letter specifiers can
339 /* be written to contiguous memory.
340 /* .IP CA_VSTREAM_CTL_START_DEADLINE (no arguments)
341 /* Change the VSTREAM_CTL_TIMEOUT behavior, to limit the total
342 /* time for all subsequent file descriptor read or write
343 /* operations, and recharge the deadline timer.
344 /* .IP CA_VSTREAM_CTL_STOP_DEADLINE (no arguments)
345 /* Revert VSTREAM_CTL_TIMEOUT behavior to the default, i.e.
346 /* a time limit for individual file descriptor read or write
347 /* operations.
348 /* .PP
349 /* vstream_fileno() gives access to the file handle associated with
350 /* a buffered stream. With streams that have separate read/write
351 /* file descriptors, the result is the current descriptor.
352 /*
353 /* vstream_req_bufsize() returns the buffer size that will be
354 /* used for the next read(2) or write(2) operation on the named
355 /* stream. A zero result means that the next read(2) or write(2)
356 /* operation will use the default buffer size (VSTREAM_BUFSIZE).
357 /*
358 /* vstream_context() returns the application context that is passed on to
359 /* the application-specified read/write routines.
360 /*
361 /* VSTREAM_PATH() is an unsafe macro that returns the name stored
362 /* with vstream_fopen() or with vstream_control(). The macro is
363 /* unsafe because it evaluates some arguments more than once.
364 /*
365 /* vstream_feof() returns non-zero when a previous operation on the
366 /* specified stream caused an end-of-file condition.
367 /* Although further read requests after EOF may complete
368 /* successfully, vstream_feof() will keep returning non-zero
369 /* until vstream_clearerr() is called for that stream.
370 /*
371 /* vstream_ferror() returns non-zero when a previous operation on the
372 /* specified stream caused a non-EOF error condition, including timeout.
373 /* After a non-EOF error on a stream, no I/O request will
374 /* complete until after vstream_clearerr() is called for that stream.
375 /*
376 /* vstream_ftimeout() returns non-zero when a previous operation on the
377 /* specified stream caused a timeout error condition. See
378 /* vstream_ferror() for error persistence details.
379 /*
380 /* vstream_clearerr() resets the timeout, error and end-of-file indication
381 /* of the specified stream, and returns no useful result.
382 /*
383 /* vstream_vfprintf() provides an alternate interface
384 /* for formatting an argument list according to a format string.
385 /*
386 /* vstream_vprintf() provides a similar alternative interface.
387 /*
388 /* vstream_bufstat() provides input and output buffer status
389 /* information. The command is one of the following:
390 /* .IP VSTREAM_BST_IN_PEND
391 /* Return the number of characters that can be read without
392 /* refilling the read buffer.
393 /* .IP VSTREAM_BST_OUT_PEND
394 /* Return the number of characters that are waiting in the
395 /* write buffer.
396 /* .PP
397 /* vstream_peek() returns the number of characters that can be
398 /* read from the named stream without refilling the read buffer.
399 /* This is an alias for vstream_bufstat(stream, VSTREAM_BST_IN_PEND).
400 /*
401 /* vstream_peek_data() returns a pointer to the unread bytes
402 /* that exist according to vstream_peek(), or null if no unread
403 /* bytes are available.
404 /*
405 /* vstream_setjmp() saves processing context and makes that context
406 /* available for use with vstream_longjmp(). Normally, vstream_setjmp()
407 /* returns zero. A non-zero result means that vstream_setjmp() returned
408 /* through a vstream_longjmp() call; the result is the \fIval\fR argument
409 /* given to vstream_longjmp().
410 /*
411 /* NB: non-local jumps such as vstream_longjmp() are not safe
412 /* for jumping out of any routine that manipulates VSTREAM data.
413 /* longjmp() like calls are best avoided in signal handlers.
414 /*
415 /* vstream_ftime() returns the time of initialization, the last buffer
416 /* fill operation, or the last buffer flush operation for the specified
417 /* stream. This information is maintained only when stream timeouts are
418 /* enabled.
419 /*
420 /* vstream_ftimeval() is like vstream_ftime() but returns more
421 /* detail.
422 /*
423 /* vstream_rd_mumble() and vstream_wr_mumble() report on
424 /* read and write error conditions, respectively.
425 /*
426 /* vstream_fstat() queries stream status information about
427 /* user-requested features. The \fIflags\fR argument is the
428 /* bitwise OR of one or more of the following, and the result
429 /* value is the bitwise OR of the features that are activated.
430 /* .IP VSTREAM_FLAG_DEADLINE
431 /* The deadline feature is activated.
432 /* .IP VSTREAM_FLAG_DOUBLE
433 /* The double-buffering feature is activated.
434 /* DIAGNOSTICS
435 /* Panics: interface violations. Fatal errors: out of memory.
436 /* SEE ALSO
437 /* timed_read(3) default read routine
438 /* timed_write(3) default write routine
439 /* vbuf_print(3) formatting engine
440 /* setjmp(3) non-local jumps
441 /* BUGS
442 /* Should use mmap() on reasonable systems.
443 /* LICENSE
444 /* .ad
445 /* .fi
446 /* The Secure Mailer license must be distributed with this software.
447 /* AUTHOR(S)
448 /* Wietse Venema
449 /* IBM T.J. Watson Research
450 /* P.O. Box 704
451 /* Yorktown Heights, NY 10598, USA
452 /*
453 /* Wietse Venema
454 /* Google, Inc.
455 /* 111 8th Avenue
456 /* New York, NY 10011, USA
457 /*--*/
458 
459 /* System library. */
460 
461 #include <sys_defs.h>
462 #include <stdlib.h> /* 44BSD stdarg.h uses abort() */
463 #include <stdarg.h>
464 #include <stddef.h>
465 #include <unistd.h>
466 #include <fcntl.h>
467 #include <time.h>
468 #include <errno.h>
469 #include <string.h>
470 
471 /* Utility library. */
472 
473 #include "mymalloc.h"
474 #include "msg.h"
475 #include "vbuf_print.h"
476 #include "iostuff.h"
477 #include "vstring.h"
478 #include "vstream.h"
479 
480 /* Application-specific. */
481 
482  /*
483  * Forward declarations.
484  */
485 static int vstream_buf_get_ready(VBUF *);
486 static int vstream_buf_put_ready(VBUF *);
487 static int vstream_buf_space(VBUF *, ssize_t);
488 
489  /*
490  * Initialization of the three pre-defined streams. Pre-allocate a static
491  * I/O buffer for the standard error stream, so that the error handler can
492  * produce a diagnostic even when memory allocation fails.
493  */
494 static unsigned char vstream_fstd_buf[VSTREAM_BUFSIZE];
495 
497  {{
498  0, /* flags */
499  0, 0, 0, 0, /* buffer */
500  vstream_buf_get_ready, vstream_buf_put_ready, vstream_buf_space,
501  }, STDIN_FILENO, (VSTREAM_RW_FN) timed_read, (VSTREAM_RW_FN) timed_write,
502  0,},
503  {{
504  0, /* flags */
505  0, 0, 0, 0, /* buffer */
506  vstream_buf_get_ready, vstream_buf_put_ready, vstream_buf_space,
507  }, STDOUT_FILENO, (VSTREAM_RW_FN) timed_read, (VSTREAM_RW_FN) timed_write,
508  0,},
509  {{
511  vstream_fstd_buf, VSTREAM_BUFSIZE, VSTREAM_BUFSIZE, vstream_fstd_buf,
512  vstream_buf_get_ready, vstream_buf_put_ready, vstream_buf_space,
513  }, STDERR_FILENO, (VSTREAM_RW_FN) timed_read, (VSTREAM_RW_FN) timed_write,
514  VSTREAM_BUFSIZE,},
515 };
516 
517 #define VSTREAM_STATIC(v) ((v) >= VSTREAM_IN && (v) <= VSTREAM_ERR)
518 
519  /*
520  * A bunch of macros to make some expressions more readable. XXX We're
521  * assuming that O_RDONLY == 0, O_WRONLY == 1, O_RDWR == 2.
522  */
523 #define VSTREAM_ACC_MASK(f) ((f) & (O_APPEND | O_WRONLY | O_RDWR))
524 
525 #define VSTREAM_CAN_READ(f) (VSTREAM_ACC_MASK(f) == O_RDONLY \
526  || VSTREAM_ACC_MASK(f) == O_RDWR)
527 #define VSTREAM_CAN_WRITE(f) (VSTREAM_ACC_MASK(f) & O_WRONLY \
528  || VSTREAM_ACC_MASK(f) & O_RDWR \
529  || VSTREAM_ACC_MASK(f) & O_APPEND)
530 
531 #define VSTREAM_BUF_COUNT(bp, n) \
532  ((bp)->flags & VSTREAM_FLAG_READ ? -(n) : (n))
533 
534 #define VSTREAM_BUF_AT_START(bp) { \
535  (bp)->cnt = VSTREAM_BUF_COUNT((bp), (bp)->len); \
536  (bp)->ptr = (bp)->data; \
537  }
538 
539 #define VSTREAM_BUF_AT_OFFSET(bp, offset) { \
540  (bp)->ptr = (bp)->data + (offset); \
541  (bp)->cnt = VSTREAM_BUF_COUNT(bp, (bp)->len - (offset)); \
542  }
543 
544 #define VSTREAM_BUF_AT_END(bp) { \
545  (bp)->cnt = 0; \
546  (bp)->ptr = (bp)->data + (bp)->len; \
547  }
548 
549 #define VSTREAM_BUF_ZERO(bp) { \
550  (bp)->flags = 0; \
551  (bp)->data = (bp)->ptr = 0; \
552  (bp)->len = (bp)->cnt = 0; \
553  }
554 
555 #define VSTREAM_BUF_ACTIONS(bp, get_action, put_action, space_action) { \
556  (bp)->get_ready = (get_action); \
557  (bp)->put_ready = (put_action); \
558  (bp)->space = (space_action); \
559  }
560 
561 #define VSTREAM_SAVE_STATE(stream, buffer, filedes) { \
562  stream->buffer = stream->buf; \
563  stream->filedes = stream->fd; \
564  }
565 
566 #define VSTREAM_RESTORE_STATE(stream, buffer, filedes) do { \
567  stream->buffer.flags = stream->buf.flags; \
568  stream->buf = stream->buffer; \
569  stream->fd = stream->filedes; \
570  } while(0)
571 
572 #define VSTREAM_FORK_STATE(stream, buffer, filedes) { \
573  stream->buffer = stream->buf; \
574  stream->filedes = stream->fd; \
575  stream->buffer.data = stream->buffer.ptr = 0; \
576  stream->buffer.len = stream->buffer.cnt = 0; \
577  stream->buffer.flags &= ~VSTREAM_FLAG_FIXED; \
578  };
579 
580 #define VSTREAM_FLAG_READ_DOUBLE (VSTREAM_FLAG_READ | VSTREAM_FLAG_DOUBLE)
581 #define VSTREAM_FLAG_WRITE_DOUBLE (VSTREAM_FLAG_WRITE | VSTREAM_FLAG_DOUBLE)
582 
583 #define VSTREAM_FFLUSH_SOME(stream) \
584  vstream_fflush_some((stream), (stream)->buf.len - (stream)->buf.cnt)
585 
586 /* Note: this does not change a negative result into a zero result. */
587 #define VSTREAM_SUB_TIME(x, y, z) \
588  do { \
589  (x).tv_sec = (y).tv_sec - (z).tv_sec; \
590  (x).tv_usec = (y).tv_usec - (z).tv_usec; \
591  while ((x).tv_usec < 0) { \
592  (x).tv_usec += 1000000; \
593  (x).tv_sec -= 1; \
594  } \
595  while ((x).tv_usec >= 1000000) { \
596  (x).tv_usec -= 1000000; \
597  (x).tv_sec += 1; \
598  } \
599  } while (0)
600 
601 /* vstream_buf_init - initialize buffer */
602 
603 static void vstream_buf_init(VBUF *bp, int flags)
604 {
605 
606  /*
607  * Initialize the buffer such that the first data access triggers a
608  * buffer boundary action.
609  */
610  VSTREAM_BUF_ZERO(bp);
612  VSTREAM_CAN_READ(flags) ? vstream_buf_get_ready : 0,
613  VSTREAM_CAN_WRITE(flags) ? vstream_buf_put_ready : 0,
614  vstream_buf_space);
615 }
616 
617 /* vstream_buf_alloc - allocate buffer memory */
618 
619 static void vstream_buf_alloc(VBUF *bp, ssize_t len)
620 {
621  VSTREAM *stream = VBUF_TO_APPL(bp, VSTREAM, buf);
622  ssize_t used = bp->ptr - bp->data;
623  const char *myname = "vstream_buf_alloc";
624 
625  if (len < bp->len)
626  msg_panic("%s: attempt to shrink buffer", myname);
627  if (bp->flags & VSTREAM_FLAG_FIXED)
628  msg_panic("%s: unable to extend fixed-size buffer", myname);
629 
630  /*
631  * Late buffer allocation allows the user to override the default policy.
632  * If a buffer already exists, allow for the presence of (output) data.
633  */
634  bp->data = (unsigned char *)
635  (bp->data ? myrealloc((void *) bp->data, len) : mymalloc(len));
636  bp->len = len;
637  if (bp->flags & VSTREAM_FLAG_READ) {
638  bp->ptr = bp->data + used;
639  if (bp->flags & VSTREAM_FLAG_DOUBLE)
640  VSTREAM_SAVE_STATE(stream, read_buf, read_fd);
641  } else {
642  VSTREAM_BUF_AT_OFFSET(bp, used);
643  if (bp->flags & VSTREAM_FLAG_DOUBLE)
644  VSTREAM_SAVE_STATE(stream, write_buf, write_fd);
645  }
646 }
647 
648 /* vstream_buf_wipe - reset buffer to initial state */
649 
650 static void vstream_buf_wipe(VBUF *bp)
651 {
652  if ((bp->flags & VBUF_FLAG_FIXED) == 0 && bp->data)
653  myfree((void *) bp->data);
654  VSTREAM_BUF_ZERO(bp);
655  VSTREAM_BUF_ACTIONS(bp, 0, 0, 0);
656 }
657 
658 /* vstream_fflush_some - flush some buffered data */
659 
660 static int vstream_fflush_some(VSTREAM *stream, ssize_t to_flush)
661 {
662  const char *myname = "vstream_fflush_some";
663  VBUF *bp = &stream->buf;
664  ssize_t used;
665  ssize_t left_over;
666  void *data;
667  ssize_t len;
668  ssize_t n;
669  int timeout;
670  struct timeval before;
671  struct timeval elapsed;
672 
673  /*
674  * Sanity checks. It is illegal to flush a read-only stream. Otherwise,
675  * if there is buffered input, discard the input. If there is buffered
676  * output, require that the amount to flush is larger than the amount to
677  * keep, so that we can memcpy() the residue.
678  */
679  if (bp->put_ready == 0)
680  msg_panic("%s: read-only stream", myname);
681  switch (bp->flags & (VSTREAM_FLAG_WRITE | VSTREAM_FLAG_READ)) {
682  case VSTREAM_FLAG_READ: /* discard input */
683  VSTREAM_BUF_AT_END(bp);
684  /* FALLTHROUGH */
685  case 0: /* flush after seek? */
686  return ((bp->flags & VSTREAM_FLAG_ERR) ? VSTREAM_EOF : 0);
687  case VSTREAM_FLAG_WRITE: /* output buffered */
688  break;
690  msg_panic("%s: read/write stream", myname);
691  }
692  used = bp->len - bp->cnt;
693  left_over = used - to_flush;
694 
695  if (msg_verbose > 2 && stream != VSTREAM_ERR)
696  msg_info("%s: fd %d flush %ld", myname, stream->fd, (long) to_flush);
697  if (to_flush < 0 || left_over < 0)
698  msg_panic("%s: bad to_flush %ld", myname, (long) to_flush);
699  if (to_flush < left_over)
700  msg_panic("%s: to_flush < left_over", myname);
701  if (to_flush == 0)
702  return ((bp->flags & VSTREAM_FLAG_ERR) ? VSTREAM_EOF : 0);
703  if (bp->flags & VSTREAM_FLAG_ERR)
704  return (VSTREAM_EOF);
705 
706  /*
707  * When flushing a buffer, allow for partial writes. These can happen
708  * while talking to a network. Update the cached file seek position, if
709  * any.
710  *
711  * When deadlines are enabled, we count the elapsed time for each write
712  * operation instead of simply comparing the time-of-day clock with a
713  * per-stream deadline. The latter could result in anomalies when an
714  * application does lengthy processing between write operations. Keep in
715  * mind that a receiver may not be able to keep up when a sender suddenly
716  * floods it with a lot of data as it tries to catch up with a deadline.
717  */
718  for (data = (void *) bp->data, len = to_flush; len > 0; len -= n, data += n) {
719  if (bp->flags & VSTREAM_FLAG_DEADLINE) {
720  timeout = stream->time_limit.tv_sec + (stream->time_limit.tv_usec > 0);
721  if (timeout <= 0) {
723  errno = ETIMEDOUT;
724  return (VSTREAM_EOF);
725  }
726  if (len == to_flush)
727  GETTIMEOFDAY(&before);
728  else
729  before = stream->iotime;
730  } else
731  timeout = stream->timeout;
732  if ((n = stream->write_fn(stream->fd, data, len, timeout, stream->context)) <= 0) {
733  bp->flags |= VSTREAM_FLAG_WR_ERR;
734  if (errno == ETIMEDOUT) {
736  stream->time_limit.tv_sec = stream->time_limit.tv_usec = 0;
737  }
738  return (VSTREAM_EOF);
739  }
740  if (timeout) {
741  GETTIMEOFDAY(&stream->iotime);
742  if (bp->flags & VSTREAM_FLAG_DEADLINE) {
743  VSTREAM_SUB_TIME(elapsed, stream->iotime, before);
744  VSTREAM_SUB_TIME(stream->time_limit, stream->time_limit, elapsed);
745  }
746  }
747  if (msg_verbose > 2 && stream != VSTREAM_ERR && n != to_flush)
748  msg_info("%s: %d flushed %ld/%ld", myname, stream->fd,
749  (long) n, (long) to_flush);
750  }
751  if (bp->flags & VSTREAM_FLAG_SEEK)
752  stream->offset += to_flush;
753 
754  /*
755  * Allow for partial buffer flush requests. We use memcpy() for reasons
756  * of portability to pre-ANSI environments (SunOS 4.x or Ultrix 4.x :-).
757  * This is OK because we have already verified that the to_flush count is
758  * larger than the left_over count.
759  */
760  if (left_over > 0)
761  memcpy(bp->data, bp->data + to_flush, left_over);
762  bp->cnt += to_flush;
763  bp->ptr -= to_flush;
764  return ((bp->flags & VSTREAM_FLAG_ERR) ? VSTREAM_EOF : 0);
765 }
766 
767 /* vstream_fflush_delayed - delayed stream flush for double-buffered stream */
768 
769 static int vstream_fflush_delayed(VSTREAM *stream)
770 {
771  int status;
772 
773  /*
774  * Sanity check.
775  */
777  msg_panic("vstream_fflush_delayed: bad flags");
778 
779  /*
780  * Temporarily swap buffers and flush unwritten data. This may seem like
781  * a lot of work, but it's peanuts compared to the write(2) call that we
782  * already have avoided. For example, delayed flush is never used on a
783  * non-pipelined SMTP connection.
784  */
785  stream->buf.flags &= ~VSTREAM_FLAG_READ;
786  VSTREAM_SAVE_STATE(stream, read_buf, read_fd);
787  stream->buf.flags |= VSTREAM_FLAG_WRITE;
788  VSTREAM_RESTORE_STATE(stream, write_buf, write_fd);
789 
790  status = VSTREAM_FFLUSH_SOME(stream);
791 
792  stream->buf.flags &= ~VSTREAM_FLAG_WRITE;
793  VSTREAM_SAVE_STATE(stream, write_buf, write_fd);
794  stream->buf.flags |= VSTREAM_FLAG_READ;
795  VSTREAM_RESTORE_STATE(stream, read_buf, read_fd);
796 
797  return (status);
798 }
799 
800 /* vstream_buf_get_ready - vbuf callback to make buffer ready for reading */
801 
802 static int vstream_buf_get_ready(VBUF *bp)
803 {
804  VSTREAM *stream = VBUF_TO_APPL(bp, VSTREAM, buf);
805  const char *myname = "vstream_buf_get_ready";
806  ssize_t n;
807  struct timeval before;
808  struct timeval elapsed;
809  int timeout;
810 
811  /*
812  * Detect a change of I/O direction or position. If so, flush any
813  * unwritten output immediately when the stream is single-buffered, or
814  * when the stream is double-buffered and the read buffer is empty.
815  */
816  switch (bp->flags & (VSTREAM_FLAG_WRITE | VSTREAM_FLAG_READ)) {
817  case VSTREAM_FLAG_WRITE: /* change direction */
818  if (bp->ptr > bp->data)
819  if ((bp->flags & VSTREAM_FLAG_DOUBLE) == 0
820  || stream->read_buf.cnt >= 0)
821  if (VSTREAM_FFLUSH_SOME(stream))
822  return (VSTREAM_EOF);
823  bp->flags &= ~VSTREAM_FLAG_WRITE;
824  if (bp->flags & VSTREAM_FLAG_DOUBLE)
825  VSTREAM_SAVE_STATE(stream, write_buf, write_fd);
826  /* FALLTHROUGH */
827  case 0: /* change position */
828  bp->flags |= VSTREAM_FLAG_READ;
829  if (bp->flags & VSTREAM_FLAG_DOUBLE) {
830  VSTREAM_RESTORE_STATE(stream, read_buf, read_fd);
831  if (bp->cnt < 0)
832  return (0);
833  }
834  /* FALLTHROUGH */
835  case VSTREAM_FLAG_READ: /* no change */
836  break;
838  msg_panic("%s: read/write stream", myname);
839  }
840 
841  /*
842  * If this is the first GET operation, allocate a buffer. Late buffer
843  * allocation gives the application a chance to override the default
844  * buffering policy.
845  *
846  * XXX Subtle code to set the preferred buffer size as late as possible.
847  */
848  if (stream->req_bufsize == 0)
849  stream->req_bufsize = VSTREAM_BUFSIZE;
850  if (bp->len < stream->req_bufsize)
851  vstream_buf_alloc(bp, stream->req_bufsize);
852 
853  /*
854  * If the stream is double-buffered and the write buffer is not empty,
855  * this is the time to flush the write buffer. Delayed flushes reduce
856  * system call overhead, and on TCP sockets, avoid triggering Nagle's
857  * algorithm.
858  */
859  if ((bp->flags & VSTREAM_FLAG_DOUBLE)
860  && stream->write_buf.len > stream->write_buf.cnt)
861  if (vstream_fflush_delayed(stream))
862  return (VSTREAM_EOF);
863 
864  /*
865  * Did we receive an EOF indication?
866  */
867  if (bp->flags & VSTREAM_FLAG_EOF)
868  return (VSTREAM_EOF);
869 
870  /*
871  * Fill the buffer with as much data as we can handle, or with as much
872  * data as is available right now, whichever is less. Update the cached
873  * file seek position, if any.
874  *
875  * When deadlines are enabled, we count the elapsed time for each read
876  * operation instead of simply comparing the time-of-day clock with a
877  * per-stream deadline. The latter could result in anomalies when an
878  * application does lengthy processing between read operations. Keep in
879  * mind that a sender may get blocked, and may not be able to keep up
880  * when a receiver suddenly wants to read a lot of data as it tries to
881  * catch up with a deadline.
882  */
883  if (bp->flags & VSTREAM_FLAG_DEADLINE) {
884  timeout = stream->time_limit.tv_sec + (stream->time_limit.tv_usec > 0);
885  if (timeout <= 0) {
887  errno = ETIMEDOUT;
888  return (VSTREAM_EOF);
889  }
890  GETTIMEOFDAY(&before);
891  } else
892  timeout = stream->timeout;
893  switch (n = stream->read_fn(stream->fd, bp->data, bp->len, timeout, stream->context)) {
894  case -1:
895  bp->flags |= VSTREAM_FLAG_RD_ERR;
896  if (errno == ETIMEDOUT) {
898  stream->time_limit.tv_sec = stream->time_limit.tv_usec = 0;
899  }
900  return (VSTREAM_EOF);
901  case 0:
902  bp->flags |= VSTREAM_FLAG_EOF;
903  return (VSTREAM_EOF);
904  default:
905  if (timeout) {
906  GETTIMEOFDAY(&stream->iotime);
907  if (bp->flags & VSTREAM_FLAG_DEADLINE) {
908  VSTREAM_SUB_TIME(elapsed, stream->iotime, before);
909  VSTREAM_SUB_TIME(stream->time_limit, stream->time_limit, elapsed);
910  }
911  }
912  if (msg_verbose > 2)
913  msg_info("%s: fd %d got %ld", myname, stream->fd, (long) n);
914  bp->cnt = -n;
915  bp->ptr = bp->data;
916  if (bp->flags & VSTREAM_FLAG_SEEK)
917  stream->offset += n;
918  return (0);
919  }
920 }
921 
922 /* vstream_buf_put_ready - vbuf callback to make buffer ready for writing */
923 
924 static int vstream_buf_put_ready(VBUF *bp)
925 {
926  VSTREAM *stream = VBUF_TO_APPL(bp, VSTREAM, buf);
927  const char *myname = "vstream_buf_put_ready";
928 
929  /*
930  * Sanity checks. Detect a change of I/O direction or position. If so,
931  * discard unread input, and reset the buffer to the beginning.
932  */
933  switch (bp->flags & (VSTREAM_FLAG_WRITE | VSTREAM_FLAG_READ)) {
934  case VSTREAM_FLAG_READ: /* change direction */
935  bp->flags &= ~VSTREAM_FLAG_READ;
936  if (bp->flags & VSTREAM_FLAG_DOUBLE)
937  VSTREAM_SAVE_STATE(stream, read_buf, read_fd);
938  /* FALLTHROUGH */
939  case 0: /* change position */
940  bp->flags |= VSTREAM_FLAG_WRITE;
941  if (bp->flags & VSTREAM_FLAG_DOUBLE)
942  VSTREAM_RESTORE_STATE(stream, write_buf, write_fd);
943  else
945  /* FALLTHROUGH */
946  case VSTREAM_FLAG_WRITE: /* no change */
947  break;
949  msg_panic("%s: read/write stream", myname);
950  }
951 
952  /*
953  * Remember the direction. If this is the first PUT operation for this
954  * stream or if the buffer is smaller than the requested size, allocate a
955  * new buffer; obviously there is no data to be flushed yet. Otherwise,
956  * flush the buffer.
957  *
958  * XXX Subtle code to set the preferred buffer size as late as possible.
959  */
960  if (stream->req_bufsize == 0)
961  stream->req_bufsize = VSTREAM_BUFSIZE;
962  if (bp->len < stream->req_bufsize) {
963  vstream_buf_alloc(bp, stream->req_bufsize);
964  } else if (bp->cnt <= 0) {
965  if (VSTREAM_FFLUSH_SOME(stream))
966  return (VSTREAM_EOF);
967  }
968  return (0);
969 }
970 
971 /* vstream_buf_space - reserve space ahead of time */
972 
973 static int vstream_buf_space(VBUF *bp, ssize_t want)
974 {
975  VSTREAM *stream = VBUF_TO_APPL(bp, VSTREAM, buf);
976  ssize_t used;
977  ssize_t incr;
978  ssize_t shortage;
979  const char *myname = "vstream_buf_space";
980 
981  /*
982  * Sanity checks. Reserving space implies writing. It is illegal to write
983  * to a read-only stream. Detect a change of I/O direction or position.
984  * If so, reset the buffer to the beginning.
985  */
986  if (bp->put_ready == 0)
987  msg_panic("%s: read-only stream", myname);
988  if (want < 0)
989  msg_panic("%s: bad length %ld", myname, (long) want);
990  switch (bp->flags & (VSTREAM_FLAG_READ | VSTREAM_FLAG_WRITE)) {
991  case VSTREAM_FLAG_READ: /* change direction */
992  bp->flags &= ~VSTREAM_FLAG_READ;
993  if (bp->flags & VSTREAM_FLAG_DOUBLE)
994  VSTREAM_SAVE_STATE(stream, read_buf, read_fd);
995  /* FALLTHROUGH */
996  case 0: /* change position */
997  bp->flags |= VSTREAM_FLAG_WRITE;
998  if (bp->flags & VSTREAM_FLAG_DOUBLE)
999  VSTREAM_RESTORE_STATE(stream, write_buf, write_fd);
1000  else
1002  /* FALLTHROUGH */
1003  case VSTREAM_FLAG_WRITE: /* no change */
1004  break;
1006  msg_panic("%s: read/write stream", myname);
1007  }
1008 
1009  /*
1010  * See if enough space is available. If not, flush a multiple of
1011  * VSTREAM_BUFSIZE bytes and resize the buffer to a multiple of
1012  * VSTREAM_BUFSIZE. We flush multiples of VSTREAM_BUFSIZE in an attempt
1013  * to keep file updates block-aligned for better performance.
1014  *
1015  * XXX Subtle code to set the preferred buffer size as late as possible.
1016  */
1017 #define VSTREAM_TRUNCATE(count, base) (((count) / (base)) * (base))
1018 #define VSTREAM_ROUNDUP(count, base) VSTREAM_TRUNCATE(count + base - 1, base)
1019 
1020  if (stream->req_bufsize == 0)
1021  stream->req_bufsize = VSTREAM_BUFSIZE;
1022  if (want > bp->cnt) {
1023  if ((used = bp->len - bp->cnt) > stream->req_bufsize)
1024  if (vstream_fflush_some(stream, VSTREAM_TRUNCATE(used, stream->req_bufsize)))
1025  return (VSTREAM_EOF);
1026  if ((shortage = (want - bp->cnt)) > 0) {
1027  if ((bp->flags & VSTREAM_FLAG_FIXED)
1028  || shortage > __MAXINT__(ssize_t) -bp->len - stream->req_bufsize) {
1029  bp->flags |= VSTREAM_FLAG_WR_ERR;
1030  } else {
1031  incr = VSTREAM_ROUNDUP(shortage, stream->req_bufsize);
1032  vstream_buf_alloc(bp, bp->len + incr);
1033  }
1034  }
1035  }
1036  return (vstream_ferror(stream) ? VSTREAM_EOF : 0); /* mmap() may fail */
1037 }
1038 
1039 /* vstream_fpurge - discard unread or unwritten content */
1040 
1041 int vstream_fpurge(VSTREAM *stream, int direction)
1042 {
1043  const char *myname = "vstream_fpurge";
1044  VBUF *bp = &stream->buf;
1045 
1046 #define VSTREAM_MAYBE_PURGE_WRITE(d, b) if ((d) & VSTREAM_PURGE_WRITE) \
1047  VSTREAM_BUF_AT_START((b))
1048 #define VSTREAM_MAYBE_PURGE_READ(d, b) if ((d) & VSTREAM_PURGE_READ) \
1049  VSTREAM_BUF_AT_END((b))
1050 
1051  /*
1052  * To discard all unread contents, position the read buffer at its end,
1053  * so that we skip over any unread data, and so that the next read
1054  * operation will refill the buffer.
1055  *
1056  * To discard all unwritten content, position the write buffer at its
1057  * beginning, so that the next write operation clobbers any unwritten
1058  * data.
1059  */
1062  VSTREAM_MAYBE_PURGE_WRITE(direction, &stream->write_buf);
1063  /* FALLTHROUGH */
1064  case VSTREAM_FLAG_READ:
1065  VSTREAM_MAYBE_PURGE_READ(direction, bp);
1066  break;
1067  case VSTREAM_FLAG_DOUBLE:
1068  VSTREAM_MAYBE_PURGE_WRITE(direction, &stream->write_buf);
1069  VSTREAM_MAYBE_PURGE_READ(direction, &stream->read_buf);
1070  break;
1072  VSTREAM_MAYBE_PURGE_READ(direction, &stream->read_buf);
1073  /* FALLTHROUGH */
1074  case VSTREAM_FLAG_WRITE:
1075  VSTREAM_MAYBE_PURGE_WRITE(direction, bp);
1076  break;
1079  msg_panic("%s: read/write stream", myname);
1080  }
1081 
1082  /*
1083  * Invalidate the cached file seek position.
1084  */
1085  bp->flags &= ~VSTREAM_FLAG_SEEK;
1086  stream->offset = 0;
1087 
1088  return (0);
1089 }
1090 
1091 /* vstream_fseek - change I/O position */
1092 
1093 off_t vstream_fseek(VSTREAM *stream, off_t offset, int whence)
1094 {
1095  const char *myname = "vstream_fseek";
1096  VBUF *bp = &stream->buf;
1097 
1098  /*
1099  * Flush any unwritten output. Discard any unread input. Position the
1100  * buffer at the end, so that the next GET or PUT operation triggers a
1101  * buffer boundary action.
1102  */
1103  switch (bp->flags & (VSTREAM_FLAG_READ | VSTREAM_FLAG_WRITE)) {
1104  case VSTREAM_FLAG_WRITE:
1105  if (bp->ptr > bp->data) {
1106  if (whence == SEEK_CUR)
1107  offset += (bp->ptr - bp->data); /* add unwritten data */
1108  else if (whence == SEEK_END)
1109  bp->flags &= ~VSTREAM_FLAG_SEEK;
1110  if (VSTREAM_FFLUSH_SOME(stream))
1111  return (-1);
1112  }
1113  VSTREAM_BUF_AT_END(bp);
1114  break;
1115  case VSTREAM_FLAG_READ:
1116  if (whence == SEEK_CUR)
1117  offset += bp->cnt; /* subtract unread data */
1118  else if (whence == SEEK_END)
1119  bp->flags &= ~VSTREAM_FLAG_SEEK;
1120  /* FALLTHROUGH */
1121  case 0:
1122  VSTREAM_BUF_AT_END(bp);
1123  break;
1125  msg_panic("%s: read/write stream", myname);
1126  }
1127 
1128  /*
1129  * Clear the read/write flags to inform the buffer boundary action
1130  * routines that we may have changed I/O position.
1131  */
1133 
1134  /*
1135  * Shave an unnecessary system call.
1136  */
1137  if (bp->flags & VSTREAM_FLAG_NSEEK) {
1138  errno = ESPIPE;
1139  return (-1);
1140  }
1141 
1142  /*
1143  * Update the cached file seek position.
1144  */
1145  if ((stream->offset = lseek(stream->fd, offset, whence)) < 0) {
1146  if (errno == ESPIPE)
1147  bp->flags |= VSTREAM_FLAG_NSEEK;
1148  } else {
1149  bp->flags |= VSTREAM_FLAG_SEEK;
1150  }
1151  bp->flags &= ~VSTREAM_FLAG_EOF;
1152  return (stream->offset);
1153 }
1154 
1155 /* vstream_ftell - return file offset */
1156 
1157 off_t vstream_ftell(VSTREAM *stream)
1158 {
1159  VBUF *bp = &stream->buf;
1160 
1161  /*
1162  * Shave an unnecessary syscall.
1163  */
1164  if (bp->flags & VSTREAM_FLAG_NSEEK) {
1165  errno = ESPIPE;
1166  return (-1);
1167  }
1168 
1169  /*
1170  * Use the cached file offset when available. This is the offset after
1171  * the last read, write or seek operation.
1172  */
1173  if ((bp->flags & VSTREAM_FLAG_SEEK) == 0) {
1174  if ((stream->offset = lseek(stream->fd, (off_t) 0, SEEK_CUR)) < 0) {
1175  bp->flags |= VSTREAM_FLAG_NSEEK;
1176  return (-1);
1177  }
1178  bp->flags |= VSTREAM_FLAG_SEEK;
1179  }
1180 
1181  /*
1182  * If this is a read buffer, subtract the number of unread bytes from the
1183  * cached offset. Remember that read counts are negative.
1184  */
1185  if (bp->flags & VSTREAM_FLAG_READ)
1186  return (stream->offset + bp->cnt);
1187 
1188  /*
1189  * If this is a write buffer, add the number of unwritten bytes to the
1190  * cached offset.
1191  */
1192  if (bp->flags & VSTREAM_FLAG_WRITE)
1193  return (stream->offset + (bp->ptr - bp->data));
1194 
1195  /*
1196  * Apparently, this is a new buffer, or a buffer after seek, so there is
1197  * no need to account for unread or unwritten data.
1198  */
1199  return (stream->offset);
1200 }
1201 
1202 /* vstream_fdopen - add buffering to pre-opened stream */
1203 
1204 VSTREAM *vstream_fdopen(int fd, int flags)
1205 {
1206  VSTREAM *stream;
1207 
1208  /*
1209  * Sanity check.
1210  */
1211  if (fd < 0)
1212  msg_panic("vstream_fdopen: bad file %d", fd);
1213 
1214  /*
1215  * Initialize buffers etc. but do as little as possible. Late buffer
1216  * allocation etc. gives the application a chance to override default
1217  * policies. Either this, or the vstream*open() routines would have to
1218  * have a really ugly interface with lots of mostly-unused arguments (can
1219  * you say VMS?).
1220  */
1221  stream = (VSTREAM *) mymalloc(sizeof(*stream));
1222  stream->fd = fd;
1223  stream->read_fn = VSTREAM_CAN_READ(flags) ? (VSTREAM_RW_FN) timed_read : 0;
1224  stream->write_fn = VSTREAM_CAN_WRITE(flags) ? (VSTREAM_RW_FN) timed_write : 0;
1225  vstream_buf_init(&stream->buf, flags);
1226  stream->offset = 0;
1227  stream->path = 0;
1228  stream->pid = 0;
1229  stream->waitpid_fn = 0;
1230  stream->timeout = 0;
1231  stream->context = 0;
1232  stream->jbuf = 0;
1233  stream->iotime.tv_sec = stream->iotime.tv_usec = 0;
1234  stream->time_limit.tv_sec = stream->time_limit.tv_usec = 0;
1235  stream->req_bufsize = 0;
1236  return (stream);
1237 }
1238 
1239 /* vstream_fopen - open buffered file stream */
1240 
1241 VSTREAM *vstream_fopen(const char *path, int flags, mode_t mode)
1242 {
1243  VSTREAM *stream;
1244  int fd;
1245 
1246  if ((fd = open(path, flags, mode)) < 0) {
1247  return (0);
1248  } else {
1249  stream = vstream_fdopen(fd, flags);
1250  stream->path = mystrdup(path);
1251  return (stream);
1252  }
1253 }
1254 
1255 /* vstream_fflush - flush write buffer */
1256 
1258 {
1259  if ((stream->buf.flags & VSTREAM_FLAG_READ_DOUBLE)
1261  && stream->write_buf.len > stream->write_buf.cnt)
1262  vstream_fflush_delayed(stream);
1263  return (VSTREAM_FFLUSH_SOME(stream));
1264 }
1265 
1266 /* vstream_fclose - close buffered stream */
1267 
1269 {
1270  int err;
1271 
1272  /*
1273  * NOTE: Negative file descriptors are not part of the external
1274  * interface. They are for internal use only, in order to support
1275  * vstream_fdclose() without a lot of code duplication. Applications that
1276  * rely on negative VSTREAM file descriptors will break without warning.
1277  */
1278  if (stream->pid != 0)
1279  msg_panic("vstream_fclose: stream has process");
1280  if ((stream->buf.flags & VSTREAM_FLAG_WRITE_DOUBLE) != 0 && stream->fd >= 0)
1281  vstream_fflush(stream);
1282  /* Do not remove: vstream_fdclose() depends on this error test. */
1283  err = vstream_ferror(stream);
1284  if (stream->buf.flags & VSTREAM_FLAG_DOUBLE) {
1285  if (stream->read_fd >= 0)
1286  err |= close(stream->read_fd);
1287  if (stream->write_fd != stream->read_fd)
1288  if (stream->write_fd >= 0)
1289  err |= close(stream->write_fd);
1290  vstream_buf_wipe(&stream->read_buf);
1291  vstream_buf_wipe(&stream->write_buf);
1292  stream->buf = stream->read_buf;
1293  } else {
1294  if (stream->fd >= 0)
1295  err |= close(stream->fd);
1296  vstream_buf_wipe(&stream->buf);
1297  }
1298  if (stream->path)
1299  myfree(stream->path);
1300  if (stream->jbuf)
1301  myfree((void *) stream->jbuf);
1302  if (!VSTREAM_STATIC(stream))
1303  myfree((void *) stream);
1304  return (err ? VSTREAM_EOF : 0);
1305 }
1306 
1307 /* vstream_fdclose - close stream, leave file(s) open */
1308 
1310 {
1311 
1312  /*
1313  * Flush unwritten output, just like vstream_fclose(). Errors are
1314  * reported by vstream_fclose().
1315  */
1316  if ((stream->buf.flags & VSTREAM_FLAG_WRITE_DOUBLE) != 0)
1317  (void) vstream_fflush(stream);
1318 
1319  /*
1320  * NOTE: Negative file descriptors are not part of the external
1321  * interface. They are for internal use only, in order to support
1322  * vstream_fdclose() without a lot of code duplication. Applications that
1323  * rely on negative VSTREAM file descriptors will break without warning.
1324  */
1325  if (stream->buf.flags & VSTREAM_FLAG_DOUBLE) {
1326  stream->fd = stream->read_fd = stream->write_fd = -1;
1327  } else {
1328  stream->fd = -1;
1329  }
1330  return (vstream_fclose(stream));
1331 }
1332 
1333 /* vstream_printf - formatted print to stdout */
1334 
1335 VSTREAM *vstream_printf(const char *fmt,...)
1336 {
1337  VSTREAM *stream = VSTREAM_OUT;
1338  va_list ap;
1339 
1340  va_start(ap, fmt);
1341  vbuf_print(&stream->buf, fmt, ap);
1342  va_end(ap);
1343  return (stream);
1344 }
1345 
1346 /* vstream_fprintf - formatted print to buffered stream */
1347 
1348 VSTREAM *vstream_fprintf(VSTREAM *stream, const char *fmt,...)
1349 {
1350  va_list ap;
1351 
1352  va_start(ap, fmt);
1353  vbuf_print(&stream->buf, fmt, ap);
1354  va_end(ap);
1355  return (stream);
1356 }
1357 
1358 /* vstream_fputs - write string to stream */
1359 
1360 int vstream_fputs(const char *str, VSTREAM *stream)
1361 {
1362  int ch;
1363 
1364  while ((ch = *str++) != 0)
1365  if (VSTREAM_PUTC(ch, stream) == VSTREAM_EOF)
1366  return (VSTREAM_EOF);
1367  return (0);
1368 }
1369 
1370 /* vstream_control - fine control */
1371 
1372 void vstream_control(VSTREAM *stream, int name,...)
1373 {
1374  const char *myname = "vstream_control";
1375  va_list ap;
1376  int floor;
1377  int old_fd;
1378  ssize_t req_bufsize = 0;
1379  VSTREAM *stream2;
1380 
1381 #define SWAP(type,a,b) do { type temp = (a); (a) = (b); (b) = (temp); } while (0)
1382 
1383  for (va_start(ap, name); name != VSTREAM_CTL_END; name = va_arg(ap, int)) {
1384  switch (name) {
1385  case VSTREAM_CTL_READ_FN:
1386  stream->read_fn = va_arg(ap, VSTREAM_RW_FN);
1387  break;
1388  case VSTREAM_CTL_WRITE_FN:
1389  stream->write_fn = va_arg(ap, VSTREAM_RW_FN);
1390  break;
1391  case VSTREAM_CTL_CONTEXT:
1392  stream->context = va_arg(ap, void *);
1393  break;
1394  case VSTREAM_CTL_PATH:
1395  if (stream->path)
1396  myfree(stream->path);
1397  stream->path = mystrdup(va_arg(ap, char *));
1398  break;
1399  case VSTREAM_CTL_DOUBLE:
1400  if ((stream->buf.flags & VSTREAM_FLAG_DOUBLE) == 0) {
1401  stream->buf.flags |= VSTREAM_FLAG_DOUBLE;
1402  if (stream->buf.flags & VSTREAM_FLAG_READ) {
1403  VSTREAM_SAVE_STATE(stream, read_buf, read_fd);
1404  VSTREAM_FORK_STATE(stream, write_buf, write_fd);
1405  } else {
1406  VSTREAM_SAVE_STATE(stream, write_buf, write_fd);
1407  VSTREAM_FORK_STATE(stream, read_buf, read_fd);
1408  }
1409  }
1410  break;
1411  case VSTREAM_CTL_READ_FD:
1412  if ((stream->buf.flags & VSTREAM_FLAG_DOUBLE) == 0)
1413  msg_panic("VSTREAM_CTL_READ_FD requires double buffering");
1414  stream->read_fd = va_arg(ap, int);
1415  stream->buf.flags |= VSTREAM_FLAG_NSEEK;
1416  break;
1417  case VSTREAM_CTL_WRITE_FD:
1418  if ((stream->buf.flags & VSTREAM_FLAG_DOUBLE) == 0)
1419  msg_panic("VSTREAM_CTL_WRITE_FD requires double buffering");
1420  stream->write_fd = va_arg(ap, int);
1421  stream->buf.flags |= VSTREAM_FLAG_NSEEK;
1422  break;
1423  case VSTREAM_CTL_SWAP_FD:
1424  stream2 = va_arg(ap, VSTREAM *);
1425  if ((stream->buf.flags & VSTREAM_FLAG_DOUBLE)
1426  != (stream2->buf.flags & VSTREAM_FLAG_DOUBLE))
1427  msg_panic("VSTREAM_CTL_SWAP_FD can't swap descriptors between "
1428  "single-buffered and double-buffered streams");
1429  if (stream->buf.flags & VSTREAM_FLAG_DOUBLE) {
1430  SWAP(int, stream->read_fd, stream2->read_fd);
1431  SWAP(int, stream->write_fd, stream2->write_fd);
1432  stream->fd = ((stream->buf.flags & VSTREAM_FLAG_WRITE) ?
1433  stream->write_fd : stream->read_fd);
1434  } else {
1435  SWAP(int, stream->fd, stream2->fd);
1436  }
1437  break;
1438  case VSTREAM_CTL_TIMEOUT:
1439  if (stream->timeout == 0)
1440  GETTIMEOFDAY(&stream->iotime);
1441  stream->timeout = va_arg(ap, int);
1442  if (stream->timeout < 0)
1443  msg_panic("%s: bad timeout %d", myname, stream->timeout);
1444  break;
1445  case VSTREAM_CTL_EXCEPT:
1446  if (stream->jbuf == 0)
1447  stream->jbuf =
1449  break;
1450 
1451 #ifdef VSTREAM_CTL_DUPFD
1452 
1453 #define VSTREAM_TRY_DUPFD(backup, fd, floor) do { \
1454  if (((backup) = (fd)) < floor) { \
1455  if (((fd) = fcntl((backup), F_DUPFD, (floor))) < 0) \
1456  msg_fatal("fcntl F_DUPFD %d: %m", (floor)); \
1457  (void) close(backup); \
1458  } \
1459  } while (0)
1460 
1461  case VSTREAM_CTL_DUPFD:
1462  floor = va_arg(ap, int);
1463  if (stream->buf.flags & VSTREAM_FLAG_DOUBLE) {
1464  VSTREAM_TRY_DUPFD(old_fd, stream->read_fd, floor);
1465  if (stream->write_fd == old_fd)
1466  stream->write_fd = stream->read_fd;
1467  else
1468  VSTREAM_TRY_DUPFD(old_fd, stream->write_fd, floor);
1469  stream->fd = (stream->buf.flags & VSTREAM_FLAG_READ) ?
1470  stream->read_fd : stream->write_fd;
1471  } else {
1472  VSTREAM_TRY_DUPFD(old_fd, stream->fd, floor);
1473  }
1474  break;
1475 #endif
1476 
1477  /*
1478  * Postpone memory (re)allocation until the space is needed.
1479  */
1480  case VSTREAM_CTL_BUFSIZE:
1481  req_bufsize = va_arg(ap, ssize_t);
1482  /* Heuristic to detect missing (ssize_t) type cast on LP64 hosts. */
1483  if (req_bufsize < 0 || req_bufsize > INT_MAX)
1484  msg_panic("unreasonable VSTREAM_CTL_BUFSIZE request: %ld",
1485  (long) req_bufsize);
1486  if ((stream->buf.flags & VSTREAM_FLAG_FIXED) == 0
1487  && req_bufsize > stream->req_bufsize) {
1488  if (msg_verbose)
1489  msg_info("fd=%d: stream buffer size old=%ld new=%ld",
1490  vstream_fileno(stream),
1491  (long) stream->req_bufsize,
1492  (long) req_bufsize);
1493  stream->req_bufsize = req_bufsize;
1494  }
1495  break;
1496 
1497  /*
1498  * Make no gettimeofday() etc. system call until we really know
1499  * that we need to do I/O. This avoids a performance hit when
1500  * sending or receiving body content one line at a time.
1501  */
1503  stream->buf.flags &= ~VSTREAM_FLAG_DEADLINE;
1504  break;
1506  if (stream->timeout <= 0)
1507  msg_panic("%s: bad timeout %d", myname, stream->timeout);
1508  stream->buf.flags |= VSTREAM_FLAG_DEADLINE;
1509  stream->time_limit.tv_sec = stream->timeout;
1510  stream->time_limit.tv_usec = 0;
1511  break;
1512  default:
1513  msg_panic("%s: bad name %d", myname, name);
1514  }
1515  }
1516  va_end(ap);
1517 }
1518 
1519 /* vstream_vprintf - formatted print to stdout */
1520 
1521 VSTREAM *vstream_vprintf(const char *format, va_list ap)
1522 {
1523  VSTREAM *vp = VSTREAM_OUT;
1524 
1525  vbuf_print(&vp->buf, format, ap);
1526  return (vp);
1527 }
1528 
1529 /* vstream_vfprintf - formatted print engine */
1530 
1531 VSTREAM *vstream_vfprintf(VSTREAM *vp, const char *format, va_list ap)
1532 {
1533  vbuf_print(&vp->buf, format, ap);
1534  return (vp);
1535 }
1536 
1537 /* vstream_bufstat - get stream buffer status */
1538 
1539 ssize_t vstream_bufstat(VSTREAM *vp, int command)
1540 {
1541  VBUF *bp;
1542 
1543  switch (command & VSTREAM_BST_MASK_DIR) {
1544  case VSTREAM_BST_FLAG_IN:
1545  if (vp->buf.flags & VSTREAM_FLAG_READ) {
1546  bp = &vp->buf;
1547  } else if (vp->buf.flags & VSTREAM_FLAG_DOUBLE) {
1548  bp = &vp->read_buf;
1549  } else {
1550  bp = 0;
1551  }
1552  switch (command & ~VSTREAM_BST_MASK_DIR) {
1553  case VSTREAM_BST_FLAG_PEND:
1554  return (bp ? -bp->cnt : 0);
1555  /* Add other requests below. */
1556  }
1557  break;
1558  case VSTREAM_BST_FLAG_OUT:
1559  if (vp->buf.flags & VSTREAM_FLAG_WRITE) {
1560  bp = &vp->buf;
1561  } else if (vp->buf.flags & VSTREAM_FLAG_DOUBLE) {
1562  bp = &vp->write_buf;
1563  } else {
1564  bp = 0;
1565  }
1566  switch (command & ~VSTREAM_BST_MASK_DIR) {
1567  case VSTREAM_BST_FLAG_PEND:
1568  return (bp ? bp->len - bp->cnt : 0);
1569  /* Add other requests below. */
1570  }
1571  break;
1572  }
1573  msg_panic("vstream_bufstat: unknown command: %d", command);
1574 }
1575 
1576 #undef vstream_peek /* API binary compatibility. */
1577 
1578 /* vstream_peek - peek at a stream */
1579 
1580 ssize_t vstream_peek(VSTREAM *vp)
1581 {
1582  if (vp->buf.flags & VSTREAM_FLAG_READ) {
1583  return (-vp->buf.cnt);
1584  } else if (vp->buf.flags & VSTREAM_FLAG_DOUBLE) {
1585  return (-vp->read_buf.cnt);
1586  } else {
1587  return (0);
1588  }
1589 }
1590 
1591 /* vstream_peek_data - peek at unread data */
1592 
1593 const char *vstream_peek_data(VSTREAM *vp)
1594 {
1595  if (vp->buf.flags & VSTREAM_FLAG_READ) {
1596  return ((const char *) vp->buf.ptr);
1597  } else if (vp->buf.flags & VSTREAM_FLAG_DOUBLE) {
1598  return ((const char *) vp->read_buf.ptr);
1599  } else {
1600  return (0);
1601  }
1602 }
1603 
1604 #ifdef TEST
1605 
1606 static void copy_line(ssize_t bufsize)
1607 {
1608  int c;
1609 
1612  while ((c = VSTREAM_GETC(VSTREAM_IN)) != VSTREAM_EOF) {
1614  if (c == '\n')
1615  break;
1616  }
1618 }
1619 
1620 static void printf_number(void)
1621 {
1622  vstream_printf("%d\n", __MAXINT__(int));
1624 }
1625 
1626  /*
1627  * Exercise some of the features.
1628  */
1629 int main(int argc, char **argv)
1630 {
1631 
1632  /*
1633  * Test buffer expansion and shrinking. Formatted print may silently
1634  * expand the write buffer and cause multiple bytes to be written.
1635  */
1636  copy_line(1); /* one-byte read/write */
1637  copy_line(2); /* two-byte read/write */
1638  copy_line(1); /* two-byte read/write */
1639  printf_number(); /* multi-byte write */
1640  exit(0);
1641 }
1642 
1643 #endif
#define VSTREAM_FLAG_RD_TIMEOUT
Definition: vstream.h:72
#define VSTREAM_CTL_STOP_DEADLINE
Definition: vstream.h:152
int msg_verbose
Definition: msg.c:177
struct timeval time_limit
Definition: vstream.h:61
#define VSTREAM_EOF
Definition: vstream.h:110
VSTREAM_JMP_BUF * jbuf
Definition: vstream.h:59
#define VSTREAM_CTL_START_DEADLINE
Definition: vstream.h:151
void myfree(void *ptr)
Definition: mymalloc.c:207
VSTREAM_RW_FN read_fn
Definition: vstream.h:46
#define VSTREAM_FLAG_WRITE
Definition: vstream.h:82
char * mystrdup(const char *str)
Definition: mymalloc.c:225
#define VSTREAM_FLAG_WR_ERR
Definition: vstream.h:71
ssize_t cnt
Definition: vbuf.h:41
int fd
Definition: vstream.h:45
unsigned char * ptr
Definition: vbuf.h:42
VBUF write_buf
Definition: vstream.h:55
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
VSTREAM vstream_fstd[]
Definition: vstream.c:496
off_t vstream_ftell(VSTREAM *stream)
Definition: vstream.c:1157
#define VSTREAM_OUT
Definition: vstream.h:67
const char * vstream_peek_data(VSTREAM *vp)
Definition: vstream.c:1593
char * path
Definition: vstream.h:51
void * myrealloc(void *ptr, ssize_t len)
Definition: mymalloc.c:175
#define VSTREAM_CTL_END
Definition: vstream.h:135
VSTREAM * vstream_vfprintf(VSTREAM *vp, const char *format, va_list ap)
Definition: vstream.c:1531
int main(int argc, char **argv)
Definition: anvil.c:1010
#define VSTREAM_GETC(vp)
Definition: vstream.h:108
#define VSTREAM_CTL_CONTEXT
Definition: vstream.h:145
#define VSTREAM_CAN_READ(f)
Definition: vstream.c:525
#define SWAP(type, a, b)
int timeout
Definition: vstream.h:58
#define VSTREAM_IN
Definition: vstream.h:66
#define VBUF_FLAG_FIXED
Definition: vbuf.h:70
#define VSTREAM_CTL_READ_FD
Definition: vstream.h:140
VBUF read_buf
Definition: vstream.h:54
#define VSTREAM_SUB_TIME(x, y, z)
Definition: vstream.c:587
#define VSTREAM_CTL_SWAP_FD
Definition: vstream.h:150
#define VSTREAM_BUF_AT_START(bp)
Definition: vstream.c:534
pid_t pid
Definition: vstream.h:56
ssize_t vstream_peek(VSTREAM *vp)
Definition: vstream.c:1580
unsigned char * data
Definition: vbuf.h:39
#define VSTREAM_FLAG_WRITE_DOUBLE
Definition: vstream.c:581
VSTREAM * vstream_fopen(const char *path, int flags, mode_t mode)
Definition: vstream.c:1241
VSTREAM_RW_FN write_fn
Definition: vstream.h:47
int const char * fmt
#define VSTREAM_FLAG_DOUBLE
Definition: vstream.h:85
#define VSTREAM_FLAG_RD_ERR
Definition: vstream.h:70
#define VSTREAM_BUF_ACTIONS(bp, get_action, put_action, space_action)
Definition: vstream.c:555
#define VSTREAM_BST_MASK_DIR
Definition: vstream.h:228
#define CA_VSTREAM_CTL_BUFSIZE(v)
Definition: vstream.h:169
VSTREAM * vstream_fprintf(VSTREAM *stream, const char *fmt,...)
Definition: vstream.c:1348
#define VSTREAM_CTL_BUFSIZE
Definition: vstream.h:149
#define VBUF_TO_APPL(vbuf_ptr, app_type, vbuf_member)
Definition: vbuf.h:56
#define VSTREAM_CTL_READ_FN
Definition: vstream.h:136
int read_fd
Definition: vstream.h:52
#define VSTREAM_FFLUSH_SOME(stream)
Definition: vstream.c:583
void * context
Definition: vstream.h:49
int vstream_fclose(VSTREAM *stream)
Definition: vstream.c:1268
#define VSTREAM_FLAG_READ_DOUBLE
Definition: vstream.c:580
VSTREAM * vstream_printf(const char *fmt,...)
Definition: vstream.c:1335
int flags
Definition: vbuf.h:38
ssize_t req_bufsize
Definition: vstream.h:48
#define VSTREAM_FLAG_EOF
Definition: vstream.h:76
Definition: vbuf.h:37
#define VSTREAM_FLAG_FIXED
Definition: vstream.h:78
ssize_t timed_read(int, void *, size_t, int, void *)
Definition: timed_read.c:60
#define __MAXINT__(T)
Definition: sys_defs.h:1681
ssize_t(* VSTREAM_RW_FN)(int, void *, size_t, int, void *)
Definition: vstream.h:34
#define VSTREAM_MAYBE_PURGE_READ(d, b)
#define VSTREAM_FORK_STATE(stream, buffer, filedes)
Definition: vstream.c:572
#define VSTREAM_TRUNCATE(count, base)
VBUF buf
Definition: vstream.h:44
#define VSTREAM_FLAG_DEADLINE
Definition: vstream.h:86
off_t offset
Definition: vstream.h:50
#define VSTREAM_FLAG_WR_TIMEOUT
Definition: vstream.h:73
#define VSTREAM_BUF_ZERO(bp)
Definition: vstream.c:549
off_t vstream_fseek(VSTREAM *stream, off_t offset, int whence)
Definition: vstream.c:1093
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
ssize_t timed_write(int, const void *, size_t, int, void *)
Definition: timed_write.c:60
#define VSTREAM_BUFSIZE
Definition: vstream.h:92
#define VSTREAM_MAYBE_PURGE_WRITE(d, b)
VBUF_PUT_READY_FN put_ready
Definition: vbuf.h:44
VBUF * vbuf_print(VBUF *bp, const char *format, va_list ap)
Definition: vbuf_print.c:147
#define VSTREAM_FLAG_READ
Definition: vstream.h:81
#define VSTREAM_CTL_TIMEOUT
Definition: vstream.h:143
#define VSTREAM_BST_FLAG_OUT
Definition: vstream.h:225
#define VSTREAM_SAVE_STATE(stream, buffer, filedes)
Definition: vstream.c:561
#define VSTREAM_CTL_WRITE_FD
Definition: vstream.h:141
VSTREAM_WAITPID_FN waitpid_fn
Definition: vstream.h:57
int vstream_fdclose(VSTREAM *stream)
Definition: vstream.c:1309
ssize_t len
Definition: vbuf.h:40
#define VSTREAM_BST_FLAG_IN
Definition: vstream.h:224
#define VSTREAM_ROUNDUP(count, base)
#define VSTREAM_STATIC(v)
Definition: vstream.c:517
#define vstream_fileno(vp)
Definition: vstream.h:115
#define VSTREAM_BST_FLAG_PEND
Definition: vstream.h:226
struct timeval iotime
Definition: vstream.h:60
#define VSTREAM_CAN_WRITE(f)
Definition: vstream.c:527
#define VSTREAM_PUTC(ch, vp)
Definition: vstream.h:107
VSTREAM * vstream_vprintf(const char *format, va_list ap)
Definition: vstream.c:1521
void vstream_control(VSTREAM *stream, int name,...)
Definition: vstream.c:1372
ssize_t vstream_bufstat(VSTREAM *vp, int command)
Definition: vstream.c:1539
int write_fd
Definition: vstream.h:53
#define VSTREAM_JMP_BUF
Definition: vstream.h:40
int vstream_fpurge(VSTREAM *stream, int direction)
Definition: vstream.c:1041
#define vstream_ferror(vp)
Definition: vstream.h:120
#define VSTREAM_CTL_EXCEPT
Definition: vstream.h:144
#define VSTREAM_FLAG_SEEK
Definition: vstream.h:83
#define VSTREAM_CTL_PATH
Definition: vstream.h:138
#define VSTREAM_FLAG_ERR
Definition: vstream.h:75
#define VSTREAM_BUF_AT_OFFSET(bp, offset)
Definition: vstream.c:539
#define VSTREAM_CTL_DOUBLE
Definition: vstream.h:139
#define VSTREAM_CTL_WRITE_FN
Definition: vstream.h:137
ssize_t write_buf(int, const char *, ssize_t, int)
Definition: write_buf.c:58
#define VSTREAM_ERR
Definition: vstream.h:68
VSTREAM * vstream_fdopen(int fd, int flags)
Definition: vstream.c:1204
#define VSTREAM_RESTORE_STATE(stream, buffer, filedes)
Definition: vstream.c:566
#define VSTREAM_BUF_AT_END(bp)
Definition: vstream.c:544
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150
int vstream_fputs(const char *str, VSTREAM *stream)
Definition: vstream.c:1360
#define VSTREAM_FLAG_NSEEK
Definition: vstream.h:84
void msg_info(const char *fmt,...)
Definition: msg.c:199