Many fixes.
[tem.git] / wrappers.h
blobf519535daf5fcfed6a735a3568d81b4c04b5b459
2 #ifndef _WRAPPERS_H
3 #define _WRAPPERS_H 1
5 #define _GNU_SOURCE 1
7 #include <errno.h>
8 #include <error.h>
9 #include <fcntl.h>
10 #include <limits.h>
11 #include <pwd.h>
12 #include <stdarg.h>
13 #include <stdbool.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/stat.h>
18 #include <sys/types.h>
19 #include <sys/wait.h>
20 #include <termios.h>
21 #include <unistd.h>
23 #include "system.h"
25 #if !__GCC_PREREQ (5, 0)
26 /* https://stackoverflow.com/a/1815371 */
27 static __warn_unused_result __force_inline __nonnull ((3)) bool
28 __builtin_mul_overflow (size_t a, size_t b, size_t *c)
30 # define SIZE_BIT (sizeof (size_t) * CHAR_BIT / 2)
31 # define HI(x) (x >> SIZE_BIT)
32 # define LO(x) ((((size_t)1 << SIZE_BIT) - 1) & x)
34 size_t s0, s1, s2, s3, x, result, carry;
36 x = LO (a) * LO (b);
37 s0 = LO (x);
39 x = HI (a) * LO (b) + HI (x);
40 s1 = LO (x);
41 s2 = HI (x);
43 x = s1 + LO (a) * HI (b);
44 s1 = LO (x);
46 x = s2 + HI (a) * HI (b) + HI (x);
47 s2 = LO (x);
48 s3 = HI (x);
50 result = s1 << SIZE_BIT | s0;
51 carry = s3 << SIZE_BIT | s2;
53 *c = result;
55 return carry != 0;
57 # endif
59 #define mul_overflow(n, m, s) __builtin_mul_overflow (n, m, s)
61 #define edie(e, ...) (error (EXIT_FAILURE, e, __VA_ARGS__), assume (false))
62 #define die(c, s) (fprintf (stderr, "%s\n", s), exit (c), assume (false))
64 static inline bool program_exited_successfully (int status) __warn_unused_result __const;
65 static inline bool
66 program_exited_successfully (int status)
68 return WIFEXITED (status) && WEXITSTATUS (status) == EXIT_SUCCESS;
70 static inline bool program_exited_unsuccessfully (int status) __warn_unused_result __const;
71 static inline bool
72 program_exited_unsuccessfully (int status)
74 return !WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS;
76 static inline bool program_terminated (int status) __warn_unused_result __const;
77 static inline bool
78 program_terminated (int status)
80 return WIFEXITED (status) || (WIFSIGNALED (status) && !WIFSTOPPED (status) && !WIFCONTINUED (status));
83 static inline int xopenat (int dd, const char *file, int oflags, int cflags) __nonnull ((2));
84 static inline int
85 xopenat (int dd, const char *file, int oflags, int cflags)
87 int fd = openat (dd, file, oflags, cflags);
88 if (fd < 0)
89 edie (errno, "openat(%s)", file);
90 return fd;
93 static inline int xopen (const char *file, int oflags, int cflags) __nonnull ((1));
94 static inline int
95 xopen (const char *file, int oflags, int cflags)
97 int fd = open (file, oflags, cflags);
99 if (fd < 0)
100 edie (errno, "open(%s)", file);
102 return fd;
105 static inline void xdup2 (int oldfd, int newfd);
106 static inline void
107 xdup2 (int oldfd, int newfd)
109 if (dup2 (oldfd, newfd) < 0)
110 edie (errno, "dup2(%d, %d)", oldfd, newfd);
113 static inline void xclose (int fd);
114 static inline void
115 xclose (int fd)
117 if (close (fd) < 0)
118 edie (errno, "close(%d)", fd);
121 static inline void
122 xpipe (int pipes[2])
124 if (pipe (pipes) != 0)
125 edie (errno, "pipe()");
128 static inline size_t full_write (int fd, const void *buf, size_t len) __nonnull ((2));
129 static inline size_t
130 full_write (int fd, const void *buf, size_t len)
132 const char *s = buf;
133 size_t n = len;
135 if (len == 0)
137 errno = EINVAL;
138 return 0;
143 int saved_errno = errno;
144 ssize_t ret = write (fd, s, n);
146 if (ret < 0)
148 if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)
150 errno = saved_errno;
151 continue;
153 break;
156 if (ret == 0)
158 /* According to gnulib note.
159 Some buggy drivers return 0 when one tries
160 to write beyond a device's end.
161 (Example: Linux 1.2.13 on /dev/fd0.)
162 Set errno to ENOSPC so they get a sensible
163 diagnostic. */
164 errno = ENOSPC;
165 break;
168 s += ret;
169 n -= ret;
171 while (n != 0);
173 return len - n;
176 static inline size_t full_read (int fd, void *buf, size_t len) __nonnull ((2));
177 static inline size_t
178 full_read (int fd, void *buf, size_t len)
180 char *s = buf;
181 size_t n = len;
183 if (len == 0)
185 errno = EINVAL;
186 return 0;
191 int saved_errno = errno;
192 ssize_t ret = read (fd, s, n);
194 if (ret < 0)
196 if (errno == EWOULDBLOCK || (errno != EINTR && errno != EAGAIN))
198 break;
200 else
202 errno = saved_errno;
203 continue;
207 if (ret == 0)
208 break;
210 s += ret;
211 n -= ret;
213 while (n != 0);
215 return len - n;
218 static inline size_t xread (int fd, void *buf, size_t len);
219 static inline size_t
220 xread (int fd, void *buf, size_t len)
222 size_t r = full_read (fd, buf, len);
224 if (r == 0)
225 edie (errno, "read(%d, %lu)", fd, (unsigned long int) len);
227 return r;
230 static inline size_t xwrite (int fd, const void *buf, size_t len);
231 static inline size_t
232 xwrite (int fd, const void *buf, size_t len)
234 size_t r = full_write (fd, buf, len);
236 if (r == 0)
237 edie (errno, "write(%d, %lu)", fd, (unsigned long int) len);
239 return r;
242 static inline const char *xttyname (int fd) __returns_nonnull;
243 static inline const char *
244 xttyname (int fd)
246 const char *name = ttyname (fd);
248 if (name == NULL)
249 edie (errno, "ttyname(%d)", fd);
251 return name;
254 static inline void *xmalloc (size_t s) __malloc __alloc_size ((1)) __returns_nonnull __warn_unused_result;
255 static inline void *
256 xmalloc (size_t s)
258 void *pointer = malloc (s);
260 if (unlikely (pointer == NULL))
261 edie (errno, "malloc()");
263 return pointer;
266 static inline void *xmallocarray (size_t n, size_t m) __malloc __alloc_size ((1, 2)) __returns_nonnull __warn_unused_result;
267 static inline void *
268 xmallocarray (size_t n, size_t m)
270 size_t s;
272 if (unlikely (mul_overflow (n, m, &s)))
273 edie (ENOMEM, "malloc()");
275 return xmalloc (s);
278 static inline void *xrealloc (void *pointer, size_t s) __malloc __nonnull ((1)) __alloc_size ((2)) __returns_nonnull __warn_unused_result;
279 static inline void *
280 xrealloc (void *pointer, size_t s)
282 pointer = realloc (pointer, s);
284 if (unlikely (pointer == NULL))
285 edie (errno, "realloc()");
287 return pointer;
290 static inline void *xreallocarray (void *pointer, size_t n, size_t m) __malloc __nonnull ((1)) __alloc_size ((2, 3)) __returns_nonnull __warn_unused_result;
291 static inline void *
292 xreallocarray (void *pointer, size_t n, size_t m)
294 size_t s;
296 if (unlikely (mul_overflow (n, m, &s)))
297 edie (ENOMEM, "realloc()");
299 pointer = realloc (pointer, s);
301 if (unlikely (pointer == NULL))
302 edie (errno, "realloc()");
304 return pointer;
307 static inline pid_t xfork (void) __warn_unused_result;
308 static inline pid_t
309 xfork (void)
311 pid_t pid = fork ();
313 if (unlikely (pid < 0))
314 edie (errno, "fork()");
316 return pid;
319 static inline pid_t xwaitpid (pid_t pid, int *status, int flags) __nonnull ((2));
320 static inline pid_t
321 xwaitpid (pid_t pid, int *status, int flags)
323 pid_t r;
325 while (unlikely ((r = waitpid (pid, status, flags)) < 0))
326 if (unlikely (errno != EINTR))
327 edie (errno, "waitpid()");
329 return r;
332 static inline void xexecvpe (char *file, char **argv, char **envp) __noreturn __nonnull ((1, 2, 3));
333 static inline void
334 xexecvpe (char *file, char **argv, char **envp)
336 execvpe (file, argv, envp);
337 /* Unreachable on success. */
338 edie (errno, "execvpe(\"%s\")", file);
341 static inline sighandler_t
342 xsignal (int signo, sighandler_t handler)
344 sighandler_t previous = signal (signo, handler);
346 if (previous == SIG_ERR)
347 edie (errno, "signal(%d)", signo);
349 return previous;
352 static inline void
353 xraise (int signo)
355 if (unlikely (raise (signo) != 0))
356 edie (errno, "raise(%d)", signo);
359 static inline void
360 xkill (pid_t pid, int signo)
362 if (unlikely (kill (pid, signo) != 0))
363 edie (errno, "kill(%d, %d)", pid, signo);
366 static inline void xchmod (const char *file_name, mode_t mode) __nonnull ((1));
367 static inline void
368 xchmod (const char *file_name, mode_t mode)
370 if (unlikely (chmod (file_name, mode) != 0))
371 edie (errno, "chmod(%s, %o)", file_name, mode);
374 static inline void xmkdir (const char *directory_name, mode_t mode) __nonnull ((1));
375 static inline void
376 xmkdir (const char *directory_name, mode_t mode)
378 if (unlikely (mode & ~07777))
379 edie (EINVAL, "mkdir(%s, %o)", directory_name, mode);
381 if (unlikely (mkdir (directory_name, mode) != 0))
383 struct stat sb;
385 if (unlikely (errno != EEXIST))
386 edie (errno, "mkdir(%s, %o)", directory_name, mode);
387 /* Do not die if there is directory with given name. */
389 if (unlikely (stat (directory_name, &sb) != 0))
390 edie (errno, "stat(%s)", directory_name);
392 if (unlikely (!S_ISDIR (sb.st_mode)))
393 edie (ENOTDIR, "%s", directory_name);
395 /* If directory exists make sure that it has required mode. */
396 if (unlikely ((sb.st_mode & 07777) != mode))
397 xchmod (directory_name, mode);
401 static inline void xunlinkat (int dd, const char *path) __nonnull ((2));
402 static inline void
403 xunlinkat (int dd, const char *path)
405 if (unlinkat (dd, path, 0) < 0 && errno != ENOENT)
406 edie (errno, "unlinkat(%s)", path);
409 static inline void xrmdir (const char *directory_name) __nonnull ((1));
410 static inline void
411 xrmdir (const char *directory_name)
413 if (rmdir (directory_name) != 0 && errno != ENOENT)
414 edie (errno, "rmdir()");
417 static inline int xsprintf (char *s, const char *fmt, ...) __nonnull ((1, 2)) __format_printf (2, 3);
418 static inline int
419 xsprintf (char *s, const char *fmt, ...)
421 int n;
422 va_list ap;
424 va_start (ap, fmt);
425 n = vsprintf (s, fmt, ap);
426 va_end (ap);
428 if (n < 0)
429 edie (errno, "sprintf()");
431 return n;
434 #if 0
435 static inline int xasprintf (char **s, const char *fmt, ...) __nonnull ((1, 2)) __format_printf (2, 3);
436 static inline int
437 xasprintf (char **s, const char *fmt, ...)
439 int n;
440 va_list ap, ap2;
442 va_start (ap, fmt);
443 va_copy (ap2, ap);
445 if (unlikely ((n = vsnprintf (NULL, 0, fmt, ap)) < 0))
446 edie (errno, "vsnprintf()");
448 va_end (ap);
450 if (*s == NULL)
451 *s = xmallocarray (n + 1, sizeof (char));
452 else
453 *s = xreallocarray (*s, n + 1, sizeof (char));
455 if (unlikely ((n = vsnprintf (*s, n + 1, fmt, ap2)) < 0))
456 edie (errno, "vsnprintf()");
458 va_end (ap2);
460 return n;
463 static inline void xastrcat (char **d, const char *s) __nonnull ((1, 2));
464 static inline void
465 xastrcat (char **d, const char *s)
467 size_t s_length = strlen (s);
468 size_t d_length = strlen (*d);
469 *d = xreallocarray (*d, d_length + s_length + 1, sizeof (char));
470 strcpy (*d + d_length, s);
472 #endif
474 static inline uid_t xgetuid (void) __warn_unused_result;
475 static inline uid_t
476 xgetuid (void)
478 uid_t uid;
479 int saved_errno = errno;
481 errno = 0;
483 if (unlikely ((uid = getuid ()) == (uid_t) -1 && errno != 0))
484 edie (errno, "getuid()");
486 errno = saved_errno;
488 return uid;
491 static inline struct passwd *xgetpwuid (uid_t uid)
492 __warn_unused_result __malloc;
493 static inline struct passwd *
494 xgetpwuid (uid_t uid)
496 int s;
497 size_t size = 64;
498 char *p = xmalloc (sizeof (struct passwd) + size);
499 struct passwd *result = NULL;
503 s = getpwuid_r (uid, (struct passwd *) p, p + sizeof (struct passwd), size, &result);
505 if (s == EINTR)
506 continue; /* Try again. */
508 if (s == ERANGE)
510 if (mul_overflow (2, size, &size))
511 edie (ENOMEM, "getpwuid_r(%lu)", (unsigned long int) uid);
513 p = xrealloc (p, sizeof (struct passwd) + size);
514 continue;
517 /* We either got an error, or we succeeded and the
518 returned name fit in the buffer. */
519 break;
521 while (true);
523 if (s != 0)
525 free (p);
526 result = NULL;
527 edie (s, "getpwuid_r(%lu)", (unsigned long int) uid);
529 else if (result == NULL)
531 free (p);
532 edie (0, "no matching password record was found for user with uid %lu",
533 (unsigned long int) uid);
536 return result;
539 static inline char *xgetwd (void) __returns_nonnull __warn_unused_result __malloc;
540 static inline char *
541 xgetwd (void)
543 size_t size = PATH_MAX;
544 char *buffer = xmalloc (PATH_MAX);
545 char *p;
547 while ((p = getcwd (buffer, size)) == NULL)
548 if (errno == ERANGE)
549 buffer = xrealloc (buffer, size *= 2);
550 else
551 edie (errno, "getcwd()");
553 return xrealloc (p, strlen (p) + 1);
556 static inline void xtcgetattr (int fd, struct termios *termiosp) __nonnull ((2));
557 static inline void
558 xtcgetattr (int fd, struct termios *termiosp)
560 if (tcgetattr (fd, termiosp) < 0)
561 edie (errno, "tcgetattr()");
564 static inline void xtcsetattr (int fd, int optional_actions, const struct termios *termiosp) __nonnull ((3));
565 static inline void
566 xtcsetattr (int fd, int optional_actions, const struct termios *termiosp)
568 if (tcsetattr (fd, optional_actions, termiosp) < 0)
569 edie (errno, "tcsetattr()");
572 static inline void xatexit (void (*f) (void)) __nonnull ((1));
573 static inline void
574 xatexit (void (*f) (void))
576 if (atexit (f) != 0)
577 edie (errno, "atexit()");
580 static inline int program_get_status (pid_t pid, int flags) __warn_unused_result;
581 static inline int
582 program_get_status (pid_t pid, int flags)
584 int status;
586 xwaitpid (pid, &status, flags);
588 return status;
591 static inline int wait_program_termination (pid_t pid) __warn_unused_result;
592 static inline int
593 wait_program_termination (pid_t pid)
595 int status;
598 xwaitpid (pid, &status, 0);
599 while (unlikely (!program_terminated (status)));
601 return status;
604 static inline bool program_is_executing (pid_t pid) __warn_unused_result;
605 static inline bool
606 program_is_executing (pid_t pid)
608 /*TODO*/
609 int status;
611 xwaitpid (pid, &status, WNOHANG);
612 return (!program_terminated (status));
615 poison (ttyname);
616 poison (malloc calloc realloc fork kill raise execvpe waitpid);
617 poison (chmod chown fchown mkdir rmdir getuid geteuid getgid setuid seteuid);
618 poison (sprintf snprintf asprintf);
619 poison (tcgetattr tcsetattr atexit read write lseek unlink nice);
621 #endif