1 /* $OpenBSD: io.c,v 1.11 2020/12/18 16:58:59 claudio Exp $ */ 2 /* 3 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/queue.h> 19 20 #include <assert.h> 21 #include <err.h> 22 #include <fcntl.h> 23 #include <stdint.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <unistd.h> 27 28 #include "extern.h" 29 30 void 31 io_socket_blocking(int fd) 32 { 33 int fl; 34 35 if ((fl = fcntl(fd, F_GETFL, 0)) == -1) 36 err(1, "fcntl"); 37 if (fcntl(fd, F_SETFL, fl & ~O_NONBLOCK) == -1) 38 err(1, "fcntl"); 39 } 40 41 void 42 io_socket_nonblocking(int fd) 43 { 44 int fl; 45 46 if ((fl = fcntl(fd, F_GETFL, 0)) == -1) 47 err(1, "fcntl"); 48 if (fcntl(fd, F_SETFL, fl | O_NONBLOCK) == -1) 49 err(1, "fcntl"); 50 } 51 52 /* 53 * Blocking write of a binary buffer. 54 * Buffers of length zero are simply ignored. 55 */ 56 void 57 io_simple_write(int fd, const void *res, size_t sz) 58 { 59 ssize_t ssz; 60 61 if (sz == 0) 62 return; 63 if ((ssz = write(fd, res, sz)) == -1) 64 err(1, "write"); 65 else if ((size_t)ssz != sz) 66 errx(1, "write: short write"); 67 } 68 69 /* 70 * Like io_simple_write() but into a buffer. 71 */ 72 void 73 io_simple_buffer(char **b, size_t *bsz, 74 size_t *bmax, const void *res, size_t sz) 75 { 76 77 if (*bsz + sz > *bmax) { 78 if ((*b = realloc(*b, *bsz + sz)) == NULL) 79 err(1, NULL); 80 *bmax = *bsz + sz; 81 } 82 83 memcpy(*b + *bsz, res, sz); 84 *bsz += sz; 85 } 86 87 /* 88 * Like io_buf_write() but into a buffer. 89 */ 90 void 91 io_buf_buffer(char **b, size_t *bsz, 92 size_t *bmax, const void *p, size_t sz) 93 { 94 95 io_simple_buffer(b, bsz, bmax, &sz, sizeof(size_t)); 96 if (sz > 0) 97 io_simple_buffer(b, bsz, bmax, p, sz); 98 } 99 100 /* 101 * Like io_str_write() but into a buffer. 102 */ 103 void 104 io_str_buffer(char **b, size_t *bsz, size_t *bmax, const char *p) 105 { 106 size_t sz = (p == NULL) ? 0 : strlen(p); 107 108 io_buf_buffer(b, bsz, bmax, p, sz); 109 } 110 111 /* 112 * Read of a binary buffer that must be on a blocking descriptor. 113 * Does nothing if "sz" is zero. 114 * This will fail and exit on EOF. 115 */ 116 void 117 io_simple_read(int fd, void *res, size_t sz) 118 { 119 ssize_t ssz; 120 char *tmp; 121 122 tmp = res; /* arithmetic on a pointer to void is a GNU extension */ 123 again: 124 if (sz == 0) 125 return; 126 if ((ssz = read(fd, tmp, sz)) == -1) 127 err(1, "read"); 128 else if (ssz == 0) 129 errx(1, "read: unexpected end of file"); 130 else if ((size_t)ssz == sz) 131 return; 132 sz -= ssz; 133 tmp += ssz; 134 goto again; 135 } 136 137 /* 138 * Read a binary buffer, allocating space for it. 139 * If the buffer is zero-sized, this won't allocate "res", but 140 * will still initialise it to NULL. 141 */ 142 void 143 io_buf_read_alloc(int fd, void **res, size_t *sz) 144 { 145 146 *res = NULL; 147 io_simple_read(fd, sz, sizeof(size_t)); 148 if (*sz == 0) 149 return; 150 if ((*res = malloc(*sz)) == NULL) 151 err(1, NULL); 152 io_simple_read(fd, *res, *sz); 153 } 154 155 /* 156 * Read a string (returns NULL for zero-length strings), allocating 157 * space for it. 158 */ 159 void 160 io_str_read(int fd, char **res) 161 { 162 size_t sz; 163 164 io_simple_read(fd, &sz, sizeof(size_t)); 165 if (sz == 0) { 166 *res = NULL; 167 return; 168 } 169 if ((*res = calloc(sz + 1, 1)) == NULL) 170 err(1, NULL); 171 io_simple_read(fd, *res, sz); 172 } 173