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
l9p_start_server(struct l9p_server * server,const char * host,const char * port)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
77134e1779SJakub Wojciech Klama memset(&hints, 0, sizeof(hints));
78134e1779SJakub Wojciech Klama hints.ai_family = PF_UNSPEC;
79134e1779SJakub Wojciech Klama hints.ai_socktype = SOCK_STREAM;
80134e1779SJakub Wojciech Klama err = getaddrinfo(host, port, &hints, &res0);
81134e1779SJakub Wojciech Klama
82134e1779SJakub Wojciech Klama if (err)
83134e1779SJakub Wojciech Klama return (-1);
84134e1779SJakub Wojciech Klama
85134e1779SJakub Wojciech Klama for (res = res0; res; res = res->ai_next) {
86134e1779SJakub Wojciech Klama int s = socket(res->ai_family, res->ai_socktype,
87134e1779SJakub Wojciech Klama res->ai_protocol);
88134e1779SJakub Wojciech Klama
89134e1779SJakub Wojciech Klama val = 1;
90134e1779SJakub Wojciech Klama setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
91134e1779SJakub Wojciech Klama
92134e1779SJakub Wojciech Klama if (s < 0)
93134e1779SJakub Wojciech Klama continue;
94134e1779SJakub Wojciech Klama
95134e1779SJakub Wojciech Klama if (bind(s, res->ai_addr, res->ai_addrlen) < 0) {
96134e1779SJakub Wojciech Klama close(s);
97134e1779SJakub Wojciech Klama continue;
98134e1779SJakub Wojciech Klama }
99134e1779SJakub Wojciech Klama
100134e1779SJakub Wojciech Klama EV_SET(&kev[nsockets++], s, EVFILT_READ, EV_ADD | EV_ENABLE, 0,
101134e1779SJakub Wojciech Klama 0, 0);
102134e1779SJakub Wojciech Klama listen(s, 10);
103134e1779SJakub Wojciech Klama }
104134e1779SJakub Wojciech Klama
105134e1779SJakub Wojciech Klama if (nsockets < 1) {
106134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR, "bind(): %s", strerror(errno));
107134e1779SJakub Wojciech Klama return(-1);
108134e1779SJakub Wojciech Klama }
109134e1779SJakub Wojciech Klama
110134e1779SJakub Wojciech Klama kq = kqueue();
111134e1779SJakub Wojciech Klama
112134e1779SJakub Wojciech Klama if (kevent(kq, kev, nsockets, NULL, 0, NULL) < 0) {
113134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR, "kevent(): %s", strerror(errno));
114134e1779SJakub Wojciech Klama return (-1);
115134e1779SJakub Wojciech Klama }
116134e1779SJakub Wojciech Klama
117134e1779SJakub Wojciech Klama for (;;) {
118134e1779SJakub Wojciech Klama evs = kevent(kq, NULL, 0, event, nsockets, NULL);
119134e1779SJakub Wojciech Klama if (evs < 0) {
120134e1779SJakub Wojciech Klama if (errno == EINTR)
121134e1779SJakub Wojciech Klama continue;
122134e1779SJakub Wojciech Klama
123134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR, "kevent(): %s", strerror(errno));
124134e1779SJakub Wojciech Klama return (-1);
125134e1779SJakub Wojciech Klama }
126134e1779SJakub Wojciech Klama
127134e1779SJakub Wojciech Klama for (i = 0; i < evs; i++) {
128134e1779SJakub Wojciech Klama struct sockaddr client_addr;
129134e1779SJakub Wojciech Klama socklen_t client_addr_len = sizeof(client_addr);
130134e1779SJakub Wojciech Klama int news = accept((int)event[i].ident, &client_addr,
131134e1779SJakub Wojciech Klama &client_addr_len);
132134e1779SJakub Wojciech Klama
133134e1779SJakub Wojciech Klama if (news < 0) {
134134e1779SJakub Wojciech Klama L9P_LOG(L9P_WARNING, "accept(): %s",
135134e1779SJakub Wojciech Klama strerror(errno));
136134e1779SJakub Wojciech Klama continue;
137134e1779SJakub Wojciech Klama }
138134e1779SJakub Wojciech Klama
139134e1779SJakub Wojciech Klama l9p_socket_accept(server, news, &client_addr,
140134e1779SJakub Wojciech Klama client_addr_len);
141134e1779SJakub Wojciech Klama }
142134e1779SJakub Wojciech Klama }
143134e1779SJakub Wojciech Klama
144134e1779SJakub Wojciech Klama }
145134e1779SJakub Wojciech Klama
146134e1779SJakub Wojciech Klama void
l9p_socket_accept(struct l9p_server * server,int conn_fd,struct sockaddr * client_addr,socklen_t client_addr_len)147134e1779SJakub Wojciech Klama l9p_socket_accept(struct l9p_server *server, int conn_fd,
148134e1779SJakub Wojciech Klama struct sockaddr *client_addr, socklen_t client_addr_len)
149134e1779SJakub Wojciech Klama {
150134e1779SJakub Wojciech Klama struct l9p_socket_softc *sc;
151134e1779SJakub Wojciech Klama struct l9p_connection *conn;
152134e1779SJakub Wojciech Klama char host[NI_MAXHOST + 1];
153134e1779SJakub Wojciech Klama char serv[NI_MAXSERV + 1];
154134e1779SJakub Wojciech Klama int err;
155134e1779SJakub Wojciech Klama
156134e1779SJakub Wojciech Klama err = getnameinfo(client_addr, client_addr_len, host, NI_MAXHOST, serv,
157134e1779SJakub Wojciech Klama NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV);
158134e1779SJakub Wojciech Klama
159134e1779SJakub Wojciech Klama if (err != 0) {
160134e1779SJakub Wojciech Klama L9P_LOG(L9P_WARNING, "cannot look up client name: %s",
161134e1779SJakub Wojciech Klama gai_strerror(err));
162134e1779SJakub Wojciech Klama } else {
163134e1779SJakub Wojciech Klama L9P_LOG(L9P_INFO, "new connection from %s:%s", host, serv);
164134e1779SJakub Wojciech Klama }
165134e1779SJakub Wojciech Klama
166134e1779SJakub Wojciech Klama if (l9p_connection_init(server, &conn) != 0) {
167134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR, "cannot create new connection");
168134e1779SJakub Wojciech Klama return;
169134e1779SJakub Wojciech Klama }
170134e1779SJakub Wojciech Klama
171134e1779SJakub Wojciech Klama sc = l9p_calloc(1, sizeof(*sc));
172134e1779SJakub Wojciech Klama sc->ls_conn = conn;
173134e1779SJakub Wojciech Klama sc->ls_fd = conn_fd;
174134e1779SJakub Wojciech Klama
175134e1779SJakub Wojciech Klama /*
176134e1779SJakub Wojciech Klama * Fill in transport handler functions and aux argument.
177134e1779SJakub Wojciech Klama */
178134e1779SJakub Wojciech Klama conn->lc_lt.lt_aux = sc;
179134e1779SJakub Wojciech Klama conn->lc_lt.lt_get_response_buffer = l9p_socket_get_response_buffer;
180134e1779SJakub Wojciech Klama conn->lc_lt.lt_send_response = l9p_socket_send_response;
181134e1779SJakub Wojciech Klama conn->lc_lt.lt_drop_response = l9p_socket_drop_response;
182134e1779SJakub Wojciech Klama
183134e1779SJakub Wojciech Klama err = pthread_create(&sc->ls_thread, NULL, l9p_socket_thread, sc);
184134e1779SJakub Wojciech Klama if (err) {
185134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR,
186134e1779SJakub Wojciech Klama "pthread_create (for connection from %s:%s): error %s",
187134e1779SJakub Wojciech Klama host, serv, strerror(err));
188134e1779SJakub Wojciech Klama l9p_connection_close(sc->ls_conn);
189134e1779SJakub Wojciech Klama free(sc);
190134e1779SJakub Wojciech Klama }
191134e1779SJakub Wojciech Klama }
192134e1779SJakub Wojciech Klama
193134e1779SJakub Wojciech Klama static void *
l9p_socket_thread(void * arg)194134e1779SJakub Wojciech Klama l9p_socket_thread(void *arg)
195134e1779SJakub Wojciech Klama {
196134e1779SJakub Wojciech Klama struct l9p_socket_softc *sc = (struct l9p_socket_softc *)arg;
197134e1779SJakub Wojciech Klama struct iovec iov;
198134e1779SJakub Wojciech Klama void *buf;
199134e1779SJakub Wojciech Klama size_t length;
200134e1779SJakub Wojciech Klama
201134e1779SJakub Wojciech Klama for (;;) {
202134e1779SJakub Wojciech Klama if (l9p_socket_readmsg(sc, &buf, &length) != 0)
203134e1779SJakub Wojciech Klama break;
204134e1779SJakub Wojciech Klama
205134e1779SJakub Wojciech Klama iov.iov_base = buf;
206134e1779SJakub Wojciech Klama iov.iov_len = length;
207134e1779SJakub Wojciech Klama l9p_connection_recv(sc->ls_conn, &iov, 1, NULL);
208134e1779SJakub Wojciech Klama free(buf);
209134e1779SJakub Wojciech Klama }
210134e1779SJakub Wojciech Klama
211134e1779SJakub Wojciech Klama L9P_LOG(L9P_INFO, "connection closed");
212134e1779SJakub Wojciech Klama l9p_connection_close(sc->ls_conn);
213134e1779SJakub Wojciech Klama free(sc);
214134e1779SJakub Wojciech Klama return (NULL);
215134e1779SJakub Wojciech Klama }
216134e1779SJakub Wojciech Klama
217134e1779SJakub Wojciech Klama static int
l9p_socket_readmsg(struct l9p_socket_softc * sc,void ** buf,size_t * size)218134e1779SJakub Wojciech Klama l9p_socket_readmsg(struct l9p_socket_softc *sc, void **buf, size_t *size)
219134e1779SJakub Wojciech Klama {
220134e1779SJakub Wojciech Klama uint32_t msize;
221134e1779SJakub Wojciech Klama size_t toread;
222134e1779SJakub Wojciech Klama ssize_t ret;
223134e1779SJakub Wojciech Klama void *buffer;
224134e1779SJakub Wojciech Klama int fd = sc->ls_fd;
225134e1779SJakub Wojciech Klama
226134e1779SJakub Wojciech Klama assert(fd > 0);
227134e1779SJakub Wojciech Klama
228134e1779SJakub Wojciech Klama buffer = l9p_malloc(sizeof(uint32_t));
229134e1779SJakub Wojciech Klama
230134e1779SJakub Wojciech Klama ret = xread(fd, buffer, sizeof(uint32_t));
231134e1779SJakub Wojciech Klama if (ret < 0) {
232134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR, "read(): %s", strerror(errno));
233134e1779SJakub Wojciech Klama return (-1);
234134e1779SJakub Wojciech Klama }
235134e1779SJakub Wojciech Klama
236134e1779SJakub Wojciech Klama if (ret != sizeof(uint32_t)) {
237134e1779SJakub Wojciech Klama if (ret == 0)
238134e1779SJakub Wojciech Klama L9P_LOG(L9P_DEBUG, "%p: EOF", (void *)sc->ls_conn);
239134e1779SJakub Wojciech Klama else
240134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR,
241134e1779SJakub Wojciech Klama "short read: %zd bytes of %zd expected",
242134e1779SJakub Wojciech Klama ret, sizeof(uint32_t));
243134e1779SJakub Wojciech Klama return (-1);
244134e1779SJakub Wojciech Klama }
245134e1779SJakub Wojciech Klama
246134e1779SJakub Wojciech Klama msize = le32toh(*(uint32_t *)buffer);
247134e1779SJakub Wojciech Klama toread = msize - sizeof(uint32_t);
248134e1779SJakub Wojciech Klama buffer = l9p_realloc(buffer, msize);
249134e1779SJakub Wojciech Klama
250134e1779SJakub Wojciech Klama ret = xread(fd, (char *)buffer + sizeof(uint32_t), toread);
251134e1779SJakub Wojciech Klama if (ret < 0) {
252134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR, "read(): %s", strerror(errno));
253134e1779SJakub Wojciech Klama return (-1);
254134e1779SJakub Wojciech Klama }
255134e1779SJakub Wojciech Klama
256134e1779SJakub Wojciech Klama if (ret != (ssize_t)toread) {
257134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR, "short read: %zd bytes of %zd expected",
258134e1779SJakub Wojciech Klama ret, toread);
259134e1779SJakub Wojciech Klama return (-1);
260134e1779SJakub Wojciech Klama }
261134e1779SJakub Wojciech Klama
262134e1779SJakub Wojciech Klama *size = msize;
263134e1779SJakub Wojciech Klama *buf = buffer;
264134e1779SJakub Wojciech Klama L9P_LOG(L9P_INFO, "%p: read complete message, buf=%p size=%d",
265134e1779SJakub Wojciech Klama (void *)sc->ls_conn, buffer, msize);
266134e1779SJakub Wojciech Klama
267134e1779SJakub Wojciech Klama return (0);
268134e1779SJakub Wojciech Klama }
269134e1779SJakub Wojciech Klama
270134e1779SJakub Wojciech Klama static int
l9p_socket_get_response_buffer(struct l9p_request * req,struct iovec * iov,size_t * niovp,void * arg __unused)271134e1779SJakub Wojciech Klama l9p_socket_get_response_buffer(struct l9p_request *req, struct iovec *iov,
272134e1779SJakub Wojciech Klama size_t *niovp, void *arg __unused)
273134e1779SJakub Wojciech Klama {
274134e1779SJakub Wojciech Klama size_t size = req->lr_conn->lc_msize;
275134e1779SJakub Wojciech Klama void *buf;
276134e1779SJakub Wojciech Klama
277134e1779SJakub Wojciech Klama buf = l9p_malloc(size);
278134e1779SJakub Wojciech Klama iov[0].iov_base = buf;
279134e1779SJakub Wojciech Klama iov[0].iov_len = size;
280134e1779SJakub Wojciech Klama
281134e1779SJakub Wojciech Klama *niovp = 1;
282134e1779SJakub Wojciech Klama return (0);
283134e1779SJakub Wojciech Klama }
284134e1779SJakub Wojciech Klama
285134e1779SJakub Wojciech Klama static int
l9p_socket_send_response(struct l9p_request * req __unused,const struct iovec * iov,const size_t niov __unused,const size_t iolen,void * arg)286134e1779SJakub Wojciech Klama l9p_socket_send_response(struct l9p_request *req __unused,
287134e1779SJakub Wojciech Klama const struct iovec *iov, const size_t niov __unused, const size_t iolen,
288134e1779SJakub Wojciech Klama void *arg)
289134e1779SJakub Wojciech Klama {
290134e1779SJakub Wojciech Klama struct l9p_socket_softc *sc = (struct l9p_socket_softc *)arg;
291134e1779SJakub Wojciech Klama
292134e1779SJakub Wojciech Klama assert(sc->ls_fd >= 0);
293134e1779SJakub Wojciech Klama
294134e1779SJakub Wojciech Klama L9P_LOG(L9P_DEBUG, "%p: sending reply, buf=%p, size=%d", arg,
295134e1779SJakub Wojciech Klama iov[0].iov_base, iolen);
296134e1779SJakub Wojciech Klama
297134e1779SJakub Wojciech Klama if (xwrite(sc->ls_fd, iov[0].iov_base, iolen) != (int)iolen) {
298134e1779SJakub Wojciech Klama L9P_LOG(L9P_ERROR, "short write: %s", strerror(errno));
299134e1779SJakub Wojciech Klama return (-1);
300134e1779SJakub Wojciech Klama }
301134e1779SJakub Wojciech Klama
302134e1779SJakub Wojciech Klama free(iov[0].iov_base);
303134e1779SJakub Wojciech Klama return (0);
304134e1779SJakub Wojciech Klama }
305134e1779SJakub Wojciech Klama
306134e1779SJakub Wojciech Klama static void
l9p_socket_drop_response(struct l9p_request * req __unused,const struct iovec * iov,size_t niov __unused,void * arg __unused)307134e1779SJakub Wojciech Klama l9p_socket_drop_response(struct l9p_request *req __unused,
308*067bb820SJakub Wojciech Klama const struct iovec *iov, size_t niov __unused, void *arg __unused)
309134e1779SJakub Wojciech Klama {
310134e1779SJakub Wojciech Klama
311134e1779SJakub Wojciech Klama L9P_LOG(L9P_DEBUG, "%p: drop buf=%p", arg, iov[0].iov_base);
312134e1779SJakub Wojciech Klama free(iov[0].iov_base);
313134e1779SJakub Wojciech Klama }
314134e1779SJakub Wojciech Klama
315134e1779SJakub Wojciech Klama static ssize_t
xread(int fd,void * buf,size_t count)316134e1779SJakub Wojciech Klama xread(int fd, void *buf, size_t count)
317134e1779SJakub Wojciech Klama {
318134e1779SJakub Wojciech Klama size_t done = 0;
319134e1779SJakub Wojciech Klama ssize_t ret;
320134e1779SJakub Wojciech Klama
321134e1779SJakub Wojciech Klama while (done < count) {
322134e1779SJakub Wojciech Klama ret = read(fd, (char *)buf + done, count - done);
323134e1779SJakub Wojciech Klama if (ret < 0) {
324134e1779SJakub Wojciech Klama if (errno == EINTR)
325134e1779SJakub Wojciech Klama continue;
326134e1779SJakub Wojciech Klama
327134e1779SJakub Wojciech Klama return (-1);
328134e1779SJakub Wojciech Klama }
329134e1779SJakub Wojciech Klama
330134e1779SJakub Wojciech Klama if (ret == 0)
331134e1779SJakub Wojciech Klama return ((ssize_t)done);
332134e1779SJakub Wojciech Klama
333134e1779SJakub Wojciech Klama done += (size_t)ret;
334134e1779SJakub Wojciech Klama }
335134e1779SJakub Wojciech Klama
336134e1779SJakub Wojciech Klama return ((ssize_t)done);
337134e1779SJakub Wojciech Klama }
338134e1779SJakub Wojciech Klama
339134e1779SJakub Wojciech Klama static ssize_t
xwrite(int fd,void * buf,size_t count)340134e1779SJakub Wojciech Klama xwrite(int fd, void *buf, size_t count)
341134e1779SJakub Wojciech Klama {
342134e1779SJakub Wojciech Klama size_t done = 0;
343134e1779SJakub Wojciech Klama ssize_t ret;
344134e1779SJakub Wojciech Klama
345134e1779SJakub Wojciech Klama while (done < count) {
346134e1779SJakub Wojciech Klama ret = write(fd, (char *)buf + done, count - done);
347134e1779SJakub Wojciech Klama if (ret < 0) {
348134e1779SJakub Wojciech Klama if (errno == EINTR)
349134e1779SJakub Wojciech Klama continue;
350134e1779SJakub Wojciech Klama
351134e1779SJakub Wojciech Klama return (-1);
352134e1779SJakub Wojciech Klama }
353134e1779SJakub Wojciech Klama
354134e1779SJakub Wojciech Klama if (ret == 0)
355134e1779SJakub Wojciech Klama return ((ssize_t)done);
356134e1779SJakub Wojciech Klama
357134e1779SJakub Wojciech Klama done += (size_t)ret;
358134e1779SJakub Wojciech Klama }
359134e1779SJakub Wojciech Klama
360134e1779SJakub Wojciech Klama return ((ssize_t)done);
361134e1779SJakub Wojciech Klama }
362