xref: /openbsd-src/sbin/ldattach/atomicio.c (revision c939d23609443b2ad7e09a909da8b6dc772dca5b)
1*c939d236Sderaadt /* $OpenBSD: atomicio.c,v 1.2 2012/12/04 02:38:51 deraadt Exp $ */
2330f45acSmbalmer /*
3330f45acSmbalmer  * Copyright (c) 2006 Damien Miller. All rights reserved.
4330f45acSmbalmer  * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved.
5330f45acSmbalmer  * Copyright (c) 1995,1999 Theo de Raadt.  All rights reserved.
6330f45acSmbalmer  * All rights reserved.
7330f45acSmbalmer  *
8330f45acSmbalmer  * Redistribution and use in source and binary forms, with or without
9330f45acSmbalmer  * modification, are permitted provided that the following conditions
10330f45acSmbalmer  * are met:
11330f45acSmbalmer  * 1. Redistributions of source code must retain the above copyright
12330f45acSmbalmer  *    notice, this list of conditions and the following disclaimer.
13330f45acSmbalmer  * 2. Redistributions in binary form must reproduce the above copyright
14330f45acSmbalmer  *    notice, this list of conditions and the following disclaimer in the
15330f45acSmbalmer  *    documentation and/or other materials provided with the distribution.
16330f45acSmbalmer  *
17330f45acSmbalmer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18330f45acSmbalmer  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19330f45acSmbalmer  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20330f45acSmbalmer  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21330f45acSmbalmer  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22330f45acSmbalmer  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23330f45acSmbalmer  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24330f45acSmbalmer  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25330f45acSmbalmer  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26330f45acSmbalmer  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27330f45acSmbalmer  */
28330f45acSmbalmer 
29*c939d236Sderaadt #include <sys/types.h>
30330f45acSmbalmer #include <sys/uio.h>
31330f45acSmbalmer 
32330f45acSmbalmer #include <errno.h>
33330f45acSmbalmer #include <poll.h>
34330f45acSmbalmer #include <string.h>
35*c939d236Sderaadt #include <limits.h>
36330f45acSmbalmer #include <unistd.h>
37330f45acSmbalmer 
38330f45acSmbalmer #include "atomicio.h"
39330f45acSmbalmer 
40330f45acSmbalmer /*
41330f45acSmbalmer  * ensure all of data on socket comes through. f==read || f==vwrite
42330f45acSmbalmer  */
43330f45acSmbalmer size_t
atomicio(ssize_t (* f)(int,void *,size_t),int fd,void * _s,size_t n)44330f45acSmbalmer atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n)
45330f45acSmbalmer {
46330f45acSmbalmer 	char *s = _s;
47330f45acSmbalmer 	size_t pos = 0;
48330f45acSmbalmer 	ssize_t res;
49330f45acSmbalmer 	struct pollfd pfd;
50330f45acSmbalmer 
51330f45acSmbalmer 	pfd.fd = fd;
52330f45acSmbalmer 	pfd.events = f == read ? POLLIN : POLLOUT;
53330f45acSmbalmer 	while (n > pos) {
54330f45acSmbalmer 		res = (f) (fd, s + pos, n - pos);
55330f45acSmbalmer 		switch (res) {
56330f45acSmbalmer 		case -1:
57330f45acSmbalmer 			if (errno == EINTR)
58330f45acSmbalmer 				continue;
59330f45acSmbalmer 			if (errno == EAGAIN) {
60330f45acSmbalmer 				(void)poll(&pfd, 1, -1);
61330f45acSmbalmer 				continue;
62330f45acSmbalmer 			}
63330f45acSmbalmer 			return 0;
64330f45acSmbalmer 		case 0:
65330f45acSmbalmer 			errno = EPIPE;
66330f45acSmbalmer 			return pos;
67330f45acSmbalmer 		default:
68330f45acSmbalmer 			pos += (size_t)res;
69330f45acSmbalmer 		}
70330f45acSmbalmer 	}
71330f45acSmbalmer 	return (pos);
72330f45acSmbalmer }
73330f45acSmbalmer 
74330f45acSmbalmer /*
75330f45acSmbalmer  * ensure all of data on socket comes through. f==readv || f==writev
76330f45acSmbalmer  */
77330f45acSmbalmer size_t
atomiciov(ssize_t (* f)(int,const struct iovec *,int),int fd,const struct iovec * _iov,int iovcnt)78330f45acSmbalmer atomiciov(ssize_t (*f) (int, const struct iovec *, int), int fd,
79330f45acSmbalmer     const struct iovec *_iov, int iovcnt)
80330f45acSmbalmer {
81330f45acSmbalmer 	size_t pos = 0, rem;
82330f45acSmbalmer 	ssize_t res;
83330f45acSmbalmer 	struct iovec iov_array[IOV_MAX], *iov = iov_array;
84330f45acSmbalmer 	struct pollfd pfd;
85330f45acSmbalmer 
86330f45acSmbalmer 	if (iovcnt > IOV_MAX) {
87330f45acSmbalmer 		errno = EINVAL;
88330f45acSmbalmer 		return 0;
89330f45acSmbalmer 	}
90330f45acSmbalmer 	/* Make a copy of the iov array because we may modify it below */
91330f45acSmbalmer 	memcpy(iov, _iov, iovcnt * sizeof(*_iov));
92330f45acSmbalmer 
93330f45acSmbalmer 	pfd.fd = fd;
94330f45acSmbalmer 	pfd.events = f == readv ? POLLIN : POLLOUT;
95330f45acSmbalmer 	for (; iovcnt > 0 && iov[0].iov_len > 0;) {
96330f45acSmbalmer 		res = (f) (fd, iov, iovcnt);
97330f45acSmbalmer 		switch (res) {
98330f45acSmbalmer 		case -1:
99330f45acSmbalmer 			if (errno == EINTR)
100330f45acSmbalmer 				continue;
101330f45acSmbalmer 			if (errno == EAGAIN) {
102330f45acSmbalmer 				(void)poll(&pfd, 1, -1);
103330f45acSmbalmer 				continue;
104330f45acSmbalmer 			}
105330f45acSmbalmer 			return 0;
106330f45acSmbalmer 		case 0:
107330f45acSmbalmer 			errno = EPIPE;
108330f45acSmbalmer 			return pos;
109330f45acSmbalmer 		default:
110330f45acSmbalmer 			rem = (size_t)res;
111330f45acSmbalmer 			pos += rem;
112330f45acSmbalmer 			/* skip completed iov entries */
113330f45acSmbalmer 			while (iovcnt > 0 && rem >= iov[0].iov_len) {
114330f45acSmbalmer 				rem -= iov[0].iov_len;
115330f45acSmbalmer 				iov++;
116330f45acSmbalmer 				iovcnt--;
117330f45acSmbalmer 			}
118330f45acSmbalmer 			/* This shouldn't happen... */
119330f45acSmbalmer 			if (rem > 0 && (iovcnt <= 0 || rem > iov[0].iov_len)) {
120330f45acSmbalmer 				errno = EFAULT;
121330f45acSmbalmer 				return 0;
122330f45acSmbalmer 			}
123330f45acSmbalmer 			if (iovcnt == 0)
124330f45acSmbalmer 				break;
125330f45acSmbalmer 			/* update pointer in partially complete iov */
126330f45acSmbalmer 			iov[0].iov_base = ((char *)iov[0].iov_base) + rem;
127330f45acSmbalmer 			iov[0].iov_len -= rem;
128330f45acSmbalmer 		}
129330f45acSmbalmer 	}
130330f45acSmbalmer 	return pos;
131330f45acSmbalmer }
132