diff options
Diffstat (limited to 'util/libreboot-utils/lib')
| -rw-r--r-- | util/libreboot-utils/lib/command.c | 4 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/file.c | 242 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/io.c | 27 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/mkhtemp.c | 67 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/rand.c | 69 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/state.c | 4 |
6 files changed, 152 insertions, 261 deletions
diff --git a/util/libreboot-utils/lib/command.c b/util/libreboot-utils/lib/command.c index 526ad03b..3bdc4191 100644 --- a/util/libreboot-utils/lib/command.c +++ b/util/libreboot-utils/lib/command.c @@ -492,8 +492,8 @@ cat_buf(unsigned char *b) if (b == NULL) exitf("null pointer in cat command"); - if (rw_file_exact(STDOUT_FILENO, b, - GBE_PART_SIZE, 0, IO_WRITE, MAX_ZERO_RW_RETRY) < 0) + if (rw_exact(STDOUT_FILENO, b, + GBE_PART_SIZE, 0, IO_WRITE) < 0) exitf("stdout: cat"); } void diff --git a/util/libreboot-utils/lib/file.c b/util/libreboot-utils/lib/file.c index 9c4683ce..a788d4af 100644 --- a/util/libreboot-utils/lib/file.c +++ b/util/libreboot-utils/lib/file.c @@ -16,9 +16,17 @@ more correct usage example: long max = pathconf("/", _PC_PATH_MAX); */ +/* for openat2: */ +#ifdef __linux__ +#if !defined(USE_OPENAT) || \ + ((USE_OPENAT) < 1) /* if 1: use openat, not openat2 */ #ifndef _GNU_SOURCE #define _GNU_SOURCE 1 #endif +#include <linux/openat2.h> +#include <sys/syscall.h> +#endif +#endif #include <sys/types.h> #include <sys/stat.h> @@ -30,12 +38,6 @@ long max = pathconf("/", _PC_PATH_MAX); #include <string.h> #include <unistd.h> -/* for openat2: */ -#ifdef __linux__ -#include <linux/openat2.h> -#include <sys/syscall.h> -#endif - #include "../include/common.h" /* check that a file changed @@ -108,7 +110,7 @@ fsync_dir(const char *path) if_err_sys((rval = fsync_on_eintr(dirfd)) == -1)) goto err_fsync_dir; - close_on_eintr(&dirfd); + xclose(&dirfd); free_and_set_null(&dirbuf); reset_caller_errno(rval); @@ -116,12 +118,12 @@ fsync_dir(const char *path) err_fsync_dir: free_and_set_null(&dirbuf); - close_on_eintr(&dirfd); + xclose(&dirfd); return with_fallback_errno(EIO); } -/* rw_file_exact() - Read perfectly or die +/* rw_exact() - Read perfectly or die * * Read/write, and absolutely insist on an * absolute read; e.g. if 100 bytes are @@ -139,8 +141,8 @@ err_fsync_dir: */ ssize_t -rw_file_exact(int fd, unsigned char *mem, size_t nrw, - off_t off, int rw_type, size_t max_retries) +rw_exact(int fd, unsigned char *mem, size_t nrw, + off_t off, int rw_type) { int saved_errno = errno; ssize_t rval = 0; @@ -148,17 +150,17 @@ rw_file_exact(int fd, unsigned char *mem, size_t nrw, size_t nrw_cur; off_t off_cur; void *mem_cur; - size_t retries_on_zero = 0; errno = 0; if (io_args(fd, mem, nrw, off, rw_type) == -1) - goto err_rw_file_exact; + goto err_rw_exact; while (1) { /* Prevent theoretical overflow */ - if (if_err(rval >= 0 && (size_t)rval > (nrw - rc), EOVERFLOW)) - goto err_rw_file_exact; + if (if_err(rval >= 0 && (size_t)rval > (nrw - (size_t)rc), + EOVERFLOW)) + goto err_rw_exact; rc += rval; if ((size_t)rc >= nrw) @@ -168,42 +170,39 @@ rw_file_exact(int fd, unsigned char *mem, size_t nrw, nrw_cur = (size_t)(nrw - (size_t)rc); if (if_err(off < 0, EOVERFLOW)) - goto err_rw_file_exact; + goto err_rw_exact; off_cur = off + (off_t)rc; - if ((rval = rw(fd, mem_cur, nrw_cur, off_cur, rw_type)) < 0) - goto err_rw_file_exact; - - if (rval == 0) { - if (retries_on_zero++ < max_retries) - continue; - - goto err_rw_file_exact; - } - - retries_on_zero = 0; + if ((rval = rw(fd, mem_cur, nrw_cur, off_cur, rw_type)) <= 0) + goto err_rw_exact; } if (if_err((size_t)rc != nrw, EIO) || (rval = rw_over_nrw(rc, nrw)) < 0) - goto err_rw_file_exact; + goto err_rw_exact; reset_caller_errno(rval); return rval; -err_rw_file_exact: +err_rw_exact: return with_fallback_errno(EIO); } -/* rw() - read-write but with more +/** + * rw() - read-write but with more * safety checks than barebones libc * * A fallback is provided for regular read/write. * rw_type can be IO_READ (read), IO_WRITE (write), * IO_PREAD (pread) or IO_PWRITE + * + * WARNING: this function allows zero-byte returns. + * this is intentional, to mimic libc behaviour. + * use rw_exact if you need to avoid this. + * (ditto partial writes/reads) + * */ - ssize_t rw(int fd, void *mem, size_t nrw, off_t off, int rw_type) @@ -213,27 +212,34 @@ rw(int fd, void *mem, size_t nrw, int saved_errno = errno; errno = 0; - if (io_args(fd, mem, nrw, off, rw_type) == -1) - return with_fallback_errno(EINVAL); - - switch (rw_type) { - case IO_WRITE: - r = write_on_eintr(fd, mem, nrw); - break; - case IO_READ: - r = read_on_eintr(fd, mem, nrw); - break; - case IO_PWRITE: - r = pwrite_on_eintr(fd, mem, nrw, off); - break; - case IO_PREAD: - r = pread_on_eintr(fd, mem, nrw, off); - break; - default: - errno = EINVAL; - break; - } + if (io_args(fd, mem, nrw, off, rw_type) == -1 || + if_err(mem == NULL, EFAULT) || + if_err(fd < 0, EBADF) || + if_err(off < 0, EFAULT) || + if_err(nrw == 0, EINVAL)) + return with_fallback_errno(EIO); + do { + switch (rw_type) { + case IO_READ: + r = read(fd, mem, nrw); + break; + case IO_WRITE: + r = write(fd, mem, nrw); + break; + case IO_PREAD: + r = pread(fd, mem, nrw, off); + break; + case IO_PWRITE: + r = pwrite(fd, mem, nrw, off); + break; + default: + errno = EINVAL; + break; + } + + } while (rw_retry(saved_errno, r)); + if ((rval = rw_over_nrw(r, nrw)) < 0) return with_fallback_errno(EIO); @@ -413,7 +419,7 @@ fs_resolve_at(int dirfd, const char *path, int flags) /* close previous fd if not the original input */ if (curfd != dirfd) - close_on_eintr(&curfd); + xclose(&curfd); curfd = nextfd; nextfd = -1; @@ -426,11 +432,11 @@ err: saved_errno = errno; if (nextfd >= 0) - close_on_eintr(&nextfd); + xclose(&nextfd); /* close curfd only if it's not the original */ if (curfd != dirfd && curfd >= 0) - close_on_eintr(&curfd); + xclose(&curfd); errno = saved_errno; return with_fallback_errno(EIO); @@ -602,20 +608,21 @@ open_file_on_eintr(const char *path, exitf("%s: not a regular file", path); } - if (lseek_on_eintr(*fd, 0, SEEK_CUR) == (off_t)-1) + if (lseek(*fd, 0, SEEK_CUR) == (off_t)-1) exitf("%s: file not seekable", path); errno = saved_errno; /* see previous comment */ } -#ifdef __linux__ /* we use openat2 on linux */ +#if defined(__linux__) && \ + (!defined(USE_OPENAT) || ((USE_OPENAT) < 1)) /* we use openat2 on linux */ int openat_on_eintr(int dirfd, const char *path, int flags, mode_t mode) { struct open_how how = { - .flags = flags, + .flags = (unsigned long long)flags, .mode = mode, .resolve = RESOLVE_BENEATH | @@ -663,20 +670,6 @@ openat_on_eintr(int dirfd, const char *path, } #endif -off_t -lseek_on_eintr(int fd, off_t off, int whence) -{ - int saved_errno = errno; - off_t rval = 0; - errno = 0; - - while (off_retry(saved_errno, - rval = lseek(fd, off, whence))); - - reset_caller_errno(rval); - return rval; -} - int mkdirat_on_eintr(int dirfd, const char *path, mode_t mode) @@ -696,90 +689,6 @@ mkdirat_on_eintr(int dirfd, return rval; } -ssize_t -read_on_eintr(int fd, - void *buf, size_t count) -{ - int saved_errno = errno; - ssize_t rval = 0; - errno = 0; - - if (if_err(buf == NULL, EFAULT) || - if_err(fd < 0, EBADF) || - if_err(count == 0, EINVAL)) - return with_fallback_errno(EIO); - - while (rw_retry(saved_errno, - rval = read(fd, buf, count))); - - reset_caller_errno(rval); - return rval; -} - -ssize_t -pread_on_eintr(int fd, - void *buf, size_t count, - off_t off) -{ - int saved_errno = errno; - ssize_t rval = 0; - errno = 0; - - if (if_err(buf == NULL, EFAULT) || - if_err(fd < 0, EBADF) || - if_err(off < 0, EFAULT) || - if_err(count == 0, EINVAL)) - return with_fallback_errno(EIO); - - while (rw_retry(saved_errno, - rval = pread(fd, buf, count, off))); - - reset_caller_errno(rval); - return rval; -} - -ssize_t -write_on_eintr(int fd, - void *buf, size_t count) -{ - int saved_errno = errno; - ssize_t rval = 0; - errno = 0; - - if (if_err(buf == NULL, EFAULT) || - if_err(fd < 0, EBADF) || - if_err(count == 0, EINVAL)) - return with_fallback_errno(EIO); - - while (rw_retry(saved_errno, - rval = write(fd, buf, count))); - - reset_caller_errno(rval); - return rval; -} - -ssize_t -pwrite_on_eintr(int fd, - void *buf, size_t count, - off_t off) -{ - int saved_errno = errno; - ssize_t rval = 0; - errno = 0; - - if (if_err(buf == NULL, EFAULT) || - if_err(fd < 0, EBADF) || - if_err(off < 0, EFAULT) || - if_err(count == 0, EINVAL)) - return with_fallback_errno(EIO); - - while (rw_retry(saved_errno, - rval = pwrite(fd, buf, count, off))); - - reset_caller_errno(rval); - return rval; -} - int fsync_on_eintr(int fd) { @@ -798,22 +707,19 @@ fsync_on_eintr(int fd) } void -close_on_eintr(int *fd) +xclose(int *fd) { int saved_errno = errno; int rval = 0; if (fd == NULL) - exitf("close_on_eintr: null pointer"); + exitf("xclose: null pointer"); if (*fd < 0) return; errno = 0; - while (fs_retry(saved_errno, - rval = close(*fd))); - - if (rval < 0) - exitf("close_on_eintr: could not close"); + if ((rval = close(*fd)) < 0) + exitf("xclose: could not close"); *fd = -1; @@ -856,18 +762,6 @@ close_on_eintr(int *fd) */ -/* retry switch for offset-based - * functions e.g. lseek - */ -/* retry switch for functions that - return long status e.g. linux syscall - */ -int -off_retry(int saved_errno, off_t rval) -{ - fs_err_retry(); -} - /* retry switch for functions that return long status e.g. linux syscall */ diff --git a/util/libreboot-utils/lib/io.c b/util/libreboot-utils/lib/io.c index f8e67977..6bfbbf51 100644 --- a/util/libreboot-utils/lib/io.c +++ b/util/libreboot-utils/lib/io.c @@ -48,9 +48,7 @@ open_gbe_file(void) if (f->gbe_st.st_nlink == 0) exitf("%s: file unlinked while open", f->fname); - while (fs_retry(saved_errno, - _flags = fcntl(f->gbe_fd, F_GETFL))); - if (_flags == -1) + if ((_flags = fcntl(f->gbe_fd, F_GETFL)) == -1) exitf("%s: fcntl(F_GETFL)", f->fname); /* O_APPEND allows POSIX write() to ignore @@ -108,16 +106,16 @@ read_file(void) /* read main file */ - _r = rw_file_exact(f->gbe_fd, f->buf, f->gbe_file_size, - 0, IO_PREAD, MAX_ZERO_RW_RETRY); + _r = rw_exact(f->gbe_fd, f->buf, f->gbe_file_size, + 0, IO_PREAD); if (_r < 0) exitf("%s: read failed", f->fname); /* copy to tmpfile */ - _r = rw_file_exact(f->tmp_fd, f->buf, f->gbe_file_size, - 0, IO_PWRITE, MAX_ZERO_RW_RETRY); + _r = rw_exact(f->tmp_fd, f->buf, f->gbe_file_size, + 0, IO_PWRITE); if (_r < 0) exitf("%s: %s: copy failed", @@ -139,8 +137,8 @@ read_file(void) if (fsync_on_eintr(f->tmp_fd) == -1) exitf("%s: fsync (tmpfile copy)", f->tname); - _r = rw_file_exact(f->tmp_fd, f->bufcmp, f->gbe_file_size, - 0, IO_PREAD, MAX_ZERO_RW_RETRY); + _r = rw_exact(f->tmp_fd, f->bufcmp, f->gbe_file_size, + 0, IO_PREAD); if (_r < 0) exitf("%s: read failed (cmp)", f->tname); @@ -251,8 +249,8 @@ write_to_gbe_bin(void) saved_errno = errno; - close_on_eintr(&f->tmp_fd); - close_on_eintr(&f->gbe_fd); + xclose(&f->tmp_fd); + xclose(&f->gbe_fd); errno = saved_errno; @@ -437,7 +435,7 @@ gbe_mv(void) tmp_gbe_bin_exists = 0; if (f->gbe_fd > -1) { - close_on_eintr(&f->gbe_fd); + xclose(&f->gbe_fd); if (fsync_dir(f->fname) < 0) { f->io_err_gbe_bin = 1; @@ -445,7 +443,7 @@ gbe_mv(void) } } - close_on_eintr(&f->tmp_fd); + xclose(&f->tmp_fd); /* before this function is called, * tmp_fd may have been moved @@ -556,8 +554,7 @@ rw_gbe_file_exact(int fd, unsigned char *mem, size_t nrw, if (nrw > (size_t)GBE_PART_SIZE) goto err_rw_gbe_file_exact; - r = rw_file_exact(fd, mem, nrw, off, rw_type, - MAX_ZERO_RW_RETRY); + r = rw_exact(fd, mem, nrw, off, rw_type); return rw_over_nrw(r, nrw); diff --git a/util/libreboot-utils/lib/mkhtemp.c b/util/libreboot-utils/lib/mkhtemp.c index 4d7ad0bd..bb714b82 100644 --- a/util/libreboot-utils/lib/mkhtemp.c +++ b/util/libreboot-utils/lib/mkhtemp.c @@ -4,10 +4,23 @@ * Hardened mktemp (be nice to the demon). */ -#if defined(__linux__) && !defined(_GNU_SOURCE) -/* for openat2 syscall on linux */ +/* for openat2 / fast path: */ +#ifdef __linux__ +#if !defined(USE_OPENAT) || \ + ((USE_OPENAT) < 1) /* if 1: use openat, not openat2 */ +#ifndef _GNU_SOURCE #define _GNU_SOURCE 1 #endif +#include <sys/syscall.h> +#include <linux/openat2.h> +#ifndef O_TMPFILE +#define O_TMPFILE 020000000 +#endif +#ifndef AT_EMPTY_PATH +#define AT_EMPTY_PATH 0x1000 +#endif +#endif +#endif #include <sys/types.h> #include <sys/stat.h> @@ -19,18 +32,6 @@ #include <string.h> #include <unistd.h> -/* for openat2 / fast path: */ -#ifdef __linux__ -#include <linux/openat2.h> -#include <sys/syscall.h> -#ifndef O_TMPFILE -#define O_TMPFILE 020000000 -#endif -#ifndef AT_EMPTY_PATH -#define AT_EMPTY_PATH 0x1000 -#endif -#endif - #include "../include/common.h" /* note: tmpdir is an override of TMPDIR or /tmp or /var/tmp */ @@ -133,7 +134,7 @@ new_tmp_common(int *fd, char **path, int type, if (*fd < 0) goto err; - close_on_eintr(&dirfd); + xclose(&dirfd); errno = saved_errno; *path = dest; @@ -144,8 +145,8 @@ new_tmp_common(int *fd, char **path, int type, err: free_and_set_null(&dest); - close_on_eintr(&dirfd); - close_on_eintr(fd); + xclose(&dirfd); + xclose(fd); /* where a TMPDIR isn't found, and we err, * we pass this back through for the @@ -289,8 +290,8 @@ success_same_dir: rval = 1; /* SUCCESS */ } - close_on_eintr(&fd_a); - close_on_eintr(&fd_b); + xclose(&fd_a); + xclose(&fd_b); /* we reset caller errno regardless * of success, so long as it's not @@ -302,8 +303,8 @@ success_same_dir: err_same_dir: /* FAILURE (probably syscall) - returns -1 */ - close_on_eintr(&fd_a); - close_on_eintr(&fd_b); + xclose(&fd_a); + xclose(&fd_b); return with_fallback_errno(EIO); /* -1 */ } @@ -358,12 +359,12 @@ sticky_heaven: if (faccessat(dirfd, ".", X_OK, AT_EACCESS) < 0) goto sticky_hell; /* down you go! */ - close_on_eintr(&dirfd); + xclose(&dirfd); reset_caller_errno(0); return 1; sticky_hell: - close_on_eintr(&dirfd); + xclose(&dirfd); (void) with_fallback_errno(EPERM); return 0; } @@ -494,7 +495,7 @@ mkhtemp(int *fd, errno = EEXIST; err: - close_on_eintr(fd); + xclose(fd); free_and_set_null(&fname_copy); return with_fallback_errno(EIO); @@ -541,7 +542,8 @@ mkhtemp_try_create(int dirfd, goto err; if (type == MKHTEMP_FILE) { -#ifdef __linux__ +#if defined(__linux__) && \ + (!defined(USE_OPENAT) || ((USE_OPENAT) < 1)) /* try O_TMPFILE fast path */ if (mkhtemp_tmpfile_linux(dirfd, st_dir_first, fname_copy, @@ -633,7 +635,7 @@ out: reset_caller_errno(0); return rval; err: - close_on_eintr(fd); + xclose(fd); if (file_created) (void) unlinkat(dirfd, fname_copy, 0); @@ -650,7 +652,8 @@ err: we still use openat() on bsd, which is still ok with our other mitigations */ -#ifdef __linux__ +#if defined(__linux__) && \ + (!defined(USE_OPENAT) || ((USE_OPENAT) < 1)) int mkhtemp_tmpfile_linux(int dirfd, struct stat *st_dir_first, @@ -718,7 +721,7 @@ err: if (linked) (void) unlinkat(dirfd, fname_copy, 0); - close_on_eintr(&tmpfd); + xclose(&tmpfd); return with_fallback_errno(EIO); out: reset_caller_errno(0); @@ -749,9 +752,7 @@ int secure_file(int *fd, if_err(*fd < 0, EBADF)) goto err_demons; - while (fs_retry(saved_errno, - flags = fcntl(*fd, F_GETFL))); - if (flags == -1) + if ((flags = fcntl(*fd, F_GETFL)) == -1) goto err_demons; if (if_err(bad_flags > 0 && (flags & bad_flags), EPERM)) @@ -896,9 +897,7 @@ lock_file(int fd, int flags) fl.l_whence = SEEK_SET; - while (fs_retry(saved_errno, - fcntl_rval = fcntl(fd, F_SETLK, &fl))); - if (fcntl_rval == -1) + if ((fcntl_rval = fcntl(fd, F_SETLK, &fl)) == -1) goto err_lock_file; reset_caller_errno(0); diff --git a/util/libreboot-utils/lib/rand.c b/util/libreboot-utils/lib/rand.c index 082612d6..bf090b43 100644 --- a/util/libreboot-utils/lib/rand.c +++ b/util/libreboot-utils/lib/rand.c @@ -4,31 +4,30 @@ * Random number generation */ -#ifndef RAND_H -#define RAND_H - +#if defined(USE_ARC4) && \ + ((USE_ARC4) > 0) +#define _DEFAULT_SOURCE 1 /* for arc4random on *linux* */ + /* (not needed on bsd - on bsd, + it is used automatically unless + overridden with USE_URANDOM */ +#elif defined(USE_URANDOM) && \ + ((USE_URANDOM) > 0) +#include <fcntl.h> /* if not arc4random: /dev/urandom */ +#elif defined(__linux__) && \ + !(defined(USE_ARC4) && ((USE_ARC4) > 0)) #ifndef _GNU_SOURCE #define _GNU_SOURCE 1 #endif +#include <sys/syscall.h> +#include <sys/random.h> +#endif #ifdef __OpenBSD__ #include <sys/param.h> #endif #include <sys/types.h> -#ifndef USE_URANDOM -#define USE_URANDOM 0 -#endif - #include <errno.h> -#if defined(USE_URANDOM) && \ - ((USE_URANDOM) > 0) -#include <fcntl.h> /* if not arc4random: /dev/urandom */ -#elif defined(__linux__) -#include <sys/random.h> -#include <sys/syscall.h> -#endif - #include <fcntl.h> #include <limits.h> #include <stddef.h> @@ -139,10 +138,15 @@ rset(void *buf, size_t n) if (n == 0) exitf("rset: zero-byte request"); -#if (defined(__OpenBSD__) || defined(__FreeBSD__) || \ +/* on linux, getrandom is recommended, + but you can pass -DUSE_ARC4=1 to use arc4random. + useful for portability testing from linux. + */ +#if (defined(USE_ARC4) && ((USE_ARC4) > 0)) || \ + ((defined(__OpenBSD__) || defined(__FreeBSD__) || \ defined(__NetBSD__) || defined(__APPLE__) || \ defined(__DragonFly__)) && !(defined(USE_URANDOM) && \ - ((USE_URANDOM) > 0)) + ((USE_URANDOM) > 0))) arc4random_buf(buf, n); #else @@ -152,35 +156,37 @@ retry_rand: { #if defined(USE_URANDOM) && \ ((USE_URANDOM) > 0) - ssize_t rc; + ssize_t rval; int fd = -1; open_file_on_eintr("/dev/urandom", &fd, O_RDONLY, 0400, NULL); while (rw_retry(saved_errno, - rc = read_on_eintr(fd, - (unsigned char *)buf + off, n - off, 0))); + rval = rw(fd, (unsigned char *)buf + off, n - off, 0, IO_READ))); #elif defined(__linux__) - long rc; + long rval; while (sys_retry(saved_errno, - rc = syscall(SYS_getrandom, + rval = syscall(SYS_getrandom, (unsigned char *)buf + off, n - off, 0))); #else #error Unsupported operating system (possibly unsecure randomisation) #endif - if (rc < 0) - goto err; /* syscall fehler */ - - if (rc == 0) - goto err; /* prevent infinite loop on fatal err */ + if (rval < 0 || /* syscall fehler */ + rval == 0) { /* prevent infinite loop on fatal err */ +#if defined(USE_URANDOM) && \ + ((USE_URANDOM) > 0) + xclose(&fd); +#endif + goto err; + } - if ((off += (size_t)rc) < n) + if ((off += (size_t)rval) < n) goto retry_rand; #if defined(USE_URANDOM) && \ ((USE_URANDOM) > 0) - close_on_eintr(&fd); + xclose(&fd); #endif } @@ -188,12 +194,7 @@ retry_rand: { reset_caller_errno(0); return; err: -#if defined(USE_URANDOM) && \ - ((USE_URANDOM) > 0) - close_on_eintr(&fd); -#endif (void) with_fallback_errno(ECANCELED); exitf("Randomisierungsfehler"); exit(EXIT_FAILURE); } -#endif diff --git a/util/libreboot-utils/lib/state.c b/util/libreboot-utils/lib/state.c index b956a483..78e15134 100644 --- a/util/libreboot-utils/lib/state.c +++ b/util/libreboot-utils/lib/state.c @@ -4,8 +4,8 @@ * State machine (singleton) for nvmutil data. */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE 1 +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE 700 #endif #include <sys/types.h> |
