1134e1779SJakub Wojciech Klama /* 2134e1779SJakub Wojciech Klama * Copyright 2016 Jakub Klama <jceel@FreeBSD.org> 3134e1779SJakub Wojciech Klama * All rights reserved 4134e1779SJakub Wojciech Klama * 5134e1779SJakub Wojciech Klama * Redistribution and use in source and binary forms, with or without 6134e1779SJakub Wojciech Klama * modification, are permitted providing that the following conditions 7134e1779SJakub Wojciech Klama * are met: 8134e1779SJakub Wojciech Klama * 1. Redistributions of source code must retain the above copyright 9134e1779SJakub Wojciech Klama * notice, this list of conditions and the following disclaimer. 10134e1779SJakub Wojciech Klama * 2. Redistributions in binary form must reproduce the above copyright 11134e1779SJakub Wojciech Klama * notice, this list of conditions and the following disclaimer in the 12134e1779SJakub Wojciech Klama * documentation and/or other materials provided with the distribution. 13134e1779SJakub Wojciech Klama * 14134e1779SJakub Wojciech Klama * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15134e1779SJakub Wojciech Klama * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16134e1779SJakub Wojciech Klama * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17134e1779SJakub Wojciech Klama * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18134e1779SJakub Wojciech Klama * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19134e1779SJakub Wojciech Klama * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20134e1779SJakub Wojciech Klama * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21134e1779SJakub Wojciech Klama * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22134e1779SJakub Wojciech Klama * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23134e1779SJakub Wojciech Klama * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24134e1779SJakub Wojciech Klama * POSSIBILITY OF SUCH DAMAGE. 25134e1779SJakub Wojciech Klama * 26134e1779SJakub Wojciech Klama */ 27134e1779SJakub Wojciech Klama 28134e1779SJakub Wojciech Klama #include <stdlib.h> 29134e1779SJakub Wojciech Klama #include <errno.h> 30134e1779SJakub Wojciech Klama #include <string.h> 31134e1779SJakub Wojciech Klama #include <unistd.h> 32134e1779SJakub Wojciech Klama #include <pthread.h> 33134e1779SJakub Wojciech Klama #include <assert.h> 34134e1779SJakub Wojciech Klama #include <sys/types.h> 35134e1779SJakub Wojciech Klama #ifdef __APPLE__ 36134e1779SJakub Wojciech Klama # include "../apple_endian.h" 37134e1779SJakub Wojciech Klama #else 38134e1779SJakub Wojciech Klama # include <sys/endian.h> 39134e1779SJakub Wojciech Klama #endif 40134e1779SJakub Wojciech Klama #include <sys/socket.h> 41134e1779SJakub Wojciech Klama #include <sys/event.h> 42134e1779SJakub Wojciech Klama #include <sys/uio.h> 43134e1779SJakub Wojciech Klama #include <netdb.h> 44134e1779SJakub Wojciech Klama #include "../lib9p.h" 45134e1779SJakub Wojciech Klama #include "../lib9p_impl.h" 46134e1779SJakub Wojciech Klama #include "../log.h" 47134e1779SJakub Wojciech Klama #include "socket.h" 48134e1779SJakub Wojciech Klama 49134e1779SJakub Wojciech Klama struct l9p_socket_softc 50134e1779SJakub Wojciech Klama { 51134e1779SJakub Wojciech Klama struct l9p_connection *ls_conn; 52134e1779SJakub Wojciech Klama struct sockaddr ls_sockaddr; 53134e1779SJakub Wojciech Klama socklen_t ls_socklen; 54134e1779SJakub Wojciech Klama pthread_t ls_thread; 55134e1779SJakub Wojciech Klama int ls_fd; 56134e1779SJakub Wojciech Klama }; 57134e1779SJakub Wojciech Klama 58134e1779SJakub Wojciech Klama static int l9p_socket_readmsg(struct l9p_socket_softc *, void **, size_t *); 59134e1779SJakub Wojciech Klama static int l9p_socket_get_response_buffer(struct l9p_request *, 60134e1779SJakub Wojciech Klama struct iovec *, size_t *, void *); 61134e1779SJakub Wojciech Klama static int l9p_socket_send_response(struct l9p_request *, const struct iovec *, 62134e1779SJakub Wojciech Klama const size_t, const size_t, void *); 63134e1779SJakub Wojciech Klama static void l9p_socket_drop_response(struct l9p_request *, const struct iovec *, 64134e1779SJakub Wojciech Klama size_t, void *); 65134e1779SJakub Wojciech Klama static void *l9p_socket_thread(void *); 66134e1779SJakub Wojciech Klama static ssize_t xread(int, void *, size_t); 67134e1779SJakub Wojciech Klama static ssize_t xwrite(int, void *, size_t); 68134e1779SJakub Wojciech Klama 69134e1779SJakub Wojciech Klama int 70134e1779SJakub Wojciech Klama l9p_start_server(struct l9p_server *server, const char *host, const char *port) 71134e1779SJakub Wojciech Klama { 72134e1779SJakub Wojciech Klama struct addrinfo *res, *res0, hints; 73134e1779SJakub Wojciech Klama struct kevent kev[2]; 74134e1779SJakub Wojciech Klama struct kevent event[2]; 75134e1779SJakub Wojciech Klama int err, kq, i, val, evs, nsockets = 0; 76134e1779SJakub Wojciech Klama int sockets[2]; 77134e1779SJakub Wojciech Klama 78134e1779SJakub Wojciech Klama memset(&hints, 0, sizeof(hints)); 79134e1779SJakub Wojciech Klama hints.ai_family = PF_UNSPEC; 80134e1779SJakub Wojciech Klama hints.ai_socktype = SOCK_STREAM; 81134e1779SJakub Wojciech Klama err = getaddrinfo(host, port, &hints, &res0); 82134e1779SJakub Wojciech Klama 83134e1779SJakub Wojciech Klama if (err) 84134e1779SJakub Wojciech Klama return (-1); 85134e1779SJakub Wojciech Klama 86134e1779SJakub Wojciech Klama for (res = res0; res; res = res->ai_next) { 87134e1779SJakub Wojciech Klama int s = socket(res->ai_family, res->ai_socktype, 88134e1779SJakub Wojciech Klama res->ai_protocol); 89134e1779SJakub Wojciech Klama 90134e1779SJakub Wojciech Klama val = 1; 91134e1779SJakub Wojciech Klama setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); 92134e1779SJakub Wojciech Klama 93134e1779SJakub Wojciech Klama if (s < 0) 94134e1779SJakub Wojciech Klama continue; 95134e1779SJakub Wojciech Klama 96134e1779SJakub Wojciech Klama if (bind(s, res->ai_addr, res->ai_addrlen) < 0) { 97134e1779SJakub Wojciech Klama close(s); 98134e1779SJakub Wojciech Klama continue; 99134e1779SJakub Wojciech Klama } 100134e1779SJakub Wojciech Klama 101134e1779SJakub Wojciech Klama sockets[nsockets] = s; 102134e1779SJakub Wojciech Klama EV_SET(&kev[nsockets++], s, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 103134e1779SJakub Wojciech Klama 0, 0); 104134e1779SJakub Wojciech Klama listen(s, 10); 105134e1779SJakub Wojciech Klama } 106134e1779SJakub Wojciech Klama 107134e1779SJakub Wojciech Klama if (nsockets < 1) { 108134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR, "bind(): %s", strerror(errno)); 109134e1779SJakub Wojciech Klama return(-1); 110134e1779SJakub Wojciech Klama } 111134e1779SJakub Wojciech Klama 112134e1779SJakub Wojciech Klama kq = kqueue(); 113134e1779SJakub Wojciech Klama 114134e1779SJakub Wojciech Klama if (kevent(kq, kev, nsockets, NULL, 0, NULL) < 0) { 115134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR, "kevent(): %s", strerror(errno)); 116134e1779SJakub Wojciech Klama return (-1); 117134e1779SJakub Wojciech Klama } 118134e1779SJakub Wojciech Klama 119134e1779SJakub Wojciech Klama for (;;) { 120134e1779SJakub Wojciech Klama evs = kevent(kq, NULL, 0, event, nsockets, NULL); 121134e1779SJakub Wojciech Klama if (evs < 0) { 122134e1779SJakub Wojciech Klama if (errno == EINTR) 123134e1779SJakub Wojciech Klama continue; 124134e1779SJakub Wojciech Klama 125134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR, "kevent(): %s", strerror(errno)); 126134e1779SJakub Wojciech Klama return (-1); 127134e1779SJakub Wojciech Klama } 128134e1779SJakub Wojciech Klama 129134e1779SJakub Wojciech Klama for (i = 0; i < evs; i++) { 130134e1779SJakub Wojciech Klama struct sockaddr client_addr; 131134e1779SJakub Wojciech Klama socklen_t client_addr_len = sizeof(client_addr); 132134e1779SJakub Wojciech Klama int news = accept((int)event[i].ident, &client_addr, 133134e1779SJakub Wojciech Klama &client_addr_len); 134134e1779SJakub Wojciech Klama 135134e1779SJakub Wojciech Klama if (news < 0) { 136134e1779SJakub Wojciech Klama L9P_LOG(L9P_WARNING, "accept(): %s", 137134e1779SJakub Wojciech Klama strerror(errno)); 138134e1779SJakub Wojciech Klama continue; 139134e1779SJakub Wojciech Klama } 140134e1779SJakub Wojciech Klama 141134e1779SJakub Wojciech Klama l9p_socket_accept(server, news, &client_addr, 142134e1779SJakub Wojciech Klama client_addr_len); 143134e1779SJakub Wojciech Klama } 144134e1779SJakub Wojciech Klama } 145134e1779SJakub Wojciech Klama 146134e1779SJakub Wojciech Klama } 147134e1779SJakub Wojciech Klama 148134e1779SJakub Wojciech Klama void 149134e1779SJakub Wojciech Klama l9p_socket_accept(struct l9p_server *server, int conn_fd, 150134e1779SJakub Wojciech Klama struct sockaddr *client_addr, socklen_t client_addr_len) 151134e1779SJakub Wojciech Klama { 152134e1779SJakub Wojciech Klama struct l9p_socket_softc *sc; 153134e1779SJakub Wojciech Klama struct l9p_connection *conn; 154134e1779SJakub Wojciech Klama char host[NI_MAXHOST + 1]; 155134e1779SJakub Wojciech Klama char serv[NI_MAXSERV + 1]; 156134e1779SJakub Wojciech Klama int err; 157134e1779SJakub Wojciech Klama 158134e1779SJakub Wojciech Klama err = getnameinfo(client_addr, client_addr_len, host, NI_MAXHOST, serv, 159134e1779SJakub Wojciech Klama NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV); 160134e1779SJakub Wojciech Klama 161134e1779SJakub Wojciech Klama if (err != 0) { 162134e1779SJakub Wojciech Klama L9P_LOG(L9P_WARNING, "cannot look up client name: %s", 163134e1779SJakub Wojciech Klama gai_strerror(err)); 164134e1779SJakub Wojciech Klama } else { 165134e1779SJakub Wojciech Klama L9P_LOG(L9P_INFO, "new connection from %s:%s", host, serv); 166134e1779SJakub Wojciech Klama } 167134e1779SJakub Wojciech Klama 168134e1779SJakub Wojciech Klama if (l9p_connection_init(server, &conn) != 0) { 169134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR, "cannot create new connection"); 170134e1779SJakub Wojciech Klama return; 171134e1779SJakub Wojciech Klama } 172134e1779SJakub Wojciech Klama 173134e1779SJakub Wojciech Klama sc = l9p_calloc(1, sizeof(*sc)); 174134e1779SJakub Wojciech Klama sc->ls_conn = conn; 175134e1779SJakub Wojciech Klama sc->ls_fd = conn_fd; 176134e1779SJakub Wojciech Klama 177134e1779SJakub Wojciech Klama /* 178134e1779SJakub Wojciech Klama * Fill in transport handler functions and aux argument. 179134e1779SJakub Wojciech Klama */ 180134e1779SJakub Wojciech Klama conn->lc_lt.lt_aux = sc; 181134e1779SJakub Wojciech Klama conn->lc_lt.lt_get_response_buffer = l9p_socket_get_response_buffer; 182134e1779SJakub Wojciech Klama conn->lc_lt.lt_send_response = l9p_socket_send_response; 183134e1779SJakub Wojciech Klama conn->lc_lt.lt_drop_response = l9p_socket_drop_response; 184134e1779SJakub Wojciech Klama 185134e1779SJakub Wojciech Klama err = pthread_create(&sc->ls_thread, NULL, l9p_socket_thread, sc); 186134e1779SJakub Wojciech Klama if (err) { 187134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR, 188134e1779SJakub Wojciech Klama "pthread_create (for connection from %s:%s): error %s", 189134e1779SJakub Wojciech Klama host, serv, strerror(err)); 190134e1779SJakub Wojciech Klama l9p_connection_close(sc->ls_conn); 191134e1779SJakub Wojciech Klama free(sc); 192134e1779SJakub Wojciech Klama } 193134e1779SJakub Wojciech Klama } 194134e1779SJakub Wojciech Klama 195134e1779SJakub Wojciech Klama static void * 196134e1779SJakub Wojciech Klama l9p_socket_thread(void *arg) 197134e1779SJakub Wojciech Klama { 198134e1779SJakub Wojciech Klama struct l9p_socket_softc *sc = (struct l9p_socket_softc *)arg; 199134e1779SJakub Wojciech Klama struct iovec iov; 200134e1779SJakub Wojciech Klama void *buf; 201134e1779SJakub Wojciech Klama size_t length; 202134e1779SJakub Wojciech Klama 203134e1779SJakub Wojciech Klama for (;;) { 204134e1779SJakub Wojciech Klama if (l9p_socket_readmsg(sc, &buf, &length) != 0) 205134e1779SJakub Wojciech Klama break; 206134e1779SJakub Wojciech Klama 207134e1779SJakub Wojciech Klama iov.iov_base = buf; 208134e1779SJakub Wojciech Klama iov.iov_len = length; 209134e1779SJakub Wojciech Klama l9p_connection_recv(sc->ls_conn, &iov, 1, NULL); 210134e1779SJakub Wojciech Klama free(buf); 211134e1779SJakub Wojciech Klama } 212134e1779SJakub Wojciech Klama 213134e1779SJakub Wojciech Klama L9P_LOG(L9P_INFO, "connection closed"); 214134e1779SJakub Wojciech Klama l9p_connection_close(sc->ls_conn); 215134e1779SJakub Wojciech Klama free(sc); 216134e1779SJakub Wojciech Klama return (NULL); 217134e1779SJakub Wojciech Klama } 218134e1779SJakub Wojciech Klama 219134e1779SJakub Wojciech Klama static int 220134e1779SJakub Wojciech Klama l9p_socket_readmsg(struct l9p_socket_softc *sc, void **buf, size_t *size) 221134e1779SJakub Wojciech Klama { 222134e1779SJakub Wojciech Klama uint32_t msize; 223134e1779SJakub Wojciech Klama size_t toread; 224134e1779SJakub Wojciech Klama ssize_t ret; 225134e1779SJakub Wojciech Klama void *buffer; 226134e1779SJakub Wojciech Klama int fd = sc->ls_fd; 227134e1779SJakub Wojciech Klama 228134e1779SJakub Wojciech Klama assert(fd > 0); 229134e1779SJakub Wojciech Klama 230134e1779SJakub Wojciech Klama buffer = l9p_malloc(sizeof(uint32_t)); 231134e1779SJakub Wojciech Klama 232134e1779SJakub Wojciech Klama ret = xread(fd, buffer, sizeof(uint32_t)); 233134e1779SJakub Wojciech Klama if (ret < 0) { 234134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR, "read(): %s", strerror(errno)); 235134e1779SJakub Wojciech Klama return (-1); 236134e1779SJakub Wojciech Klama } 237134e1779SJakub Wojciech Klama 238134e1779SJakub Wojciech Klama if (ret != sizeof(uint32_t)) { 239134e1779SJakub Wojciech Klama if (ret == 0) 240134e1779SJakub Wojciech Klama L9P_LOG(L9P_DEBUG, "%p: EOF", (void *)sc->ls_conn); 241134e1779SJakub Wojciech Klama else 242134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR, 243134e1779SJakub Wojciech Klama "short read: %zd bytes of %zd expected", 244134e1779SJakub Wojciech Klama ret, sizeof(uint32_t)); 245134e1779SJakub Wojciech Klama return (-1); 246134e1779SJakub Wojciech Klama } 247134e1779SJakub Wojciech Klama 248134e1779SJakub Wojciech Klama msize = le32toh(*(uint32_t *)buffer); 249134e1779SJakub Wojciech Klama toread = msize - sizeof(uint32_t); 250134e1779SJakub Wojciech Klama buffer = l9p_realloc(buffer, msize); 251134e1779SJakub Wojciech Klama 252134e1779SJakub Wojciech Klama ret = xread(fd, (char *)buffer + sizeof(uint32_t), toread); 253134e1779SJakub Wojciech Klama if (ret < 0) { 254134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR, "read(): %s", strerror(errno)); 255134e1779SJakub Wojciech Klama return (-1); 256134e1779SJakub Wojciech Klama } 257134e1779SJakub Wojciech Klama 258134e1779SJakub Wojciech Klama if (ret != (ssize_t)toread) { 259134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR, "short read: %zd bytes of %zd expected", 260134e1779SJakub Wojciech Klama ret, toread); 261134e1779SJakub Wojciech Klama return (-1); 262134e1779SJakub Wojciech Klama } 263134e1779SJakub Wojciech Klama 264134e1779SJakub Wojciech Klama *size = msize; 265134e1779SJakub Wojciech Klama *buf = buffer; 266134e1779SJakub Wojciech Klama L9P_LOG(L9P_INFO, "%p: read complete message, buf=%p size=%d", 267134e1779SJakub Wojciech Klama (void *)sc->ls_conn, buffer, msize); 268134e1779SJakub Wojciech Klama 269134e1779SJakub Wojciech Klama return (0); 270134e1779SJakub Wojciech Klama } 271134e1779SJakub Wojciech Klama 272134e1779SJakub Wojciech Klama static int 273134e1779SJakub Wojciech Klama l9p_socket_get_response_buffer(struct l9p_request *req, struct iovec *iov, 274134e1779SJakub Wojciech Klama size_t *niovp, void *arg __unused) 275134e1779SJakub Wojciech Klama { 276134e1779SJakub Wojciech Klama size_t size = req->lr_conn->lc_msize; 277134e1779SJakub Wojciech Klama void *buf; 278134e1779SJakub Wojciech Klama 279134e1779SJakub Wojciech Klama buf = l9p_malloc(size); 280134e1779SJakub Wojciech Klama iov[0].iov_base = buf; 281134e1779SJakub Wojciech Klama iov[0].iov_len = size; 282134e1779SJakub Wojciech Klama 283134e1779SJakub Wojciech Klama *niovp = 1; 284134e1779SJakub Wojciech Klama return (0); 285134e1779SJakub Wojciech Klama } 286134e1779SJakub Wojciech Klama 287134e1779SJakub Wojciech Klama static int 288134e1779SJakub Wojciech Klama l9p_socket_send_response(struct l9p_request *req __unused, 289134e1779SJakub Wojciech Klama const struct iovec *iov, const size_t niov __unused, const size_t iolen, 290134e1779SJakub Wojciech Klama void *arg) 291134e1779SJakub Wojciech Klama { 292134e1779SJakub Wojciech Klama struct l9p_socket_softc *sc = (struct l9p_socket_softc *)arg; 293134e1779SJakub Wojciech Klama 294134e1779SJakub Wojciech Klama assert(sc->ls_fd >= 0); 295134e1779SJakub Wojciech Klama 296134e1779SJakub Wojciech Klama L9P_LOG(L9P_DEBUG, "%p: sending reply, buf=%p, size=%d", arg, 297134e1779SJakub Wojciech Klama iov[0].iov_base, iolen); 298134e1779SJakub Wojciech Klama 299134e1779SJakub Wojciech Klama if (xwrite(sc->ls_fd, iov[0].iov_base, iolen) != (int)iolen) { 300134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR, "short write: %s", strerror(errno)); 301134e1779SJakub Wojciech Klama return (-1); 302134e1779SJakub Wojciech Klama } 303134e1779SJakub Wojciech Klama 304134e1779SJakub Wojciech Klama free(iov[0].iov_base); 305134e1779SJakub Wojciech Klama return (0); 306134e1779SJakub Wojciech Klama } 307134e1779SJakub Wojciech Klama 308134e1779SJakub Wojciech Klama static void 309134e1779SJakub Wojciech Klama l9p_socket_drop_response(struct l9p_request *req __unused, 310*067bb820SJakub Wojciech Klama const struct iovec *iov, size_t niov __unused, void *arg __unused) 311134e1779SJakub Wojciech Klama { 312134e1779SJakub Wojciech Klama 313134e1779SJakub Wojciech Klama L9P_LOG(L9P_DEBUG, "%p: drop buf=%p", arg, iov[0].iov_base); 314134e1779SJakub Wojciech Klama free(iov[0].iov_base); 315134e1779SJakub Wojciech Klama } 316134e1779SJakub Wojciech Klama 317134e1779SJakub Wojciech Klama static ssize_t 318134e1779SJakub Wojciech Klama xread(int fd, void *buf, size_t count) 319134e1779SJakub Wojciech Klama { 320134e1779SJakub Wojciech Klama size_t done = 0; 321134e1779SJakub Wojciech Klama ssize_t ret; 322134e1779SJakub Wojciech Klama 323134e1779SJakub Wojciech Klama while (done < count) { 324134e1779SJakub Wojciech Klama ret = read(fd, (char *)buf + done, count - done); 325134e1779SJakub Wojciech Klama if (ret < 0) { 326134e1779SJakub Wojciech Klama if (errno == EINTR) 327134e1779SJakub Wojciech Klama continue; 328134e1779SJakub Wojciech Klama 329134e1779SJakub Wojciech Klama return (-1); 330134e1779SJakub Wojciech Klama } 331134e1779SJakub Wojciech Klama 332134e1779SJakub Wojciech Klama if (ret == 0) 333134e1779SJakub Wojciech Klama return ((ssize_t)done); 334134e1779SJakub Wojciech Klama 335134e1779SJakub Wojciech Klama done += (size_t)ret; 336134e1779SJakub Wojciech Klama } 337134e1779SJakub Wojciech Klama 338134e1779SJakub Wojciech Klama return ((ssize_t)done); 339134e1779SJakub Wojciech Klama } 340134e1779SJakub Wojciech Klama 341134e1779SJakub Wojciech Klama static ssize_t 342134e1779SJakub Wojciech Klama xwrite(int fd, void *buf, size_t count) 343134e1779SJakub Wojciech Klama { 344134e1779SJakub Wojciech Klama size_t done = 0; 345134e1779SJakub Wojciech Klama ssize_t ret; 346134e1779SJakub Wojciech Klama 347134e1779SJakub Wojciech Klama while (done < count) { 348134e1779SJakub Wojciech Klama ret = write(fd, (char *)buf + done, count - done); 349134e1779SJakub Wojciech Klama if (ret < 0) { 350134e1779SJakub Wojciech Klama if (errno == EINTR) 351134e1779SJakub Wojciech Klama continue; 352134e1779SJakub Wojciech Klama 353134e1779SJakub Wojciech Klama return (-1); 354134e1779SJakub Wojciech Klama } 355134e1779SJakub Wojciech Klama 356134e1779SJakub Wojciech Klama if (ret == 0) 357134e1779SJakub Wojciech Klama return ((ssize_t)done); 358134e1779SJakub Wojciech Klama 359134e1779SJakub Wojciech Klama done += (size_t)ret; 360134e1779SJakub Wojciech Klama } 361134e1779SJakub Wojciech Klama 362134e1779SJakub Wojciech Klama return ((ssize_t)done); 363134e1779SJakub Wojciech Klama } 364