chiark / gitweb /
basic: modernize conf-files.c a bit
[elogind.git] / src / basic / io-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <poll.h>
23 #include <unistd.h>
24
25 #include "io-util.h"
26
27 int flush_fd(int fd) {
28         struct pollfd pollfd = {
29                 .fd = fd,
30                 .events = POLLIN,
31         };
32
33         for (;;) {
34                 char buf[LINE_MAX];
35                 ssize_t l;
36                 int r;
37
38                 r = poll(&pollfd, 1, 0);
39                 if (r < 0) {
40                         if (errno == EINTR)
41                                 continue;
42
43                         return -errno;
44
45                 } else if (r == 0)
46                         return 0;
47
48                 l = read(fd, buf, sizeof(buf));
49                 if (l < 0) {
50
51                         if (errno == EINTR)
52                                 continue;
53
54                         if (errno == EAGAIN)
55                                 return 0;
56
57                         return -errno;
58                 } else if (l == 0)
59                         return 0;
60         }
61 }
62
63 ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
64         uint8_t *p = buf;
65         ssize_t n = 0;
66
67         assert(fd >= 0);
68         assert(buf);
69
70         /* If called with nbytes == 0, let's call read() at least
71          * once, to validate the operation */
72
73         if (nbytes > (size_t) SSIZE_MAX)
74                 return -EINVAL;
75
76         do {
77                 ssize_t k;
78
79                 k = read(fd, p, nbytes);
80                 if (k < 0) {
81                         if (errno == EINTR)
82                                 continue;
83
84                         if (errno == EAGAIN && do_poll) {
85
86                                 /* We knowingly ignore any return value here,
87                                  * and expect that any error/EOF is reported
88                                  * via read() */
89
90                                 (void) fd_wait_for_event(fd, POLLIN, USEC_INFINITY);
91                                 continue;
92                         }
93
94                         return n > 0 ? n : -errno;
95                 }
96
97                 if (k == 0)
98                         return n;
99
100                 assert((size_t) k <= nbytes);
101
102                 p += k;
103                 nbytes -= k;
104                 n += k;
105         } while (nbytes > 0);
106
107         return n;
108 }
109
110 int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) {
111         ssize_t n;
112
113         n = loop_read(fd, buf, nbytes, do_poll);
114         if (n < 0)
115                 return (int) n;
116         if ((size_t) n != nbytes)
117                 return -EIO;
118
119         return 0;
120 }
121
122 int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
123         const uint8_t *p = buf;
124
125         assert(fd >= 0);
126         assert(buf);
127
128         if (nbytes > (size_t) SSIZE_MAX)
129                 return -EINVAL;
130
131         do {
132                 ssize_t k;
133
134                 k = write(fd, p, nbytes);
135                 if (k < 0) {
136                         if (errno == EINTR)
137                                 continue;
138
139                         if (errno == EAGAIN && do_poll) {
140                                 /* We knowingly ignore any return value here,
141                                  * and expect that any error/EOF is reported
142                                  * via write() */
143
144                                 (void) fd_wait_for_event(fd, POLLOUT, USEC_INFINITY);
145                                 continue;
146                         }
147
148                         return -errno;
149                 }
150
151                 if (_unlikely_(nbytes > 0 && k == 0)) /* Can't really happen */
152                         return -EIO;
153
154                 assert((size_t) k <= nbytes);
155
156                 p += k;
157                 nbytes -= k;
158         } while (nbytes > 0);
159
160         return 0;
161 }
162
163 int pipe_eof(int fd) {
164         struct pollfd pollfd = {
165                 .fd = fd,
166                 .events = POLLIN|POLLHUP,
167         };
168
169         int r;
170
171         r = poll(&pollfd, 1, 0);
172         if (r < 0)
173                 return -errno;
174
175         if (r == 0)
176                 return 0;
177
178         return pollfd.revents & POLLHUP;
179 }
180
181 int fd_wait_for_event(int fd, int event, usec_t t) {
182
183         struct pollfd pollfd = {
184                 .fd = fd,
185                 .events = event,
186         };
187
188         struct timespec ts;
189         int r;
190
191         r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL);
192         if (r < 0)
193                 return -errno;
194
195         if (r == 0)
196                 return 0;
197
198         return pollfd.revents;
199 }
200
201 static size_t nul_length(const uint8_t *p, size_t sz) {
202         size_t n = 0;
203
204         while (sz > 0) {
205                 if (*p != 0)
206                         break;
207
208                 n++;
209                 p++;
210                 sz--;
211         }
212
213         return n;
214 }
215
216 ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) {
217         const uint8_t *q, *w, *e;
218         ssize_t l;
219
220         q = w = p;
221         e = q + sz;
222         while (q < e) {
223                 size_t n;
224
225                 n = nul_length(q, e - q);
226
227                 /* If there are more than the specified run length of
228                  * NUL bytes, or if this is the beginning or the end
229                  * of the buffer, then seek instead of write */
230                 if ((n > run_length) ||
231                     (n > 0 && q == p) ||
232                     (n > 0 && q + n >= e)) {
233                         if (q > w) {
234                                 l = write(fd, w, q - w);
235                                 if (l < 0)
236                                         return -errno;
237                                 if (l != q -w)
238                                         return -EIO;
239                         }
240
241                         if (lseek(fd, n, SEEK_CUR) == (off_t) -1)
242                                 return -errno;
243
244                         q += n;
245                         w = q;
246                 } else if (n > 0)
247                         q += n;
248                 else
249                         q ++;
250         }
251
252         if (q > w) {
253                 l = write(fd, w, q - w);
254                 if (l < 0)
255                         return -errno;
256                 if (l != q - w)
257                         return -EIO;
258         }
259
260         return q - (const uint8_t*) p;
261 }