ccan: update to include closefrom

Signed-off-by: ZmnSCPxj jxPCSnmZ <ZmnSCPxj@protonmail.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
ZmnSCPxj jxPCSnmZ
2021-10-19 09:51:43 +08:00
committed by Christian Decker
parent ed6eaf9171
commit 5a84abb09e
14 changed files with 665 additions and 27 deletions

View File

@@ -96,6 +96,7 @@ CCAN_OBJS := \
ccan-bitmap.o \
ccan-bitops.o \
ccan-breakpoint.o \
ccan-closefrom.o \
ccan-crc32c.o \
ccan-crypto-hmac.o \
ccan-crypto-hkdf.o \
@@ -154,6 +155,7 @@ CCAN_HEADERS := \
$(CCANDIR)/ccan/cast/cast.h \
$(CCANDIR)/ccan/cdump/cdump.h \
$(CCANDIR)/ccan/check_type/check_type.h \
$(CCANDIR)/ccan/closefrom/closefrom.h \
$(CCANDIR)/ccan/compiler/compiler.h \
$(CCANDIR)/ccan/container_of/container_of.h \
$(CCANDIR)/ccan/cppmagic/cppmagic.h \
@@ -857,3 +859,5 @@ ccan-json_escape.o: $(CCANDIR)/ccan/json_escape/json_escape.c
@$(call VERBOSE, "cc $<", $(CC) $(CFLAGS) -c -o $@ $<)
ccan-json_out.o: $(CCANDIR)/ccan/json_out/json_out.c
@$(call VERBOSE, "cc $<", $(CC) $(CFLAGS) -c -o $@ $<)
ccan-closefrom.o: $(CCANDIR)/ccan/closefrom/closefrom.c
@$(call VERBOSE, "cc $<", $(CC) $(CFLAGS) -c -o $@ $<)

View File

@@ -1,3 +1,3 @@
CCAN imported from http://ccodearchive.net.
CCAN version: init-2507-g05ec8351
CCAN version: init-2519-gcc888f28

1
ccan/ccan/closefrom/LICENSE Symbolic link
View File

@@ -0,0 +1 @@
../../licenses/CC0

69
ccan/ccan/closefrom/_info Normal file
View File

@@ -0,0 +1,69 @@
#include "config.h"
#include <stdio.h>
#include <string.h>
/**
* closefrom - close all fds starting from specified fd.
*
* This code is an example of what to do in a child process to
* ensure that none of the (possibly sensitive) file descriptors
* in the parent remain in the child process.
*
* License: CC0 (Public domain)
* Author: ZmnSCPxj jxPCSnmZ <ZmnSCPxj@protonmail.com>
*
* Example:
* #include <ccan/closefrom/closefrom.h>
* #include <ccan/err/err.h>
* #include <stdio.h>
* #include <sys/resource.h>
* #include <sys/time.h>
* #include <sys/types.h>
* #include <sys/wait.h>
* #include <unistd.h>
*
* int main(int argc, char **argv)
* {
* pid_t child;
*
* // If being emulated, then we might end up
* // looping over a large _SC_OPEN_MAX
* // (Some systems have it as INT_MAX!)
* // If so, closefrom_limit will lower this limit
* // to a value you specify, or if given 0 will
* // limit to 4096.
* // Call this as early as possible.
* closefrom_limit(0);
*
* // If we limited, we can query this so we can
* // print it in debug logs or something.
* if (closefrom_may_be_slow())
* printf("we limited ourselves to 4096 fds.\n");
*
* child = fork();
* if (child < 0)
* err(1, "Forking");
* if (child == 0) {
* closefrom(STDERR_FILENO + 1);
* // Insert your *whatever* code here.
* _exit(0);
* }
*
* waitpid(child, NULL, 0);
*
* return 0;
* }
*
*/
int main(int argc, char *argv[])
{
/* Expect exactly one argument */
if (argc != 2)
return 1;
if (strcmp(argv[1], "depends") == 0) {
return 0;
}
return 1;
}

View File

