1 : #ifndef EX_UTILS_H
2 : #define EX_UTILS_H 1
3 :
4 : /* ************************************************************************** */
5 : /* headers: Vstr (and all supporting system headers), plus extra ones we need */
6 : /* ************************************************************************** */
7 : #define _GNU_SOURCE 1 /* for posix_fadvice etc. */
8 : #define VSTR_COMPILE_INCLUDE 1 /* make Vstr include it's system headers */
9 : #include <vstr.h>
10 :
11 : #include <errno.h>
12 :
13 : #include <err.h> /* BSD/Linux header see: man errx */
14 :
15 : #include <poll.h>
16 :
17 : #include <sys/types.h> /* stat + open + STDXXX_FILENO */
18 : #include <sys/stat.h>
19 : #include <unistd.h>
20 : #include <fcntl.h>
21 :
22 : #include <string.h> /* strncmp() etc. in GETOPT macros */
23 :
24 : #include "compiler.h" /* includes autoconf.h */
25 :
26 : #undef NULL
27 : #define NULL ((void *)0) /* fix C++/old-C braindamage */
28 :
29 : /* fix.h ? */
30 : #ifndef O_NOATIME
31 : #define O_NOATIME 0
32 : #endif
33 :
34 : /* **************************************************************** */
35 : /* defines: TRUE/FALSE and assert(), Note that GETOPT is used later */
36 : /* **************************************************************** */
37 :
38 : #ifndef FALSE
39 : # define FALSE 0
40 : #endif
41 :
42 : #ifndef TRUE
43 : # define TRUE 1
44 : #endif
45 :
46 : #ifndef SWAP_TYPE
47 : #define SWAP_TYPE(x, y, type) do { \
48 : type internal_local_tmp = (x); \
49 : (x) = (y); \
50 : (y) = internal_local_tmp; \
51 : } while (FALSE)
52 : #endif
53 :
54 : /* help the programmers with the double negatives all the time */
55 : #define CSTREQ(x, y) (!strcmp(x, y))
56 :
57 : /* values, values, values */
58 : #define min_t(T, a, b) ((((T)(a)) > ((T)(b))) ? (a) : (b))
59 : #define max_t(T, a, b) ((((T)(a)) < ((T)(b))) ? (a) : (b))
60 :
61 :
62 : /* Simple getopt code... */
63 : #define EX_UTILS_GETOPT_NUM(name, var) \
64 : else if (!strncmp("--" name "=", argv[count], strlen("--" name "=")) || \
65 : !strncmp("--" name, argv[count], strlen(argv[count]))) \
66 : { \
67 : if (strncmp("--" name, argv[count], strlen(argv[count]))) \
68 : (var) = strtol(argv[count] + strlen("--" name "="), NULL, 0); \
69 : else \
70 : { \
71 : (var) = 0; \
72 : \
73 : ++count; \
74 : if (count >= argc) \
75 : break; \
76 : \
77 : (var) = strtol(argv[count], NULL, 0); \
78 : } \
79 : } \
80 : else if (0) ASSERT(FALSE)
81 :
82 : #define EX_UTILS_GETOPT_CSTR(name, var) \
83 : else if (!strncmp("--" name "=", argv[count], strlen("--" name "=")) || \
84 : !strncmp("--" name, argv[count], strlen(argv[count]))) \
85 : { \
86 : if (strncmp("--" name, argv[count], strlen(argv[count]))) \
87 : (var) = argv[count] + strlen("--" name "="); \
88 : else \
89 : { \
90 : (var) = NULL; \
91 : \
92 : ++count; \
93 : if (count >= argc) \
94 : break; \
95 : \
96 : (var) = argv[count]; \
97 : } \
98 : } \
99 : else if (0) ASSERT(FALSE)
100 :
101 : #define EX_UTILS_GETOPT_TOGGLE(name, var) \
102 : else if (!strncmp("--" name, argv[count], strlen(argv[count]))) \
103 : (var) = !(var); \
104 : else if (0) ASSERT(FALSE)
105 :
106 :
107 : #if COMPILE_DEBUG
108 : # define assert(x) do { if (x) {} else { warnx("assert(%s), FAILED at %s:%u", #x , __FILE__, __LINE__); abort(); } } while (FALSE)
109 : # define ASSERT(x) do { if (x) {} else { warnx("ASSERT(%s), FAILED at %s:%u", #x , __FILE__, __LINE__); abort(); } } while (FALSE)
110 : # define assert_ret(x, y) do { if (x) {} else { warnx("assert(%s), FAILED at %s:%u", #x , __FILE__, __LINE__); abort(); } } while (FALSE)
111 : # define ASSERT_RET(x, y) do { if (x) {} else { warnx("ASSERT(%s), FAILED at %s:%u", #x , __FILE__, __LINE__); abort(); } } while (FALSE)
112 : # define ASSERT_NO_SWITCH_DEF() break; default: ASSERT(!"default label")
113 : #else
114 : # define assert(x) do { } while (FALSE)
115 : # define ASSERT(x) do { } while (FALSE)
116 : # define assert_ret(x, y) do { if (x) {} else return y; } while (FALSE)
117 : # define ASSERT_RET(x, y) do { if (x) {} else return y; } while (FALSE)
118 : # define ASSERT_NO_SWITCH_DEF() break
119 : #endif
120 : #define ASSERT_NOT_REACHED() ASSERT(!"not reached")
121 :
122 :
123 : /* ********************************* */
124 : /* generic POSIX IO helper functions */
125 : /* ********************************* */
126 :
127 : /* limits on amount of data we keep in core -- can be overridden */
128 : /* Note that EX_UTILS_NO_USE_INPUT should be defined if Input IO isn't needed */
129 : #ifndef EX_MAX_R_DATA_INCORE
130 : #define EX_MAX_R_DATA_INCORE (8 * 1024)
131 : #endif
132 : #ifndef EX_MAX_W_DATA_INCORE
133 : #define EX_MAX_W_DATA_INCORE (8 * 1024)
134 : #endif
135 :
136 : #ifndef EX_UTILS_RET_FAIL
137 : #define EX_UTILS_RET_FAIL FALSE
138 : #endif
139 :
140 : #define IO_OK 0
141 : #define IO_BLOCK 1
142 : #define IO_EOF 2
143 : #define IO_NONE 3
144 : #define IO_FAIL 4
145 :
146 : #if !defined(EX_UTILS_NO_FUNCS) && !defined(EX_UTILS_NO_USE_BLOCK)
147 : /* block waiting for IO read, write or both... */
148 : static void io_block(int io_r_fd, int io_w_fd)
149 0 : {
150 : struct pollfd ios_beg[2];
151 0 : struct pollfd *ios = ios_beg;
152 0 : unsigned int num = 0;
153 :
154 0 : ios[0].revents = ios[1].revents = 0;
155 :
156 0 : if (io_r_fd == io_w_fd)
157 : { /* block on both read and write, same fds */
158 0 : num = 1;
159 0 : ios[0].events = POLLIN | POLLOUT;
160 0 : ios[0].fd = io_w_fd;
161 : }
162 : else
163 : { /* block on read or write or both */
164 0 : if (io_r_fd != -1)
165 : {
166 0 : ios->events = POLLIN;
167 0 : ios->fd = io_r_fd;
168 0 : ++num; ++ios;
169 : }
170 0 : if (io_w_fd != -1)
171 : {
172 0 : ios->events = POLLOUT;
173 0 : ios->fd = io_w_fd;
174 0 : ++num; ++ios;
175 : }
176 : }
177 :
178 0 : while (poll(ios_beg, num, -1) == -1) /* can't timeout */
179 : {
180 0 : if (errno != EINTR)
181 0 : err(EXIT_FAILURE, "poll");
182 : }
183 0 : }
184 : #endif
185 :
186 : /* Try and move some data from Vstr string to fd */
187 : #if !defined(EX_UTILS_NO_FUNCS) && !defined(EX_UTILS_NO_USE_PUT)
188 : static int io_put(Vstr_base *io_w, int fd)
189 208 : {
190 208 : if (!io_w->len)
191 104 : return (IO_NONE);
192 :
193 104 : if (!vstr_sc_write_fd(io_w, 1, io_w->len, fd, NULL))
194 : {
195 0 : if (errno == EAGAIN)
196 0 : return (IO_BLOCK);
197 :
198 : if (EX_UTILS_RET_FAIL)
199 0 : return (IO_FAIL);
200 :
201 0 : err(EXIT_FAILURE, "write");
202 : }
203 :
204 104 : return (IO_OK);
205 : }
206 : #endif
207 :
208 : #if !defined(EX_UTILS_NO_FUNCS) && !defined(EX_UTILS_NO_USE_BLOCK)
209 : #ifndef EX_UTILS_NO_USE_PUTALL
210 : /* loop outputting data until empty, blocking when needed */
211 : static int io_put_all(Vstr_base *io_w, int fd)
212 104 : {
213 104 : int state = IO_NONE;
214 :
215 304 : while ((state = io_put(io_w, fd)) != IO_NONE)
216 : {
217 96 : if (state == IO_BLOCK)
218 0 : io_block(-1, fd);
219 :
220 24 : if (EX_UTILS_RET_FAIL && (state == IO_FAIL))
221 0 : return (IO_FAIL);
222 : }
223 :
224 104 : return (state);
225 : }
226 : #endif
227 : #endif
228 :
229 : #if !defined(EX_UTILS_NO_FUNCS) && !defined(EX_UTILS_NO_USE_INPUT)
230 : #ifndef EX_UTILS_NO_USE_GET
231 : /* Try and move some data from fd to Vstr string */
232 : static int io_get(Vstr_base *io_r, int fd)
233 6462 : {
234 6462 : if (io_r->len < EX_MAX_R_DATA_INCORE)
235 : {
236 6462 : unsigned int ern = 0;
237 :
238 6462 : vstr_sc_read_iov_fd(io_r, io_r->len, fd, 56, 64, &ern);
239 :
240 6462 : if (ern == VSTR_TYPE_SC_READ_FD_ERR_EOF)
241 10 : return (IO_EOF);
242 6452 : else if ((ern == VSTR_TYPE_SC_READ_FD_ERR_READ_ERRNO) && (errno == EAGAIN))
243 0 : return (IO_BLOCK);
244 : else if (EX_UTILS_RET_FAIL && ern)
245 : return (IO_FAIL);
246 6452 : else if (ern)
247 0 : err(EXIT_FAILURE, "read");
248 : }
249 :
250 6452 : return (IO_OK);
251 : }
252 : #endif
253 :
254 : #if !defined(EX_UTILS_NO_FUNCS) && !defined(EX_UTILS_NO_USE_LIMIT)
255 : /* block read or writting, depending on limits */
256 : static void io_limit(int io_r_state, int io_r_fd,
257 : int io_w_state, int io_w_fd, Vstr_base *s_w)
258 8 : {
259 8 : if (io_w_state == IO_BLOCK) /* maybe allow data to build up */
260 : {
261 0 : if (io_r_state == IO_BLOCK) /* block to either get or put some data */
262 0 : io_block(io_r_fd, io_w_fd);
263 0 : else if (s_w->len > EX_MAX_W_DATA_INCORE)
264 0 : io_block(-1, io_w_fd); /* block to put more data */
265 : }
266 8 : else if ((io_w_state == IO_NONE) && (io_r_state == IO_BLOCK))
267 0 : io_block(io_r_fd, -1); /* block to get more data */
268 8 : }
269 : #endif
270 : #endif
271 :
272 : /* generic POSIX IO functions that _don't_ call Vstr functions */
273 :
274 : #if !defined(EX_UTILS_NO_FUNCS) && !defined(EX_UTILS_NO_USE_IO_FD)
275 : static int io_fd_set_o_nonblock(int fd)
276 88 : {
277 88 : int flags = 0;
278 :
279 : /* see if the NONBLOCK flag is set... */
280 88 : if ((flags = fcntl(fd, F_GETFL)) == -1)
281 0 : return (FALSE);
282 :
283 : /* if it isn't try and add it to the current flags */
284 88 : if (!(flags & O_NONBLOCK) &&
285 : (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1))
286 0 : return (FALSE);
287 :
288 88 : return (TRUE);
289 : }
290 : #endif
291 :
292 :
293 : #ifdef VSTR_AUTOCONF_HAVE_OPEN64
294 : # define EX_UTILS_OPEN open64
295 : #else
296 : # define EX_UTILS_OPEN open
297 : #endif
298 :
299 : /* This is inherited from open() on Linux, is it always? */
300 : #ifdef __linux__
301 : # define OS_INHERITS_NONBLOCK_FROM_OPEN 1
302 : #else
303 : # define OS_INHERITS_NONBLOCK_FROM_OPEN 0
304 : #endif
305 :
306 : #if !defined(EX_UTILS_NO_FUNCS) && !defined(EX_UTILS_NO_USE_OPEN)
307 : # ifndef VSTR_AUTOCONF_HAVE_OPEN64
308 : # define open64 open
309 : # endif
310 : static int io__open(const char *filename, int xflags)
311 72441 : { /* do we alway6s want to do this for fifo's ? */
312 72441 : int flags = O_RDONLY | O_NOCTTY | xflags;
313 72441 : int fd = EX_UTILS_OPEN(filename, flags);
314 :
315 72433 : if ((fd == -1) && EX_UTILS_RET_FAIL)
316 39320 : return (-1);
317 :
318 33121 : if (fd == -1)
319 0 : err(EXIT_FAILURE, "open(%s)", filename);
320 :
321 : /* When doing IO, it should always be non-blocking -- doesn't work
322 : * for files, but fd object might be a FIFO etc. */
323 33121 : if (!OS_INHERITS_NONBLOCK_FROM_OPEN || !(xflags & O_NONBLOCK))
324 8 : io_fd_set_o_nonblock(fd);
325 :
326 33121 : return (fd);
327 : }
328 : #if !defined(EX_UTILS_NO_USE_BLOCK) && !defined(EX_UTILS_NO_USE_BLOCKING_OPEN)
329 : static int io_open(const char *filename)
330 8 : {
331 8 : return (io__open(filename, 0));
332 : }
333 : #endif
334 : #ifdef EX_UTILS_USE_NONBLOCKING_OPEN
335 : static int io_open_nonblock(const char *filename)
336 : {
337 : return (io__open(filename, O_NONBLOCK));
338 : }
339 : #endif
340 : #endif
341 :
342 : /* ************************ */
343 : /* generic helper functions */
344 : /* ************************ */
345 :
346 : #if !defined(EX_UTILS_NO_FUNCS) && !defined(EX_UTILS_NO_USE_INIT)
347 : /* Example init function */
348 : static Vstr_base *ex_init(Vstr_base **s2)
349 80 : {
350 80 : Vstr_base *s1 = NULL;
351 : struct stat64 stat_buf;
352 :
353 80 : if (!vstr_init()) /* init the library */
354 0 : errno = ENOMEM, err(EXIT_FAILURE, "init");
355 :
356 :
357 : /* alter the node buffer size to be whatever the stdout block size is */
358 80 : if (fstat64(1, &stat_buf) == -1)
359 : {
360 0 : warn("fstat(STDOUT)");
361 0 : stat_buf.st_blksize = 0;
362 : }
363 :
364 80 : if (!stat_buf.st_blksize) /* this is allowed to be Zero -- *BSD proc */
365 0 : stat_buf.st_blksize = 4096;
366 :
367 80 : if (!vstr_cntl_conf(NULL, VSTR_CNTL_CONF_SET_NUM_BUF_SZ,
368 : stat_buf.st_blksize / 32))
369 0 : warnx("Couldn't alter node size to match block size");
370 :
371 : /* create strings... */
372 80 : if (!(s1 = vstr_make_base(NULL)) ||
373 : (s2 && !(*s2 = vstr_make_base(NULL))))
374 0 : errno = ENOMEM, err(EXIT_FAILURE, "Create string");
375 :
376 : /* create some data storage for _both_ of the above strings */
377 80 : vstr_make_spare_nodes(NULL, VSTR_TYPE_NODE_BUF, 64);
378 :
379 : /* Try and make stdout non-blocking, if it is a file this won't do anything */
380 80 : io_fd_set_o_nonblock(STDOUT_FILENO);
381 :
382 80 : return (s1);
383 : }
384 : #endif
385 :
386 : #if !defined(EX_UTILS_NO_FUNCS) && !defined(EX_UTILS_NO_USE_EXIT)
387 : /* Example exit function */
388 : static int ex_exit(Vstr_base *s1, Vstr_base *s2)
389 80 : {
390 : /* These next calls are only really needed for debugging,
391 : * in that when they are done any memory leaks can be seen in debugging mode.
392 : */
393 :
394 : /* As with the system free() both of these are ok if passed NULL */
395 :
396 : /* free s1, our String object */
397 80 : vstr_free_base(s1);
398 : /* free s2, our String object */
399 80 : vstr_free_base(s2);
400 :
401 : /* "exit" Vstr, this free's all internal data and no library calls apart from
402 : * vstr_init() should be called after this.
403 : */
404 80 : vstr_exit();
405 :
406 80 : return (EXIT_SUCCESS);
407 : }
408 : #endif
409 :
410 : #endif
|