1 /* $OpenBSD: io.c,v 1.27 2024/11/26 13:59:09 claudio Exp $ */ 2 /* 3 * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org> 4 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/queue.h> 20 #include <sys/socket.h> 21 22 #include <err.h> 23 #include <errno.h> 24 #include <fcntl.h> 25 #include <stdint.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include <unistd.h> 29 #include <imsg.h> 30 31 #include "extern.h" 32 33 #define IO_FD_MARK 0x80000000U 34 35 /* 36 * Create new io buffer, call io_close() when done with it. 37 * Function always returns a new buffer. 38 */ 39 struct ibuf * 40 io_new_buffer(void) 41 { 42 struct ibuf *b; 43 44 if ((b = ibuf_dynamic(64, MAX_MSG_SIZE)) == NULL) 45 err(1, NULL); 46 ibuf_add_zero(b, sizeof(size_t)); /* can not fail */ 47 return b; 48 } 49 50 /* 51 * Add a simple object of static size to the io buffer. 52 */ 53 void 54 io_simple_buffer(struct ibuf *b, const void *res, size_t sz) 55 { 56 if (ibuf_add(b, res, sz) == -1) 57 err(1, NULL); 58 } 59 60 /* 61 * Add a sz sized buffer into the io buffer. 62 */ 63 void 64 io_buf_buffer(struct ibuf *b, const void *p, size_t sz) 65 { 66 if (ibuf_add(b, &sz, sizeof(size_t)) == -1) 67 err(1, NULL); 68 if (sz > 0) 69 if (ibuf_add(b, p, sz) == -1) 70 err(1, NULL); 71 } 72 73 /* 74 * Add a string into the io buffer. 75 */ 76 void 77 io_str_buffer(struct ibuf *b, const char *p) 78 { 79 size_t sz = (p == NULL) ? 0 : strlen(p); 80 81 io_buf_buffer(b, p, sz); 82 } 83 84 /* 85 * Finish and enqueue a io buffer. 86 */ 87 void 88 io_close_buffer(struct msgbuf *msgbuf, struct ibuf *b) 89 { 90 size_t len; 91 92 len = ibuf_size(b); 93 if (ibuf_fd_avail(b)) 94 len |= IO_FD_MARK; 95 ibuf_set(b, 0, &len, sizeof(len)); 96 ibuf_close(msgbuf, b); 97 } 98 99 /* 100 * Read of an ibuf and extract sz byte from there. 101 * Does nothing if "sz" is zero. 102 * Return 1 on success or 0 if there was not enough data. 103 */ 104 void 105 io_read_buf(struct ibuf *b, void *res, size_t sz) 106 { 107 if (sz == 0) 108 return; 109 if (ibuf_get(b, res, sz) == -1) 110 err(1, "bad internal framing"); 111 } 112 113 /* 114 * Read a string (returns NULL for zero-length strings), allocating 115 * space for it. 116 * Return 1 on success or 0 if there was not enough data. 117 */ 118 void 119 io_read_str(struct ibuf *b, char **res) 120 { 121 size_t sz; 122 123 io_read_buf(b, &sz, sizeof(sz)); 124 if (sz == 0) { 125 *res = NULL; 126 return; 127 } 128 if ((*res = calloc(sz + 1, 1)) == NULL) 129 err(1, NULL); 130 io_read_buf(b, *res, sz); 131 } 132 133 /* 134 * Read a binary buffer, allocating space for it. 135 * If the buffer is zero-sized, this won't allocate "res", but 136 * will still initialise it to NULL. 137 * Return 1 on success or 0 if there was not enough data. 138 */ 139 void 140 io_read_buf_alloc(struct ibuf *b, void **res, size_t *sz) 141 { 142 *res = NULL; 143 io_read_buf(b, sz, sizeof(*sz)); 144 if (*sz == 0) 145 return; 146 if ((*res = malloc(*sz)) == NULL) 147 err(1, NULL); 148 io_read_buf(b, *res, *sz); 149 } 150 151 struct ibuf * 152 io_parse_hdr(struct ibuf *buf, void *arg, int *fd) 153 { 154 struct ibuf *b; 155 size_t len; 156 int hasfd = 0; 157 158 if (ibuf_get(buf, &len, sizeof(len)) == -1) 159 return NULL; 160 161 if (len & IO_FD_MARK) { 162 hasfd = 1; 163 len &= ~IO_FD_MARK; 164 } 165 if (len <= sizeof(len) || len > MAX_MSG_SIZE) { 166 errno = ERANGE; 167 return NULL; 168 } 169 if ((b = ibuf_open(len)) == NULL) 170 return NULL; 171 if (hasfd) { 172 ibuf_fd_set(b, *fd); 173 *fd = -1; 174 } 175 return b; 176 } 177 178 struct ibuf * 179 io_buf_get(struct msgbuf *msgq) 180 { 181 struct ibuf *b; 182 183 if ((b = msgbuf_get(msgq)) == NULL) 184 return NULL; 185 186 ibuf_skip(b, sizeof(size_t)); 187 return b; 188 } 189