@@ -0,0 +1,225 @@
/* CC0 license (public domain) - see LICENSE file for details */
#include <ccan/closefrom/closefrom.h>
#include <dirent.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <unistd.h>
/* See also:
* https://stackoverflow.com/a/918469
*
* The implementation below is not exhaustive of all the suggested above.
*/
#if !HAVE_CLOSEFROM
/* IBM AIX.
* https://www.ibm.com/docs/en/aix/7.2?topic=f-fcntl-dup-dup2-subroutine
*/
#if HAVE_F_CLOSEM
#include <fcntl.h>
void closefrom(int fromfd)
{
(void) fcntl(fromfd, F_CLOSEM, 0);
}
bool closefrom_may_be_slow(void)
{
return false;
}
#else /* !HAVE_F_CLOSEM */
#if HAVE_NR_CLOSE_RANGE
#include <sys/syscall.h>
#endif
#define PROC_PID_FD_LEN \
( 6 /* /proc/ */ \
+ 20 /* 64-bit $PID */ \
+ 3 /* /fd */ \
+ 1 /* NUL */ \
)
static bool can_get_maxfd(void)
{
#if HAVE_F_MAXFD
int res = fcntl(0, F_MAXFD);
if (res < 0)
return false;
else
return true;
#else
return false;
#endif
}
/* Linux >= 5.9 */
static bool can_close_range(void)
{
#if HAVE_NR_CLOSE_RANGE
int res = syscall(__NR_close_range, INT_MAX, INT_MAX, 0);
if (res < 0)
return false;
return true;
#else
return false;
#endif
}
/* On Linux, Solaris, AIX, Cygwin, and NetBSD. */
static bool can_open_proc_pid_fd(void)
{
char dnam[PROC_PID_FD_LEN];
DIR *dir;
sprintf(dnam, "/proc/%ld/fd", (long) getpid());
dir = opendir(dnam);
if (!dir)
return false;
closedir(dir);
return true;
}
/* On FreeBSD and MacOS. */
static bool can_open_dev_fd(void)
{
DIR *dir;
dir = opendir("/dev/fd");
if (!dir)
return false;
closedir(dir);
return true;
}
bool closefrom_may_be_slow(void)
{
if (can_get_maxfd())
return false;
else if (can_close_range())
return false;
else if (can_open_proc_pid_fd())
return false;
else if (can_open_dev_fd())
return false;
else
return true;
}
/* It is possible that we run out of available file descriptors.
* However, if we are going to close anyway, we could just try
* closing file descriptors until we reach maxfd.
*/
static
DIR *try_opendir(const char *dnam, int *fromfd, int maxfd)
{
DIR *dir;
do {
dir = opendir(dnam);
if (!dir && (errno == ENFILE || errno == EMFILE)) {
if (*fromfd < maxfd)
close((*fromfd)++);
else
break;
}
} while (!dir && (errno == ENFILE || errno == EMFILE));
return dir;
}
void closefrom(int fromfd)
{
int saved_errno = errno;
int res;
int maxfd;
char dnam[PROC_PID_FD_LEN];
DIR *dir;
struct dirent *entry;
(void) res;
if (fromfd < 0)
goto quit;
#if HAVE_NR_CLOSE_RANGE
res = syscall(__NR_close_range, fromfd, INT_MAX, 0);
if (res == 0)
goto quit;
#endif
maxfd = sysconf(_SC_OPEN_MAX);
sprintf(dnam, "/proc/%ld/fd", (long) getpid());
dir = try_opendir(dnam, &fromfd, maxfd);
if (!dir)
dir = try_opendir("/dev/fd", &fromfd, maxfd);
if (dir) {
while ((entry = readdir(dir))) {
long fd;
char *endp;
fd = strtol(entry->d_name, &endp, 10);
if (entry->d_name != endp && *endp == '\0' &&
fd >= 0 && fd < INT_MAX && fd >= fromfd &&
fd != dirfd(dir) )
close(fd);
}
closedir(dir);
goto quit;
}
#if HAVE_F_MAXFD
res = fcntl(0, F_MAXFD);
if (res >= 0)
maxfd = res + 1;
#endif
/* Fallback. */
for (; fromfd < maxfd; ++fromfd)
close(fromfd);
quit:
errno = saved_errno;
}
#endif /* !HAVE_F_CLOSEM */
void closefrom_limit(unsigned int arg_limit)
{
rlim_t limit = (rlim_t) arg_limit;
struct rlimit nofile;
if (!closefrom_may_be_slow())
return;
if (limit == 0)
limit = 4096;
getrlimit(RLIMIT_NOFILE, &nofile);
/* Respect the max limit.
* If we are not running as root then we cannot raise
* it, but we *can* lower the max limit.
*/
if (nofile.rlim_max != RLIM_INFINITY && limit > nofile.rlim_max)
limit = nofile.rlim_max;
nofile.rlim_cur = limit;
nofile.rlim_max = limit;
setrlimit(RLIMIT_NOFILE, &nofile);
}
#endif /* !HAVE_CLOSEFROM */

