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