1 /* $OpenBSD: io.c,v 1.9 2020/09/12 15:46:48 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 * Write a binary buffer of the given size, which may be zero. 102 */ 103 void 104 io_buf_write(int fd, const void *p, size_t sz) 105 { 106 107 io_simple_write(fd, &sz, sizeof(size_t)); 108 io_simple_write(fd, p, sz); 109 } 110 111 /* 112 * Like io_str_write() but into a buffer. 113 */ 114 void 115 io_str_buffer(char **b, size_t *bsz, size_t *bmax, const char *p) 116 { 117 size_t sz = (p == NULL) ? 0 : strlen(p); 118 119 io_buf_buffer(b, bsz, bmax, p, sz); 120 } 121 122 /* 123 * Write a NUL-terminated string, which may be zero-length. 124 */ 125 void 126 io_str_write(int fd, const char *p) 127 { 128 size_t sz = (p == NULL) ? 0 : strlen(p); 129 130 io_buf_write(fd, p, sz); 131 } 132 133 /* 134 * Read of a binary buffer that must be on a blocking descriptor. 135 * Does nothing if "sz" is zero. 136 * This will fail and exit on EOF. 137 */ 138 void 139 io_simple_read(int fd, void *res, size_t sz) 140 { 141 ssize_t ssz; 142 char *tmp; 143 144 tmp = res; /* arithmetic on a pointer to void is a GNU extension */ 145 again: 146 if (sz == 0) 147 return; 148 if ((ssz = read(fd, tmp, sz)) == -1) 149 err(1, "read"); 150 else if (ssz == 0) 151 errx(1, "read: unexpected end of file"); 152 else if ((size_t)ssz == sz) 153 return; 154 sz -= ssz; 155 tmp += ssz; 156 goto again; 157 } 158 159 /* 160 * Read a binary buffer, allocating space for it. 161 * If the buffer is zero-sized, this won't allocate "res", but 162 * will still initialise it to NULL. 163 */ 164 void 165 io_buf_read_alloc(int fd, void **res, size_t *sz) 166 { 167 168 *res = NULL; 169 io_simple_read(fd, sz, sizeof(size_t)); 170 if (*sz == 0) 171 return; 172 if ((*res = malloc(*sz)) == NULL) 173 err(1, NULL); 174 io_simple_read(fd, *res, *sz); 175 } 176 177 /* 178 * Read a string (which may just be \0 and zero-length), allocating 179 * space for it. 180 */ 181 void 182 io_str_read(int fd, char **res) 183 { 184 size_t sz; 185 186 io_simple_read(fd, &sz, sizeof(size_t)); 187 if ((*res = calloc(sz + 1, 1)) == NULL) 188 err(1, NULL); 189 io_simple_read(fd, *res, sz); 190 } 191