View File

@@ -0,0 +1,81 @@
/* CC0 license (public domain) - see LICENSE file for details */
#ifndef CCAN_CLOSEFROM_H
#define CCAN_CLOSEFROM_H
#include "config.h"
#include <stdbool.h>
#if HAVE_CLOSEFROM
/* BSD. */
#include <unistd.h>
/* Solaris. */
#include <stdlib.h>
static inline
bool closefrom_may_be_slow(void)
{
return 0;
}
static inline
void closefrom_limit(unsigned int limit)
{
}
#else /* !HAVE_CLOSEFROM */
/**
* closefrom - Close all open file descriptors, starting
* at fromfd onwards.
* @fromfd: the first fd to close; it and all higher file descriptors
* will be closed.
*
* This is not multithread-safe: other threads in the same process
* may or may not open new file descriptors in parallel to this call.
* However, the expected use-case is that this will be called in a
* child process just after fork(), meaning the child process is still
* single-threaded.
*/
void closefrom_(int fromfd);
/* In case the standard library has it, but declared in some
* *other* header we do not know of yet, we use closefrom_ in
* the actual name the linker sees.
*/
#define closefrom closefrom_
/**
* closefrom_may_be_slow - check if the closefrom() function could
* potentially take a long time.
*
* The return value is true if closefrom() is emulated by
* looping from fromfd to sysconf(_SC_OPEN_MAX), which can be
* very large (possibly even INT_MAX on some systems).
* If so, you might want to use setrlimit to limit _SC_OPEN_MAX.
* If this returns false, then closefrom is efficient and you do not
* need to limit the number of file descriptors.
*
* You can use closefrom_limit to perform the limiting based on
* closefrom_may_be_slow.
* This API is exposed in case you want to output to debug logs or
* something similar.
*/
bool closefrom_may_be_slow(void);
/**
* closefrom_limit - If closefrom_may_be_slow(), lower the limit on
* the number of file descriptors we keep open, to prevent closefrom
* from being *too* slow.
* @limit: 0 to use a reasonable default of 4096, or non-zero for the
* limit you prefer.
*
* This function does nothing if closefrom_may_be_slow() return false.
*
* This function only *lowers* the limit from the hard limit set by
* root before running this program.
* If the limit is higher than the hard limit, then the hard limit is
* respected.
*/
void closefrom_limit(unsigned int limit);
#endif /* !HAVE_CLOSEFROM */
#endif /* CCAN_CLOSEFROM_H */

View File

