1*134e1779SJakub Wojciech Klama /* 2*134e1779SJakub Wojciech Klama * Copyright 2016 Jakub Klama <jceel@FreeBSD.org> 3*134e1779SJakub Wojciech Klama * All rights reserved 4*134e1779SJakub Wojciech Klama * 5*134e1779SJakub Wojciech Klama * Redistribution and use in source and binary forms, with or without 6*134e1779SJakub Wojciech Klama * modification, are permitted providing that the following conditions 7*134e1779SJakub Wojciech Klama * are met: 8*134e1779SJakub Wojciech Klama * 1. Redistributions of source code must retain the above copyright 9*134e1779SJakub Wojciech Klama * notice, this list of conditions and the following disclaimer. 10*134e1779SJakub Wojciech Klama * 2. Redistributions in binary form must reproduce the above copyright 11*134e1779SJakub Wojciech Klama * notice, this list of conditions and the following disclaimer in the 12*134e1779SJakub Wojciech Klama * documentation and/or other materials provided with the distribution. 13*134e1779SJakub Wojciech Klama * 14*134e1779SJakub Wojciech Klama * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15*134e1779SJakub Wojciech Klama * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16*134e1779SJakub Wojciech Klama * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*134e1779SJakub Wojciech Klama * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18*134e1779SJakub Wojciech Klama * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*134e1779SJakub Wojciech Klama * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*134e1779SJakub Wojciech Klama * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*134e1779SJakub Wojciech Klama * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22*134e1779SJakub Wojciech Klama * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23*134e1779SJakub Wojciech Klama * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24*134e1779SJakub Wojciech Klama * POSSIBILITY OF SUCH DAMAGE. 25*134e1779SJakub Wojciech Klama * 26*134e1779SJakub Wojciech Klama */ 27*134e1779SJakub Wojciech Klama 28*134e1779SJakub Wojciech Klama #include <stdlib.h> 29*134e1779SJakub Wojciech Klama #include <errno.h> 30*134e1779SJakub Wojciech Klama #include <string.h> 31*134e1779SJakub Wojciech Klama #include <unistd.h> 32*134e1779SJakub Wojciech Klama #include <pthread.h> 33*134e1779SJakub Wojciech Klama #include <assert.h> 34*134e1779SJakub Wojciech Klama #include <sys/types.h> 35*134e1779SJakub Wojciech Klama #ifdef __APPLE__ 36*134e1779SJakub Wojciech Klama # include "../apple_endian.h" 37*134e1779SJakub Wojciech Klama #else 38*134e1779SJakub Wojciech Klama # include <sys/endian.h> 39*134e1779SJakub Wojciech Klama #endif 40*134e1779SJakub Wojciech Klama #include <sys/socket.h> 41*134e1779SJakub Wojciech Klama #include <sys/event.h> 42*134e1779SJakub Wojciech Klama #include <sys/uio.h> 43*134e1779SJakub Wojciech Klama #include <netdb.h> 44*134e1779SJakub Wojciech Klama #include "../lib9p.h" 45*134e1779SJakub Wojciech Klama #include "../lib9p_impl.h" 46*134e1779SJakub Wojciech Klama #include "../log.h" 47*134e1779SJakub Wojciech Klama #include "socket.h" 48*134e1779SJakub Wojciech Klama 49*134e1779SJakub Wojciech Klama struct l9p_socket_softc 50*134e1779SJakub Wojciech Klama { 51*134e1779SJakub Wojciech Klama struct l9p_connection *ls_conn; 52*134e1779SJakub Wojciech Klama struct sockaddr ls_sockaddr; 53*134e1779SJakub Wojciech Klama socklen_t ls_socklen; 54*134e1779SJakub Wojciech Klama pthread_t ls_thread; 55*134e1779SJakub Wojciech Klama int ls_fd; 56*134e1779SJakub Wojciech Klama }; 57*134e1779SJakub Wojciech Klama 58*134e1779SJakub Wojciech Klama static int l9p_socket_readmsg(struct l9p_socket_softc *, void **, size_t *); 59*134e1779SJakub Wojciech Klama static int l9p_socket_get_response_buffer(struct l9p_request *, 60*134e1779SJakub Wojciech Klama struct iovec *, size_t *, void *); 61*134e1779SJakub Wojciech Klama static int l9p_socket_send_response(struct l9p_request *, const struct iovec *, 62*134e1779SJakub Wojciech Klama const size_t, const size_t, void *); 63*134e1779SJakub Wojciech Klama static void l9p_socket_drop_response(struct l9p_request *, const struct iovec *, 64*134e1779SJakub Wojciech Klama size_t, void *); 65*134e1779SJakub Wojciech Klama static void *l9p_socket_thread(void *); 66*134e1779SJakub Wojciech Klama static ssize_t xread(int, void *, size_t); 67*134e1779SJakub Wojciech Klama static ssize_t xwrite(int, void *, size_t); 68*134e1779SJakub Wojciech Klama 69*134e1779SJakub Wojciech Klama int 70*134e1779SJakub Wojciech Klama l9p_start_server(struct l9p_server *server, const char *host, const char *port) 71*134e1779SJakub Wojciech Klama { 72*134e1779SJakub Wojciech Klama struct addrinfo *res, *res0, hints; 73*134e1779SJakub Wojciech Klama struct kevent kev[2]; 74*134e1779SJakub Wojciech Klama struct kevent event[2]; 75*134e1779SJakub Wojciech Klama int err, kq, i, val, evs, nsockets = 0; 76*134e1779SJakub Wojciech Klama int sockets[2]; 77*134e1779SJakub Wojciech Klama 78*134e1779SJakub Wojciech Klama memset(&hints, 0, sizeof(hints)); 79*134e1779SJakub Wojciech Klama hints.ai_family = PF_UNSPEC; 80*134e1779SJakub Wojciech Klama hints.ai_socktype = SOCK_STREAM; 81*134e1779SJakub Wojciech Klama err = getaddrinfo(host, port, &hints, &res0); 82*134e1779SJakub Wojciech Klama 83*134e1779SJakub Wojciech Klama if (err) 84*134e1779SJakub Wojciech Klama return (-1); 85*134e1779SJakub Wojciech Klama 86*134e1779SJakub Wojciech Klama for (res = res0; res; res = res->ai_next) { 87*134e1779SJakub Wojciech Klama int s = socket(res->ai_family, res->ai_socktype, 88*134e1779SJakub Wojciech Klama res->ai_protocol); 89*134e1779SJakub Wojciech Klama 90*134e1779SJakub Wojciech Klama val = 1; 91*134e1779SJakub Wojciech Klama setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); 92*134e1779SJakub Wojciech Klama 93*134e1779SJakub Wojciech Klama if (s < 0) 94*134e1779SJakub Wojciech Klama continue; 95*134e1779SJakub Wojciech Klama 96*134e1779SJakub Wojciech Klama if (bind(s, res->ai_addr, res->ai_addrlen) < 0) { 97*134e1779SJakub Wojciech Klama close(s); 98*134e1779SJakub Wojciech Klama continue; 99*134e1779SJakub Wojciech Klama } 100*134e1779SJakub Wojciech Klama 101*134e1779SJakub Wojciech Klama sockets[nsockets] = s; 102*134e1779SJakub Wojciech Klama EV_SET(&kev[nsockets++], s, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 103*134e1779SJakub Wojciech Klama 0, 0); 104*134e1779SJakub Wojciech Klama listen(s, 10); 105*134e1779SJakub Wojciech Klama } 106*134e1779SJakub Wojciech Klama 107*134e1779SJakub Wojciech Klama if (nsockets < 1) { 108*134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR, "bind(): %s", strerror(errno)); 109*134e1779SJakub Wojciech Klama return(-1); 110*134e1779SJakub Wojciech Klama } 111*134e1779SJakub Wojciech Klama 112*134e1779SJakub Wojciech Klama kq = kqueue(); 113*134e1779SJakub Wojciech Klama 114*134e1779SJakub Wojciech Klama if (kevent(kq, kev, nsockets, NULL, 0, NULL) < 0) { 115*134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR, "kevent(): %s", strerror(errno)); 116*134e1779SJakub Wojciech Klama return (-1); 117*134e1779SJakub Wojciech Klama } 118*134e1779SJakub Wojciech Klama 119*134e1779SJakub Wojciech Klama for (;;) { 120*134e1779SJakub Wojciech Klama evs = kevent(kq, NULL, 0, event, nsockets, NULL); 121*134e1779SJakub Wojciech Klama if (evs < 0) { 122*134e1779SJakub Wojciech Klama if (errno == EINTR) 123*134e1779SJakub Wojciech Klama continue; 124*134e1779SJakub Wojciech Klama 125*134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR, "kevent(): %s", strerror(errno)); 126*134e1779SJakub Wojciech Klama return (-1); 127*134e1779SJakub Wojciech Klama } 128*134e1779SJakub Wojciech Klama 129*134e1779SJakub Wojciech Klama for (i = 0; i < evs; i++) { 130*134e1779SJakub Wojciech Klama struct sockaddr client_addr; 131*134e1779SJakub Wojciech Klama socklen_t client_addr_len = sizeof(client_addr); 132*134e1779SJakub Wojciech Klama int news = accept((int)event[i].ident, &client_addr, 133*134e1779SJakub Wojciech Klama &client_addr_len); 134*134e1779SJakub Wojciech Klama 135*134e1779SJakub Wojciech Klama if (news < 0) { 136*134e1779SJakub Wojciech Klama L9P_LOG(L9P_WARNING, "accept(): %s", 137*134e1779SJakub Wojciech Klama strerror(errno)); 138*134e1779SJakub Wojciech Klama continue; 139*134e1779SJakub Wojciech Klama } 140*134e1779SJakub Wojciech Klama 141*134e1779SJakub Wojciech Klama l9p_socket_accept(server, news, &client_addr, 142*134e1779SJakub Wojciech Klama client_addr_len); 143*134e1779SJakub Wojciech Klama } 144*134e1779SJakub Wojciech Klama } 145*134e1779SJakub Wojciech Klama 146*134e1779SJakub Wojciech Klama } 147*134e1779SJakub Wojciech Klama 148*134e1779SJakub Wojciech Klama void 149*134e1779SJakub Wojciech Klama l9p_socket_accept(struct l9p_server *server, int conn_fd, 150*134e1779SJakub Wojciech Klama struct sockaddr *client_addr, socklen_t client_addr_len) 151*134e1779SJakub Wojciech Klama { 152*134e1779SJakub Wojciech Klama struct l9p_socket_softc *sc; 153*134e1779SJakub Wojciech Klama struct l9p_connection *conn; 154*134e1779SJakub Wojciech Klama char host[NI_MAXHOST + 1]; 155*134e1779SJakub Wojciech Klama char serv[NI_MAXSERV + 1]; 156*134e1779SJakub Wojciech Klama int err; 157*134e1779SJakub Wojciech Klama 158*134e1779SJakub Wojciech Klama err = getnameinfo(client_addr, client_addr_len, host, NI_MAXHOST, serv, 159*134e1779SJakub Wojciech Klama NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV); 160*134e1779SJakub Wojciech Klama 161*134e1779SJakub Wojciech Klama if (err != 0) { 162*134e1779SJakub Wojciech Klama L9P_LOG(L9P_WARNING, "cannot look up client name: %s", 163*134e1779SJakub Wojciech Klama gai_strerror(err)); 164*134e1779SJakub Wojciech Klama } else { 165*134e1779SJakub Wojciech Klama L9P_LOG(L9P_INFO, "new connection from %s:%s", host, serv); 166*134e1779SJakub Wojciech Klama } 167*134e1779SJakub Wojciech Klama 168*134e1779SJakub Wojciech Klama if (l9p_connection_init(server, &conn) != 0) { 169*134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR, "cannot create new connection"); 170*134e1779SJakub Wojciech Klama return; 171*134e1779SJakub Wojciech Klama } 172*134e1779SJakub Wojciech Klama 173*134e1779SJakub Wojciech Klama sc = l9p_calloc(1, sizeof(*sc)); 174*134e1779SJakub Wojciech Klama sc->ls_conn = conn; 175*134e1779SJakub Wojciech Klama sc->ls_fd = conn_fd; 176*134e1779SJakub Wojciech Klama 177*134e1779SJakub Wojciech Klama /* 178*134e1779SJakub Wojciech Klama * Fill in transport handler functions and aux argument. 179*134e1779SJakub Wojciech Klama */ 180*134e1779SJakub Wojciech Klama conn->lc_lt.lt_aux = sc; 181*134e1779SJakub Wojciech Klama conn->lc_lt.lt_get_response_buffer = l9p_socket_get_response_buffer; 182*134e1779SJakub Wojciech Klama conn->lc_lt.lt_send_response = l9p_socket_send_response; 183*134e1779SJakub Wojciech Klama conn->lc_lt.lt_drop_response = l9p_socket_drop_response; 184*134e1779SJakub Wojciech Klama 185*134e1779SJakub Wojciech Klama err = pthread_create(&sc->ls_thread, NULL, l9p_socket_thread, sc); 186*134e1779SJakub Wojciech Klama if (err) { 187*134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR, 188*134e1779SJakub Wojciech Klama "pthread_create (for connection from %s:%s): error %s", 189*134e1779SJakub Wojciech Klama host, serv, strerror(err)); 190*134e1779SJakub Wojciech Klama l9p_connection_close(sc->ls_conn); 191*134e1779SJakub Wojciech Klama free(sc); 192*134e1779SJakub Wojciech Klama } 193*134e1779SJakub Wojciech Klama } 194*134e1779SJakub Wojciech Klama 195*134e1779SJakub Wojciech Klama static void * 196*134e1779SJakub Wojciech Klama l9p_socket_thread(void *arg) 197*134e1779SJakub Wojciech Klama { 198*134e1779SJakub Wojciech Klama struct l9p_socket_softc *sc = (struct l9p_socket_softc *)arg; 199*134e1779SJakub Wojciech Klama struct iovec iov; 200*134e1779SJakub Wojciech Klama void *buf; 201*134e1779SJakub Wojciech Klama size_t length; 202*134e1779SJakub Wojciech Klama 203*134e1779SJakub Wojciech Klama for (;;) { 204*134e1779SJakub Wojciech Klama if (l9p_socket_readmsg(sc, &buf, &length) != 0) 205*134e1779SJakub Wojciech Klama break; 206*134e1779SJakub Wojciech Klama 207*134e1779SJakub Wojciech Klama iov.iov_base = buf; 208*134e1779SJakub Wojciech Klama iov.iov_len = length; 209*134e1779SJakub Wojciech Klama l9p_connection_recv(sc->ls_conn, &iov, 1, NULL); 210*134e1779SJakub Wojciech Klama free(buf); 211*134e1779SJakub Wojciech Klama } 212*134e1779SJakub Wojciech Klama 213*134e1779SJakub Wojciech Klama L9P_LOG(L9P_INFO, "connection closed"); 214*134e1779SJakub Wojciech Klama l9p_connection_close(sc->ls_conn); 215*134e1779SJakub Wojciech Klama free(sc); 216*134e1779SJakub Wojciech Klama return (NULL); 217*134e1779SJakub Wojciech Klama } 218*134e1779SJakub Wojciech Klama 219*134e1779SJakub Wojciech Klama static int 220*134e1779SJakub Wojciech Klama l9p_socket_readmsg(struct l9p_socket_softc *sc, void **buf, size_t *size) 221*134e1779SJakub Wojciech Klama { 222*134e1779SJakub Wojciech Klama uint32_t msize; 223*134e1779SJakub Wojciech Klama size_t toread; 224*134e1779SJakub Wojciech Klama ssize_t ret; 225*134e1779SJakub Wojciech Klama void *buffer; 226*134e1779SJakub Wojciech Klama int fd = sc->ls_fd; 227*134e1779SJakub Wojciech Klama 228*134e1779SJakub Wojciech Klama assert(fd > 0); 229*134e1779SJakub Wojciech Klama 230*134e1779SJakub Wojciech Klama buffer = l9p_malloc(sizeof(uint32_t)); 231*134e1779SJakub Wojciech Klama 232*134e1779SJakub Wojciech Klama ret = xread(fd, buffer, sizeof(uint32_t)); 233*134e1779SJakub Wojciech Klama if (ret < 0) { 234*134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR, "read(): %s", strerror(errno)); 235*134e1779SJakub Wojciech Klama return (-1); 236*134e1779SJakub Wojciech Klama } 237*134e1779SJakub Wojciech Klama 238*134e1779SJakub Wojciech Klama if (ret != sizeof(uint32_t)) { 239*134e1779SJakub Wojciech Klama if (ret == 0) 240*134e1779SJakub Wojciech Klama L9P_LOG(L9P_DEBUG, "%p: EOF", (void *)sc->ls_conn); 241*134e1779SJakub Wojciech Klama else 242*134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR, 243*134e1779SJakub Wojciech Klama "short read: %zd bytes of %zd expected", 244*134e1779SJakub Wojciech Klama ret, sizeof(uint32_t)); 245*134e1779SJakub Wojciech Klama return (-1); 246*134e1779SJakub Wojciech Klama } 247*134e1779SJakub Wojciech Klama 248*134e1779SJakub Wojciech Klama msize = le32toh(*(uint32_t *)buffer); 249*134e1779SJakub Wojciech Klama toread = msize - sizeof(uint32_t); 250*134e1779SJakub Wojciech Klama buffer = l9p_realloc(buffer, msize); 251*134e1779SJakub Wojciech Klama 252*134e1779SJakub Wojciech Klama ret = xread(fd, (char *)buffer + sizeof(uint32_t), toread); 253*134e1779SJakub Wojciech Klama if (ret < 0) { 254*134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR, "read(): %s", strerror(errno)); 255*134e1779SJakub Wojciech Klama return (-1); 256*134e1779SJakub Wojciech Klama } 257*134e1779SJakub Wojciech Klama 258*134e1779SJakub Wojciech Klama if (ret != (ssize_t)toread) { 259*134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR, "short read: %zd bytes of %zd expected", 260*134e1779SJakub Wojciech Klama ret, toread); 261*134e1779SJakub Wojciech Klama return (-1); 262*134e1779SJakub Wojciech Klama } 263*134e1779SJakub Wojciech Klama 264*134e1779SJakub Wojciech Klama *size = msize; 265*134e1779SJakub Wojciech Klama *buf = buffer; 266*134e1779SJakub Wojciech Klama L9P_LOG(L9P_INFO, "%p: read complete message, buf=%p size=%d", 267*134e1779SJakub Wojciech Klama (void *)sc->ls_conn, buffer, msize); 268*134e1779SJakub Wojciech Klama 269*134e1779SJakub Wojciech Klama return (0); 270*134e1779SJakub Wojciech Klama } 271*134e1779SJakub Wojciech Klama 272*134e1779SJakub Wojciech Klama static int 273*134e1779SJakub Wojciech Klama l9p_socket_get_response_buffer(struct l9p_request *req, struct iovec *iov, 274*134e1779SJakub Wojciech Klama size_t *niovp, void *arg __unused) 275*134e1779SJakub Wojciech Klama { 276*134e1779SJakub Wojciech Klama size_t size = req->lr_conn->lc_msize; 277*134e1779SJakub Wojciech Klama void *buf; 278*134e1779SJakub Wojciech Klama 279*134e1779SJakub Wojciech Klama buf = l9p_malloc(size); 280*134e1779SJakub Wojciech Klama iov[0].iov_base = buf; 281*134e1779SJakub Wojciech Klama iov[0].iov_len = size; 282*134e1779SJakub Wojciech Klama 283*134e1779SJakub Wojciech Klama *niovp = 1; 284*134e1779SJakub Wojciech Klama return (0); 285*134e1779SJakub Wojciech Klama } 286*134e1779SJakub Wojciech Klama 287*134e1779SJakub Wojciech Klama static int 288*134e1779SJakub Wojciech Klama l9p_socket_send_response(struct l9p_request *req __unused, 289*134e1779SJakub Wojciech Klama const struct iovec *iov, const size_t niov __unused, const size_t iolen, 290*134e1779SJakub Wojciech Klama void *arg) 291*134e1779SJakub Wojciech Klama { 292*134e1779SJakub Wojciech Klama struct l9p_socket_softc *sc = (struct l9p_socket_softc *)arg; 293*134e1779SJakub Wojciech Klama 294*134e1779SJakub Wojciech Klama assert(sc->ls_fd >= 0); 295*134e1779SJakub Wojciech Klama 296*134e1779SJakub Wojciech Klama L9P_LOG(L9P_DEBUG, "%p: sending reply, buf=%p, size=%d", arg, 297*134e1779SJakub Wojciech Klama iov[0].iov_base, iolen); 298*134e1779SJakub Wojciech Klama 299*134e1779SJakub Wojciech Klama if (xwrite(sc->ls_fd, iov[0].iov_base, iolen) != (int)iolen) { 300*134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR, "short write: %s", strerror(errno)); 301*134e1779SJakub Wojciech Klama return (-1); 302*134e1779SJakub Wojciech Klama } 303*134e1779SJakub Wojciech Klama 304*134e1779SJakub Wojciech Klama free(iov[0].iov_base); 305*134e1779SJakub Wojciech Klama return (0); 306*134e1779SJakub Wojciech Klama } 307*134e1779SJakub Wojciech Klama 308*134e1779SJakub Wojciech Klama static void 309*134e1779SJakub Wojciech Klama l9p_socket_drop_response(struct l9p_request *req __unused, 310*134e1779SJakub Wojciech Klama const struct iovec *iov, size_t niov __unused, void *arg) 311*134e1779SJakub Wojciech Klama { 312*134e1779SJakub Wojciech Klama 313*134e1779SJakub Wojciech Klama L9P_LOG(L9P_DEBUG, "%p: drop buf=%p", arg, iov[0].iov_base); 314*134e1779SJakub Wojciech Klama free(iov[0].iov_base); 315*134e1779SJakub Wojciech Klama } 316*134e1779SJakub Wojciech Klama 317*134e1779SJakub Wojciech Klama static ssize_t 318*134e1779SJakub Wojciech Klama xread(int fd, void *buf, size_t count) 319*134e1779SJakub Wojciech Klama { 320*134e1779SJakub Wojciech Klama size_t done = 0; 321*134e1779SJakub Wojciech Klama ssize_t ret; 322*134e1779SJakub Wojciech Klama 323*134e1779SJakub Wojciech Klama while (done < count) { 324*134e1779SJakub Wojciech Klama ret = read(fd, (char *)buf + done, count - done); 325*134e1779SJakub Wojciech Klama if (ret < 0) { 326*134e1779SJakub Wojciech Klama if (errno == EINTR) 327*134e1779SJakub Wojciech Klama continue; 328*134e1779SJakub Wojciech Klama 329*134e1779SJakub Wojciech Klama return (-1); 330*134e1779SJakub Wojciech Klama } 331*134e1779SJakub Wojciech Klama 332*134e1779SJakub Wojciech Klama if (ret == 0) 333*134e1779SJakub Wojciech Klama return ((ssize_t)done); 334*134e1779SJakub Wojciech Klama 335*134e1779SJakub Wojciech Klama done += (size_t)ret; 336*134e1779SJakub Wojciech Klama } 337*134e1779SJakub Wojciech Klama 338*134e1779SJakub Wojciech Klama return ((ssize_t)done); 339*134e1779SJakub Wojciech Klama } 340*134e1779SJakub Wojciech Klama 341*134e1779SJakub Wojciech Klama static ssize_t 342*134e1779SJakub Wojciech Klama xwrite(int fd, void *buf, size_t count) 343*134e1779SJakub Wojciech Klama { 344*134e1779SJakub Wojciech Klama size_t done = 0; 345*134e1779SJakub Wojciech Klama ssize_t ret; 346*134e1779SJakub Wojciech Klama 347*134e1779SJakub Wojciech Klama while (done < count) { 348*134e1779SJakub Wojciech Klama ret = write(fd, (char *)buf + done, count - done); 349*134e1779SJakub Wojciech Klama if (ret < 0) { 350*134e1779SJakub Wojciech Klama if (errno == EINTR) 351*134e1779SJakub Wojciech Klama continue; 352*134e1779SJakub Wojciech Klama 353*134e1779SJakub Wojciech Klama return (-1); 354*134e1779SJakub Wojciech Klama } 355*134e1779SJakub Wojciech Klama 356*134e1779SJakub Wojciech Klama if (ret == 0) 357*134e1779SJakub Wojciech Klama return ((ssize_t)done); 358*134e1779SJakub Wojciech Klama 359*134e1779SJakub Wojciech Klama done += (size_t)ret; 360*134e1779SJakub Wojciech Klama } 361*134e1779SJakub Wojciech Klama 362*134e1779SJakub Wojciech Klama return ((ssize_t)done); 363*134e1779SJakub Wojciech Klama } 364