@@ -0,0 +1,192 @@
#include <ccan/closefrom/closefrom.h>
/* Include the C files directly. */
#include <ccan/closefrom/closefrom.c>
#include <ccan/tap/tap.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
/* Open a pipe, do closefrom, check pipe no longer works. */
static
int pipe_close(void)
{
int fds[2];
ssize_t wres;
char buf = '\0';
if (pipe(fds) < 0)
return 0;
/* Writing to the write end should succeed, the
* pipe is working. */
do {
wres = write(fds[1], &buf, 1);
} while ((wres < 0) && (errno == EINTR));
if (wres < 0)
return 0;
closefrom(STDERR_FILENO + 1);
/* Writing to the write end should fail because
* everything should be closed. */
do {
wres = write(fds[1], &buf, 1);
} while ((wres < 0) && (errno == EINTR));
return (wres < 0) && (errno == EBADF);
}
/* Open a pipe, fork, do closefrom in child, read pipe from parent,
* parent should see EOF.
*/
static
int fork_close(void)
{
int fds[2];
pid_t child;
char buf;
ssize_t rres;
if (pipe(fds) < 0)
return 0;
child = fork();
if (child < 0)
return 0;
if (child == 0) {
/* Child. */
closefrom(STDERR_FILENO + 1);
_exit(0);
} else {
/* Parent. */
/* Close write end of pipe. */
close(fds[1]);
do {
rres = read(fds[0], &buf, 1);
} while ((rres < 0) && (errno == EINTR));
/* Should have seen EOF. */
if (rres != 0)
return 0;
/* Clean up. */
waitpid(child, NULL, 0);
closefrom(STDERR_FILENO + 1);
}
return 1;
}
/* Open a pipe, fork, in child set the write end to fd #3,
* in parent set the read end to fd #3, send a byte from
* child to parent, check.
*/
static
int fork_communicate(void)
{
int fds[2];
pid_t child;
char wbuf = 42;
char rbuf;
ssize_t rres;
ssize_t wres;
int status;
if (pipe(fds) < 0)
return 0;
child = fork();
if (child < 0)
return 0;
if (child == 0) {
/* Child. */
/* Move write end to fd #3. */
if (fds[1] != 3) {
if (dup2(fds[1], 3) < 0)
_exit(127);
close(fds[1]);
fds[1] = 3;
}
closefrom(4);
do {
wres = write(fds[1], &wbuf, 1);
} while ((wres < 0) && (errno == EINTR));
if (wres < 0)
_exit(127);
_exit(0);
} else {
/* Parent. */
/* Move read end to fd #3. */
if (fds[0] != 3) {
if (dup2(fds[0], 3) < 0)
return 0;
close(fds[0]);
fds[0] = 3;
}
closefrom(4);
/* Wait for child to finish. */
waitpid(child, &status, 0);
if (!WIFEXITED(status))
return 0;
if (WEXITSTATUS(status) != 0)
return 0;
/* Read 1 byte. */
do {
rres = read(fds[0], &rbuf, 1);
} while ((rres < 0) && (errno == EINTR));
if (rres < 0)
return 0;
if (rres != 1)
return 0;
/* Should get same byte as what was sent. */
if (rbuf != wbuf)
return 0;
/* Next attempt to read should EOF. */
do {
rres = read(fds[0], &rbuf, 1);
} while ((rres < 0) && (errno == EINTR));
if (rres < 0)
return 0;
/* Should EOF. */
if (rres != 0)
return 0;
}
/* Clean up. */
close(fds[0]);
return 1;
}
int main(void)
{
/* Limit closefrom. */
closefrom_limit(0);
/* This is how many tests you plan to run */
plan_tests(3);
ok1(pipe_close());
ok1(fork_close());
ok1(fork_communicate());
/* This exits depending on whether all tests passed */
return exit_status();
}

View File

@@ -72,7 +72,8 @@ static inline uint32_t gf2_matrix_times(uint32_t *mat, uint32_t vec) {
/* Multiply a matrix by itself over GF(2). Both mat and square must have 32
rows. */
static inline void gf2_matrix_square(uint32_t *square, uint32_t *mat) {
for (unsigned n = 0; n < 32; n++)
unsigned n;
for (n = 0; n < 32; n++)
square[n] = gf2_matrix_times(mat, mat[n]);
}
@@ -87,7 +88,8 @@ static void crc32c_zeros_op(uint32_t *even, size_t len) {
/* put operator for one zero bit in odd */
odd[0] = POLY; /* CRC-32C polynomial */
uint32_t row = 1;
for (unsigned n = 1; n < 32; n++) {
unsigned n;
for (n = 1; n < 32; n++) {
odd[n] = row;
row <<= 1;
}
@@ -111,7 +113,7 @@ static void crc32c_zeros_op(uint32_t *even, size_t len) {
} while (len);
/* answer ended up in odd -- copy to even */
for (unsigned n = 0; n < 32; n++)
for (n = 0; n < 32; n++)
even[n] = odd[n];
}
@@ -121,7 +123,8 @@ static void crc32c_zeros(uint32_t zeros[][256], size_t len) {
uint32_t op[32];
crc32c_zeros_op(op, len);
for (unsigned n = 0; n < 256; n++) {
unsigned n;
for (n = 0; n < 256; n++) {
zeros[0][n] = gf2_matrix_times(op, n);
zeros[1][n] = gf2_matrix_times(op, n << 8);
zeros[2][n] = gf2_matrix_times(op, n << 16);
@@ -265,7 +268,8 @@ uint32_t crc32c(uint32_t crc, void const *buf, size_t len) {
static bool crc32c_once_little;
static uint32_t crc32c_table_little[8][256];
static void crc32c_init_sw_little(void) {
for (unsigned n = 0; n < 256; n++) {
unsigned n;
for (n = 0; n < 256; n++) {
uint32_t crc = n;
crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
@@ -277,9 +281,10 @@ static void crc32c_init_sw_little(void) {
crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
crc32c_table_little[0][n] = crc;
}
for (unsigned n = 0; n < 256; n++) {
for (n = 0; n < 256; n++) {
uint32_t crc = crc32c_table_little[0][n];
for (unsigned k = 1; k < 8; k++) {
unsigned k;
for (k = 1; k < 8; k++) {
crc = crc32c_table_little[0][crc & 0xff] ^ (crc >> 8);
crc32c_table_little[k][n] = crc;
}
@@ -340,7 +345,8 @@ static bool crc32c_once_big;
static uint32_t crc32c_table_big_byte[256];
static uint64_t crc32c_table_big[8][256];
static void crc32c_init_sw_big(void) {
for (unsigned n = 0; n < 256; n++) {
unsigned n;
for (n = 0; n < 256; n++) {
uint32_t crc = n;
crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
@@ -352,10 +358,11 @@ static void crc32c_init_sw_big(void) {
crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
crc32c_table_big_byte[n] = crc;
}
for (unsigned n = 0; n < 256; n++) {
for (n = 0; n < 256; n++) {
uint32_t crc = crc32c_table_big_byte[n];
crc32c_table_big[0][n] = swap(crc);
for (unsigned k = 1; k < 8; k++) {
unsigned k;
for (k = 1; k < 8; k++) {
crc = crc32c_table_big_byte[crc & 0xff] ^ (crc >> 8);
crc32c_table_big[k][n] = swap(crc);
}

View File

@@ -121,7 +121,9 @@ bool add_listener(struct io_listener *l)
static int find_always(const struct io_plan *plan)
{
for (size_t i = 0; i < num_always; i++)
size_t i = 0;
for (i = 0; i < num_always; i++)
if (always[i] == plan)
return i;
return -1;
@@ -287,8 +289,10 @@ static bool *exclusive(struct io_plan *plan)
/* For simplicity, we do one always at a time */
static bool handle_always(void)
{
int i;
/* Backwards is simple easier to remove entries */
for (int i = num_always - 1; i >= 0; i--) {
for (i = num_always - 1; i >= 0; i--) {
struct io_plan *plan = always[i];
if (num_exclusive && !*exclusive(plan))
@@ -323,10 +327,12 @@ bool backend_set_exclusive(struct io_plan *plan, bool excl)
* else that we manipulate events. */
static void exclude_pollfds(void)
{
size_t i;
if (num_exclusive == 0)
return;
for (size_t i = 0; i < num_fds; i++) {
for (i = 0; i < num_fds; i++) {
struct pollfd *pfd = &pollfds[fds[i]->backend_info];
if (!fds[i]->exclusive[IO_IN])
@@ -343,10 +349,12 @@ static void exclude_pollfds(void)
static void restore_pollfds(void)
{
size_t i;
if (num_exclusive == 0)
return;
for (size_t i = 0; i < num_fds; i++) {
for (i = 0; i < num_fds; i++) {
struct pollfd *pfd = &pollfds[fds[i]->backend_info];
if (fds[i]->listener) {

View File

@@ -21,7 +21,8 @@ bool json_escape_eq(const struct json_escape *a, const struct json_escape *b)
bool json_escape_needed(const char *str, size_t len)
{
for (size_t i = 0; i < len; i++) {
size_t i;
for (i = 0; i < len; i++) {
if ((unsigned)str[i] < ' '
|| str[i] == 127
|| str[i] == '"'

View File

@@ -51,6 +51,7 @@ int main(int argc, char *argv[])
return 1;
if (strcmp(argv[1], "depends") == 0) {
printf("ccan/closefrom\n");
printf("ccan/noerr\n");
return 0;
}

View File

@@ -1,4 +1,5 @@
/* CC0 license (public domain) - see LICENSE file for details */
#include <ccan/closefrom/closefrom.h>
#include <ccan/pipecmd/pipecmd.h>
#include <ccan/noerr/noerr.h>
#include <stdlib.h>
@@ -115,7 +116,8 @@ pid_t pipecmdarr(int *fd_tochild, int *fd_fromchild, int *fd_errfromchild,
goto fail;
if (childpid == 0) {
for (int i = 0; i < num_child_close; i++)
int i;
for (i = 0; i < num_child_close; i++)
close(child_close[i]);
// Child runs command.
@@ -138,11 +140,21 @@ pid_t pipecmdarr(int *fd_tochild, int *fd_fromchild, int *fd_errfromchild,
close(errfromchild[1]);
}
/* Map execfail[1] to fd 3. */
if (execfail[1] != 3) {
if (dup2(execfail[1], 3) == -1)
goto child_errno_fail;
/* CLOEXEC is not shared by dup2, so copy the flags
* from execfail[1] to 3.
*/
if (fcntl(3, F_SETFD, fcntl(execfail[1], F_GETFD)) < 0)
goto child_errno_fail;
close(execfail[1]);
execfail[1] = 3;
}
/* Make (fairly!) sure all other fds are closed. */
int max = sysconf(_SC_OPEN_MAX);
for (int i = 3; i < max; i++)
if (i != execfail[1])
close(i);
closefrom(4);
execvp(arr[0], arr);
@@ -155,7 +167,8 @@ pid_t pipecmdarr(int *fd_tochild, int *fd_fromchild, int *fd_errfromchild,
exit(127);
}
for (int i = 0; i < num_par_close; i++)
int i;
for (i = 0; i < num_par_close; i++)
close(par_close[i]);
/* Child will close this without writing on successful exec. */
@@ -175,7 +188,7 @@ pid_t pipecmdarr(int *fd_tochild, int *fd_fromchild, int *fd_errfromchild,
return childpid;
fail:
for (int i = 0; i < num_par_close; i++)
for (i = 0; i < num_par_close; i++)
close_noerr(par_close[i]);
return -1;
}

View File

@@ -70,7 +70,8 @@ static bool decode_8_chars(const char c[8], beint64_t *res, int *bytes)
{
uint64_t acc = 0;
size_t num_pad = 0;
for (int i = 0; i < 8; i++) {
int i;
for (i = 0; i < 8; i++) {
const char *p;
acc <<= 5;

View File

@@ -498,6 +498,43 @@ static const struct test base_tests[] = {
" return __builtin_cpu_supports(\"mmx\");\n"
"}"
},
{ "HAVE_CLOSEFROM", "closefrom() offered by system",
"DEFINES_EVERYTHING", NULL, NULL,
"#include <stdlib.h>\n"
"#include <unistd.h>\n"
"int main(void) {\n"
" closefrom(STDERR_FILENO + 1);\n"
" return 0;\n"
"}\n"
},
{ "HAVE_F_CLOSEM", "F_CLOSEM defined for fctnl.",
"DEFINES_EVERYTHING", NULL, NULL,
"#include <fcntl.h>\n"
"#include <unistd.h>\n"
"int main(void) {\n"
" int res = fcntl(STDERR_FILENO + 1, F_CLOSEM, 0);\n"
" return res < 0;\n"
"}\n"
},
{ "HAVE_NR_CLOSE_RANGE", "close_range syscall available as __NR_close_range.",
"DEFINES_EVERYTHING", NULL, NULL,
"#include <limits.h>\n"
"#include <sys/syscall.h>\n"
"#include <unistd.h>\n"
"int main(void) {\n"
" int res = syscall(__NR_close_range, STDERR_FILENO + 1, INT_MAX, 0);\n"
" return res < 0;\n"
"}\n"
},
{ "HAVE_F_MAXFD", "F_MAXFD defined for fcntl.",
"DEFINES_EVERYTHING", NULL, NULL,
"#include <fcntl.h>\n"
"#include <unistd.h>\n"
"int main(void) {\n"
" int res = fcntl(0, F_MAXFD);\n"
" return res < 0;\n"
"}\n"
},
};
static void c12r_err(int eval, const char *fmt, ...)
@@ -765,9 +802,7 @@ static bool run_test(const char *cmd, const char *wrapper, struct test *test)
strcpy(cmd, wrapper);
strcat(cmd, " ." DIR_SEP OUTPUT_FILE);
output = run(cmd, &status);
if (wrapper) {
free(cmd);
}
free(cmd);
if (!strstr(test->style, "EXECUTE") && status != 0)
c12r_errx(EXIT_BAD_TEST,
"Test for %s failed with %i:\n%s",