1362aecb2SWilly Tarreau // SPDX-License-Identifier: GPL-2.0 2362aecb2SWilly Tarreau 3362aecb2SWilly Tarreau /* platform-specific include files coming from the compiler */ 4362aecb2SWilly Tarreau #include <limits.h> 5362aecb2SWilly Tarreau 6362aecb2SWilly Tarreau /* libc-specific include files 7362aecb2SWilly Tarreau * The program may be built in 2 ways: 8362aecb2SWilly Tarreau * $(CC) -nostdlib -include /path/to/nolibc.h => NOLIBC already defined 9362aecb2SWilly Tarreau * $(CC) -nostdlib -I/path/to/nolibc/sysroot 10362aecb2SWilly Tarreau */ 11362aecb2SWilly Tarreau #ifndef NOLIBC 12362aecb2SWilly Tarreau #include <stdio.h> 13362aecb2SWilly Tarreau #include <stdlib.h> 14362aecb2SWilly Tarreau #include <string.h> 15362aecb2SWilly Tarreau #endif 16362aecb2SWilly Tarreau 17362aecb2SWilly Tarreau /* will be used by nolibc by getenv() */ 18362aecb2SWilly Tarreau char **environ; 19362aecb2SWilly Tarreau 2023da7bc9SWilly Tarreau /* definition of a series of tests */ 2123da7bc9SWilly Tarreau struct test { 2223da7bc9SWilly Tarreau const char *name; // test name 2323da7bc9SWilly Tarreau int (*func)(int min, int max); // handler 2423da7bc9SWilly Tarreau }; 2523da7bc9SWilly Tarreau 26362aecb2SWilly Tarreau #define CASE_ERR(err) \ 27362aecb2SWilly Tarreau case err: return #err 28362aecb2SWilly Tarreau 29362aecb2SWilly Tarreau /* returns the error name (e.g. "ENOENT") for common errors, "SUCCESS" for 0, 30362aecb2SWilly Tarreau * or the decimal value for less common ones. 31362aecb2SWilly Tarreau */ 32362aecb2SWilly Tarreau const char *errorname(int err) 33362aecb2SWilly Tarreau { 34362aecb2SWilly Tarreau switch (err) { 35362aecb2SWilly Tarreau case 0: return "SUCCESS"; 36362aecb2SWilly Tarreau CASE_ERR(EPERM); 37362aecb2SWilly Tarreau CASE_ERR(ENOENT); 38362aecb2SWilly Tarreau CASE_ERR(ESRCH); 39362aecb2SWilly Tarreau CASE_ERR(EINTR); 40362aecb2SWilly Tarreau CASE_ERR(EIO); 41362aecb2SWilly Tarreau CASE_ERR(ENXIO); 42362aecb2SWilly Tarreau CASE_ERR(E2BIG); 43362aecb2SWilly Tarreau CASE_ERR(ENOEXEC); 44362aecb2SWilly Tarreau CASE_ERR(EBADF); 45362aecb2SWilly Tarreau CASE_ERR(ECHILD); 46362aecb2SWilly Tarreau CASE_ERR(EAGAIN); 47362aecb2SWilly Tarreau CASE_ERR(ENOMEM); 48362aecb2SWilly Tarreau CASE_ERR(EACCES); 49362aecb2SWilly Tarreau CASE_ERR(EFAULT); 50362aecb2SWilly Tarreau CASE_ERR(ENOTBLK); 51362aecb2SWilly Tarreau CASE_ERR(EBUSY); 52362aecb2SWilly Tarreau CASE_ERR(EEXIST); 53362aecb2SWilly Tarreau CASE_ERR(EXDEV); 54362aecb2SWilly Tarreau CASE_ERR(ENODEV); 55362aecb2SWilly Tarreau CASE_ERR(ENOTDIR); 56362aecb2SWilly Tarreau CASE_ERR(EISDIR); 57362aecb2SWilly Tarreau CASE_ERR(EINVAL); 58362aecb2SWilly Tarreau CASE_ERR(ENFILE); 59362aecb2SWilly Tarreau CASE_ERR(EMFILE); 60362aecb2SWilly Tarreau CASE_ERR(ENOTTY); 61362aecb2SWilly Tarreau CASE_ERR(ETXTBSY); 62362aecb2SWilly Tarreau CASE_ERR(EFBIG); 63362aecb2SWilly Tarreau CASE_ERR(ENOSPC); 64362aecb2SWilly Tarreau CASE_ERR(ESPIPE); 65362aecb2SWilly Tarreau CASE_ERR(EROFS); 66362aecb2SWilly Tarreau CASE_ERR(EMLINK); 67362aecb2SWilly Tarreau CASE_ERR(EPIPE); 68362aecb2SWilly Tarreau CASE_ERR(EDOM); 69362aecb2SWilly Tarreau CASE_ERR(ERANGE); 70362aecb2SWilly Tarreau CASE_ERR(ENOSYS); 71362aecb2SWilly Tarreau default: 72362aecb2SWilly Tarreau return itoa(err); 73362aecb2SWilly Tarreau } 74362aecb2SWilly Tarreau } 75362aecb2SWilly Tarreau 76362aecb2SWilly Tarreau static int pad_spc(int llen, int cnt, const char *fmt, ...) 77362aecb2SWilly Tarreau { 78362aecb2SWilly Tarreau va_list args; 79362aecb2SWilly Tarreau int len; 80362aecb2SWilly Tarreau int ret; 81362aecb2SWilly Tarreau 82362aecb2SWilly Tarreau for (len = 0; len < cnt - llen; len++) 83362aecb2SWilly Tarreau putchar(' '); 84362aecb2SWilly Tarreau 85362aecb2SWilly Tarreau va_start(args, fmt); 86362aecb2SWilly Tarreau ret = vfprintf(stdout, fmt, args); 87362aecb2SWilly Tarreau va_end(args); 88362aecb2SWilly Tarreau return ret < 0 ? ret : ret + len; 89362aecb2SWilly Tarreau } 90362aecb2SWilly Tarreau 91362aecb2SWilly Tarreau /* The tests below are intended to be used by the macroes, which evaluate 92362aecb2SWilly Tarreau * expression <expr>, print the status to stdout, and update the "ret" 93362aecb2SWilly Tarreau * variable to count failures. The functions themselves return the number 94362aecb2SWilly Tarreau * of failures, thus either 0 or 1. 95362aecb2SWilly Tarreau */ 96362aecb2SWilly Tarreau 97362aecb2SWilly Tarreau #define EXPECT_ZR(cond, expr) \ 98362aecb2SWilly Tarreau do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_zr(expr, llen); } while (0) 99362aecb2SWilly Tarreau 100362aecb2SWilly Tarreau static int expect_zr(int expr, int llen) 101362aecb2SWilly Tarreau { 102362aecb2SWilly Tarreau int ret = !(expr == 0); 103362aecb2SWilly Tarreau 104362aecb2SWilly Tarreau llen += printf(" = %d ", expr); 105362aecb2SWilly Tarreau pad_spc(llen, 40, ret ? "[FAIL]\n" : " [OK]\n"); 106362aecb2SWilly Tarreau return ret; 107362aecb2SWilly Tarreau } 108362aecb2SWilly Tarreau 109362aecb2SWilly Tarreau 110362aecb2SWilly Tarreau #define EXPECT_NZ(cond, expr, val) \ 111362aecb2SWilly Tarreau do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_nz(expr, llen; } while (0) 112362aecb2SWilly Tarreau 113362aecb2SWilly Tarreau static int expect_nz(int expr, int llen) 114362aecb2SWilly Tarreau { 115362aecb2SWilly Tarreau int ret = !(expr != 0); 116362aecb2SWilly Tarreau 117362aecb2SWilly Tarreau llen += printf(" = %d ", expr); 118362aecb2SWilly Tarreau pad_spc(llen, 40, ret ? "[FAIL]\n" : " [OK]\n"); 119362aecb2SWilly Tarreau return ret; 120362aecb2SWilly Tarreau } 121362aecb2SWilly Tarreau 122362aecb2SWilly Tarreau 123362aecb2SWilly Tarreau #define EXPECT_EQ(cond, expr, val) \ 124362aecb2SWilly Tarreau do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_eq(expr, llen, val); } while (0) 125362aecb2SWilly Tarreau 126362aecb2SWilly Tarreau static int expect_eq(int expr, int llen, int val) 127362aecb2SWilly Tarreau { 128362aecb2SWilly Tarreau int ret = !(expr == val); 129362aecb2SWilly Tarreau 130362aecb2SWilly Tarreau llen += printf(" = %d ", expr); 131362aecb2SWilly Tarreau pad_spc(llen, 40, ret ? "[FAIL]\n" : " [OK]\n"); 132362aecb2SWilly Tarreau return ret; 133362aecb2SWilly Tarreau } 134362aecb2SWilly Tarreau 135362aecb2SWilly Tarreau 136362aecb2SWilly Tarreau #define EXPECT_NE(cond, expr, val) \ 137362aecb2SWilly Tarreau do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_ne(expr, llen, val); } while (0) 138362aecb2SWilly Tarreau 139362aecb2SWilly Tarreau static int expect_ne(int expr, int llen, int val) 140362aecb2SWilly Tarreau { 141362aecb2SWilly Tarreau int ret = !(expr != val); 142362aecb2SWilly Tarreau 143362aecb2SWilly Tarreau llen += printf(" = %d ", expr); 144362aecb2SWilly Tarreau pad_spc(llen, 40, ret ? "[FAIL]\n" : " [OK]\n"); 145362aecb2SWilly Tarreau return ret; 146362aecb2SWilly Tarreau } 147362aecb2SWilly Tarreau 148362aecb2SWilly Tarreau 149362aecb2SWilly Tarreau #define EXPECT_GE(cond, expr, val) \ 150362aecb2SWilly Tarreau do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_ge(expr, llen, val); } while (0) 151362aecb2SWilly Tarreau 152362aecb2SWilly Tarreau static int expect_ge(int expr, int llen, int val) 153362aecb2SWilly Tarreau { 154362aecb2SWilly Tarreau int ret = !(expr >= val); 155362aecb2SWilly Tarreau 156362aecb2SWilly Tarreau llen += printf(" = %d ", expr); 157362aecb2SWilly Tarreau pad_spc(llen, 40, ret ? "[FAIL]\n" : " [OK]\n"); 158362aecb2SWilly Tarreau return ret; 159362aecb2SWilly Tarreau } 160362aecb2SWilly Tarreau 161362aecb2SWilly Tarreau 162362aecb2SWilly Tarreau #define EXPECT_GT(cond, expr, val) \ 163362aecb2SWilly Tarreau do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_gt(expr, llen, val); } while (0) 164362aecb2SWilly Tarreau 165362aecb2SWilly Tarreau static int expect_gt(int expr, int llen, int val) 166362aecb2SWilly Tarreau { 167362aecb2SWilly Tarreau int ret = !(expr > val); 168362aecb2SWilly Tarreau 169362aecb2SWilly Tarreau llen += printf(" = %d ", expr); 170362aecb2SWilly Tarreau pad_spc(llen, 40, ret ? "[FAIL]\n" : " [OK]\n"); 171362aecb2SWilly Tarreau return ret; 172362aecb2SWilly Tarreau } 173362aecb2SWilly Tarreau 174362aecb2SWilly Tarreau 175362aecb2SWilly Tarreau #define EXPECT_LE(cond, expr, val) \ 176362aecb2SWilly Tarreau do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_le(expr, llen, val); } while (0) 177362aecb2SWilly Tarreau 178362aecb2SWilly Tarreau static int expect_le(int expr, int llen, int val) 179362aecb2SWilly Tarreau { 180362aecb2SWilly Tarreau int ret = !(expr <= val); 181362aecb2SWilly Tarreau 182362aecb2SWilly Tarreau llen += printf(" = %d ", expr); 183362aecb2SWilly Tarreau pad_spc(llen, 40, ret ? "[FAIL]\n" : " [OK]\n"); 184362aecb2SWilly Tarreau return ret; 185362aecb2SWilly Tarreau } 186362aecb2SWilly Tarreau 187362aecb2SWilly Tarreau 188362aecb2SWilly Tarreau #define EXPECT_LT(cond, expr, val) \ 189362aecb2SWilly Tarreau do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_lt(expr, llen, val); } while (0) 190362aecb2SWilly Tarreau 191362aecb2SWilly Tarreau static int expect_lt(int expr, int llen, int val) 192362aecb2SWilly Tarreau { 193362aecb2SWilly Tarreau int ret = !(expr < val); 194362aecb2SWilly Tarreau 195362aecb2SWilly Tarreau llen += printf(" = %d ", expr); 196362aecb2SWilly Tarreau pad_spc(llen, 40, ret ? "[FAIL]\n" : " [OK]\n"); 197362aecb2SWilly Tarreau return ret; 198362aecb2SWilly Tarreau } 199362aecb2SWilly Tarreau 200362aecb2SWilly Tarreau 201362aecb2SWilly Tarreau #define EXPECT_SYSZR(cond, expr) \ 202362aecb2SWilly Tarreau do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_syszr(expr, llen); } while (0) 203362aecb2SWilly Tarreau 204362aecb2SWilly Tarreau static int expect_syszr(int expr, int llen) 205362aecb2SWilly Tarreau { 206362aecb2SWilly Tarreau int ret = 0; 207362aecb2SWilly Tarreau 208362aecb2SWilly Tarreau if (expr) { 209362aecb2SWilly Tarreau ret = 1; 210362aecb2SWilly Tarreau llen += printf(" = %d %s ", expr, errorname(errno)); 211362aecb2SWilly Tarreau llen += pad_spc(llen, 40, "[FAIL]\n"); 212362aecb2SWilly Tarreau } else { 213362aecb2SWilly Tarreau llen += printf(" = %d ", expr); 214362aecb2SWilly Tarreau llen += pad_spc(llen, 40, " [OK]\n"); 215362aecb2SWilly Tarreau } 216362aecb2SWilly Tarreau return ret; 217362aecb2SWilly Tarreau } 218362aecb2SWilly Tarreau 219362aecb2SWilly Tarreau 220362aecb2SWilly Tarreau #define EXPECT_SYSEQ(cond, expr, val) \ 221362aecb2SWilly Tarreau do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_syseq(expr, llen, val); } while (0) 222362aecb2SWilly Tarreau 223362aecb2SWilly Tarreau static int expect_syseq(int expr, int llen, int val) 224362aecb2SWilly Tarreau { 225362aecb2SWilly Tarreau int ret = 0; 226362aecb2SWilly Tarreau 227362aecb2SWilly Tarreau if (expr != val) { 228362aecb2SWilly Tarreau ret = 1; 229362aecb2SWilly Tarreau llen += printf(" = %d %s ", expr, errorname(errno)); 230362aecb2SWilly Tarreau llen += pad_spc(llen, 40, "[FAIL]\n"); 231362aecb2SWilly Tarreau } else { 232362aecb2SWilly Tarreau llen += printf(" = %d ", expr); 233362aecb2SWilly Tarreau llen += pad_spc(llen, 40, " [OK]\n"); 234362aecb2SWilly Tarreau } 235362aecb2SWilly Tarreau return ret; 236362aecb2SWilly Tarreau } 237362aecb2SWilly Tarreau 238362aecb2SWilly Tarreau 239362aecb2SWilly Tarreau #define EXPECT_SYSNE(cond, expr, val) \ 240362aecb2SWilly Tarreau do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_sysne(expr, llen, val); } while (0) 241362aecb2SWilly Tarreau 242362aecb2SWilly Tarreau static int expect_sysne(int expr, int llen, int val) 243362aecb2SWilly Tarreau { 244362aecb2SWilly Tarreau int ret = 0; 245362aecb2SWilly Tarreau 246362aecb2SWilly Tarreau if (expr == val) { 247362aecb2SWilly Tarreau ret = 1; 248362aecb2SWilly Tarreau llen += printf(" = %d %s ", expr, errorname(errno)); 249362aecb2SWilly Tarreau llen += pad_spc(llen, 40, "[FAIL]\n"); 250362aecb2SWilly Tarreau } else { 251362aecb2SWilly Tarreau llen += printf(" = %d ", expr); 252362aecb2SWilly Tarreau llen += pad_spc(llen, 40, " [OK]\n"); 253362aecb2SWilly Tarreau } 254362aecb2SWilly Tarreau return ret; 255362aecb2SWilly Tarreau } 256362aecb2SWilly Tarreau 257362aecb2SWilly Tarreau 258362aecb2SWilly Tarreau #define EXPECT_SYSER(cond, expr, expret, experr) \ 259362aecb2SWilly Tarreau do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_syserr(expr, expret, experr, llen); } while (0) 260362aecb2SWilly Tarreau 261362aecb2SWilly Tarreau static int expect_syserr(int expr, int expret, int experr, int llen) 262362aecb2SWilly Tarreau { 263362aecb2SWilly Tarreau int ret = 0; 264362aecb2SWilly Tarreau int _errno = errno; 265362aecb2SWilly Tarreau 266362aecb2SWilly Tarreau llen += printf(" = %d %s ", expr, errorname(_errno)); 267362aecb2SWilly Tarreau if (expr != expret || _errno != experr) { 268362aecb2SWilly Tarreau ret = 1; 269362aecb2SWilly Tarreau llen += printf(" != (%d %s) ", expret, errorname(experr)); 270362aecb2SWilly Tarreau llen += pad_spc(llen, 40, "[FAIL]\n"); 271362aecb2SWilly Tarreau } else { 272362aecb2SWilly Tarreau llen += pad_spc(llen, 40, " [OK]\n"); 273362aecb2SWilly Tarreau } 274362aecb2SWilly Tarreau return ret; 275362aecb2SWilly Tarreau } 276362aecb2SWilly Tarreau 277362aecb2SWilly Tarreau 278362aecb2SWilly Tarreau #define EXPECT_PTRZR(cond, expr) \ 279362aecb2SWilly Tarreau do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_ptrzr(expr, llen); } while (0) 280362aecb2SWilly Tarreau 281362aecb2SWilly Tarreau static int expect_ptrzr(const void *expr, int llen) 282362aecb2SWilly Tarreau { 283362aecb2SWilly Tarreau int ret = 0; 284362aecb2SWilly Tarreau 285362aecb2SWilly Tarreau llen += printf(" = <%p> ", expr); 286362aecb2SWilly Tarreau if (expr) { 287362aecb2SWilly Tarreau ret = 1; 288362aecb2SWilly Tarreau llen += pad_spc(llen, 40, "[FAIL]\n"); 289362aecb2SWilly Tarreau } else { 290362aecb2SWilly Tarreau llen += pad_spc(llen, 40, " [OK]\n"); 291362aecb2SWilly Tarreau } 292362aecb2SWilly Tarreau return ret; 293362aecb2SWilly Tarreau } 294362aecb2SWilly Tarreau 295362aecb2SWilly Tarreau 296362aecb2SWilly Tarreau #define EXPECT_PTRNZ(cond, expr) \ 297362aecb2SWilly Tarreau do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_ptrnz(expr, llen); } while (0) 298362aecb2SWilly Tarreau 299362aecb2SWilly Tarreau static int expect_ptrnz(const void *expr, int llen) 300362aecb2SWilly Tarreau { 301362aecb2SWilly Tarreau int ret = 0; 302362aecb2SWilly Tarreau 303362aecb2SWilly Tarreau llen += printf(" = <%p> ", expr); 304362aecb2SWilly Tarreau if (!expr) { 305362aecb2SWilly Tarreau ret = 1; 306362aecb2SWilly Tarreau llen += pad_spc(llen, 40, "[FAIL]\n"); 307362aecb2SWilly Tarreau } else { 308362aecb2SWilly Tarreau llen += pad_spc(llen, 40, " [OK]\n"); 309362aecb2SWilly Tarreau } 310362aecb2SWilly Tarreau return ret; 311362aecb2SWilly Tarreau } 312362aecb2SWilly Tarreau 313362aecb2SWilly Tarreau 314362aecb2SWilly Tarreau #define EXPECT_STRZR(cond, expr) \ 315362aecb2SWilly Tarreau do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_strzr(expr, llen); } while (0) 316362aecb2SWilly Tarreau 317362aecb2SWilly Tarreau static int expect_strzr(const char *expr, int llen) 318362aecb2SWilly Tarreau { 319362aecb2SWilly Tarreau int ret = 0; 320362aecb2SWilly Tarreau 321362aecb2SWilly Tarreau llen += printf(" = <%s> ", expr); 322362aecb2SWilly Tarreau if (expr) { 323362aecb2SWilly Tarreau ret = 1; 324362aecb2SWilly Tarreau llen += pad_spc(llen, 40, "[FAIL]\n"); 325362aecb2SWilly Tarreau } else { 326362aecb2SWilly Tarreau llen += pad_spc(llen, 40, " [OK]\n"); 327362aecb2SWilly Tarreau } 328362aecb2SWilly Tarreau return ret; 329362aecb2SWilly Tarreau } 330362aecb2SWilly Tarreau 331362aecb2SWilly Tarreau 332362aecb2SWilly Tarreau #define EXPECT_STRNZ(cond, expr) \ 333362aecb2SWilly Tarreau do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_strnz(expr, llen); } while (0) 334362aecb2SWilly Tarreau 335362aecb2SWilly Tarreau static int expect_strnz(const char *expr, int llen) 336362aecb2SWilly Tarreau { 337362aecb2SWilly Tarreau int ret = 0; 338362aecb2SWilly Tarreau 339362aecb2SWilly Tarreau llen += printf(" = <%s> ", expr); 340362aecb2SWilly Tarreau if (!expr) { 341362aecb2SWilly Tarreau ret = 1; 342362aecb2SWilly Tarreau llen += pad_spc(llen, 40, "[FAIL]\n"); 343362aecb2SWilly Tarreau } else { 344362aecb2SWilly Tarreau llen += pad_spc(llen, 40, " [OK]\n"); 345362aecb2SWilly Tarreau } 346362aecb2SWilly Tarreau return ret; 347362aecb2SWilly Tarreau } 348362aecb2SWilly Tarreau 349362aecb2SWilly Tarreau 350362aecb2SWilly Tarreau #define EXPECT_STREQ(cond, expr, cmp) \ 351362aecb2SWilly Tarreau do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_streq(expr, llen, cmp); } while (0) 352362aecb2SWilly Tarreau 353362aecb2SWilly Tarreau static int expect_streq(const char *expr, int llen, const char *cmp) 354362aecb2SWilly Tarreau { 355362aecb2SWilly Tarreau int ret = 0; 356362aecb2SWilly Tarreau 357362aecb2SWilly Tarreau llen += printf(" = <%s> ", expr); 358362aecb2SWilly Tarreau if (strcmp(expr, cmp) != 0) { 359362aecb2SWilly Tarreau ret = 1; 360362aecb2SWilly Tarreau llen += pad_spc(llen, 40, "[FAIL]\n"); 361362aecb2SWilly Tarreau } else { 362362aecb2SWilly Tarreau llen += pad_spc(llen, 40, " [OK]\n"); 363362aecb2SWilly Tarreau } 364362aecb2SWilly Tarreau return ret; 365362aecb2SWilly Tarreau } 366362aecb2SWilly Tarreau 367362aecb2SWilly Tarreau 368362aecb2SWilly Tarreau #define EXPECT_STRNE(cond, expr, cmp) \ 369362aecb2SWilly Tarreau do { if (!cond) pad_spc(llen, 40, "[SKIPPED]\n"); else ret += expect_strne(expr, llen, cmp); } while (0) 370362aecb2SWilly Tarreau 371362aecb2SWilly Tarreau static int expect_strne(const char *expr, int llen, const char *cmp) 372362aecb2SWilly Tarreau { 373362aecb2SWilly Tarreau int ret = 0; 374362aecb2SWilly Tarreau 375362aecb2SWilly Tarreau llen += printf(" = <%s> ", expr); 376362aecb2SWilly Tarreau if (strcmp(expr, cmp) == 0) { 377362aecb2SWilly Tarreau ret = 1; 378362aecb2SWilly Tarreau llen += pad_spc(llen, 40, "[FAIL]\n"); 379362aecb2SWilly Tarreau } else { 380362aecb2SWilly Tarreau llen += pad_spc(llen, 40, " [OK]\n"); 381362aecb2SWilly Tarreau } 382362aecb2SWilly Tarreau return ret; 383362aecb2SWilly Tarreau } 384362aecb2SWilly Tarreau 38523da7bc9SWilly Tarreau 386362aecb2SWilly Tarreau /* declare tests based on line numbers. There must be exactly one test per line. */ 387362aecb2SWilly Tarreau #define CASE_TEST(name) \ 388362aecb2SWilly Tarreau case __LINE__: llen += printf("%d %s", test, #name); 389362aecb2SWilly Tarreau 390362aecb2SWilly Tarreau 391b4844fa0SWilly Tarreau /* used by some syscall tests below */ 392b4844fa0SWilly Tarreau int test_getdents64(const char *dir) 393b4844fa0SWilly Tarreau { 394b4844fa0SWilly Tarreau char buffer[4096]; 395b4844fa0SWilly Tarreau int fd, ret; 396b4844fa0SWilly Tarreau int err; 397b4844fa0SWilly Tarreau 398b4844fa0SWilly Tarreau ret = fd = open(dir, O_RDONLY | O_DIRECTORY, 0); 399b4844fa0SWilly Tarreau if (ret < 0) 400b4844fa0SWilly Tarreau return ret; 401b4844fa0SWilly Tarreau 402b4844fa0SWilly Tarreau ret = getdents64(fd, (void *)buffer, sizeof(buffer)); 403b4844fa0SWilly Tarreau err = errno; 404b4844fa0SWilly Tarreau close(fd); 405b4844fa0SWilly Tarreau 406b4844fa0SWilly Tarreau errno = err; 407b4844fa0SWilly Tarreau return ret; 408b4844fa0SWilly Tarreau } 409b4844fa0SWilly Tarreau 410b4844fa0SWilly Tarreau /* Run syscall tests between IDs <min> and <max>. 411b4844fa0SWilly Tarreau * Return 0 on success, non-zero on failure. 412b4844fa0SWilly Tarreau */ 413b4844fa0SWilly Tarreau int run_syscall(int min, int max) 414b4844fa0SWilly Tarreau { 415b4844fa0SWilly Tarreau struct stat stat_buf; 416b4844fa0SWilly Tarreau int test; 417b4844fa0SWilly Tarreau int tmp; 418b4844fa0SWilly Tarreau int ret = 0; 419b4844fa0SWilly Tarreau void *p1, *p2; 420b4844fa0SWilly Tarreau 421b4844fa0SWilly Tarreau for (test = min; test >= 0 && test <= max; test++) { 422b4844fa0SWilly Tarreau int llen = 0; // line length 423b4844fa0SWilly Tarreau 424b4844fa0SWilly Tarreau /* avoid leaving empty lines below, this will insert holes into 425b4844fa0SWilly Tarreau * test numbers. 426b4844fa0SWilly Tarreau */ 427b4844fa0SWilly Tarreau switch (test + __LINE__ + 1) { 428b4844fa0SWilly Tarreau CASE_TEST(getpid); EXPECT_SYSNE(1, getpid(), -1); break; 429b4844fa0SWilly Tarreau CASE_TEST(getppid); EXPECT_SYSNE(1, getppid(), -1); break; 430b4844fa0SWilly Tarreau CASE_TEST(gettid); EXPECT_SYSNE(1, gettid(), -1); break; 431b4844fa0SWilly Tarreau CASE_TEST(getpgid_self); EXPECT_SYSNE(1, getpgid(0), -1); break; 432b4844fa0SWilly Tarreau CASE_TEST(getpgid_bad); EXPECT_SYSER(1, getpgid(-1), -1, ESRCH); break; 433b4844fa0SWilly Tarreau CASE_TEST(kill_0); EXPECT_SYSZR(1, kill(getpid(), 0)); break; 434b4844fa0SWilly Tarreau CASE_TEST(kill_CONT); EXPECT_SYSZR(1, kill(getpid(), 0)); break; 435b4844fa0SWilly Tarreau CASE_TEST(kill_BADPID); EXPECT_SYSER(1, kill(INT_MAX, 0), -1, ESRCH); break; 436b4844fa0SWilly Tarreau CASE_TEST(sbrk); if ((p1 = p2 = sbrk(4096)) != (void *)-1) p2 = sbrk(-4096); EXPECT_SYSZR(1, (p2 == (void *)-1) || p2 == p1); break; 437b4844fa0SWilly Tarreau CASE_TEST(brk); EXPECT_SYSZR(1, brk(sbrk(0))); break; 438b4844fa0SWilly Tarreau CASE_TEST(chdir_root); EXPECT_SYSZR(1, chdir("/")); break; 439b4844fa0SWilly Tarreau CASE_TEST(chdir_dot); EXPECT_SYSZR(1, chdir(".")); break; 440b4844fa0SWilly Tarreau CASE_TEST(chdir_blah); EXPECT_SYSER(1, chdir("/blah"), -1, ENOENT); break; 441b4844fa0SWilly Tarreau CASE_TEST(chmod_net); EXPECT_SYSZR(1, chmod("/proc/self/net", 0555)); break; 442b4844fa0SWilly Tarreau CASE_TEST(chmod_self); EXPECT_SYSER(1, chmod("/proc/self", 0555), -1, EPERM); break; 443b4844fa0SWilly Tarreau CASE_TEST(chown_self); EXPECT_SYSER(1, chown("/proc/self", 0, 0), -1, EPERM); break; 444b4844fa0SWilly Tarreau CASE_TEST(chroot_root); EXPECT_SYSZR(1, chroot("/")); break; 445b4844fa0SWilly Tarreau CASE_TEST(chroot_blah); EXPECT_SYSER(1, chroot("/proc/self/blah"), -1, ENOENT); break; 446b4844fa0SWilly Tarreau CASE_TEST(chroot_exe); EXPECT_SYSER(1, chroot("/proc/self/exe"), -1, ENOTDIR); break; 447b4844fa0SWilly Tarreau CASE_TEST(close_m1); EXPECT_SYSER(1, close(-1), -1, EBADF); break; 448b4844fa0SWilly Tarreau CASE_TEST(close_dup); EXPECT_SYSZR(1, close(dup(0))); break; 449b4844fa0SWilly Tarreau CASE_TEST(dup_0); tmp = dup(0); EXPECT_SYSNE(1, tmp, -1); close(tmp); break; 450b4844fa0SWilly Tarreau CASE_TEST(dup_m1); tmp = dup(-1); EXPECT_SYSER(1, tmp, -1, EBADF); if (tmp != -1) close(tmp); break; 451b4844fa0SWilly Tarreau CASE_TEST(dup2_0); tmp = dup2(0, 100); EXPECT_SYSNE(1, tmp, -1); close(tmp); break; 452b4844fa0SWilly Tarreau CASE_TEST(dup2_m1); tmp = dup2(-1, 100); EXPECT_SYSER(1, tmp, -1, EBADF); if (tmp != -1) close(tmp); break; 453b4844fa0SWilly Tarreau CASE_TEST(dup3_0); tmp = dup3(0, 100, 0); EXPECT_SYSNE(1, tmp, -1); close(tmp); break; 454b4844fa0SWilly Tarreau CASE_TEST(dup3_m1); tmp = dup3(-1, 100, 0); EXPECT_SYSER(1, tmp, -1, EBADF); if (tmp != -1) close(tmp); break; 455b4844fa0SWilly Tarreau CASE_TEST(execve_root); EXPECT_SYSER(1, execve("/", (char*[]){ [0] = "/", [1] = NULL }, NULL), -1, EACCES); break; 456b4844fa0SWilly Tarreau CASE_TEST(getdents64_root); EXPECT_SYSNE(1, test_getdents64("/"), -1); break; 457b4844fa0SWilly Tarreau CASE_TEST(getdents64_null); EXPECT_SYSER(1, test_getdents64("/dev/null"), -1, ENOTDIR); break; 458b4844fa0SWilly Tarreau CASE_TEST(gettimeofday_null); EXPECT_SYSZR(1, gettimeofday(NULL, NULL)); break; 459b4844fa0SWilly Tarreau CASE_TEST(gettimeofday_bad1); EXPECT_SYSER(1, gettimeofday((void *)1, NULL), -1, EFAULT); break; 460b4844fa0SWilly Tarreau CASE_TEST(gettimeofday_bad2); EXPECT_SYSER(1, gettimeofday(NULL, (void *)1), -1, EFAULT); break; 461b4844fa0SWilly Tarreau CASE_TEST(gettimeofday_bad2); EXPECT_SYSER(1, gettimeofday(NULL, (void *)1), -1, EFAULT); break; 462b4844fa0SWilly Tarreau CASE_TEST(ioctl_tiocinq); EXPECT_SYSZR(1, ioctl(0, TIOCINQ, &tmp)); break; 463b4844fa0SWilly Tarreau CASE_TEST(ioctl_tiocinq); EXPECT_SYSZR(1, ioctl(0, TIOCINQ, &tmp)); break; 464b4844fa0SWilly Tarreau CASE_TEST(link_root1); EXPECT_SYSER(1, link("/", "/"), -1, EEXIST); break; 465b4844fa0SWilly Tarreau CASE_TEST(link_blah); EXPECT_SYSER(1, link("/proc/self/blah", "/blah"), -1, ENOENT); break; 466b4844fa0SWilly Tarreau CASE_TEST(link_dir); EXPECT_SYSER(1, link("/", "/blah"), -1, EPERM); break; 467b4844fa0SWilly Tarreau CASE_TEST(link_cross); EXPECT_SYSER(1, link("/proc/self/net", "/blah"), -1, EXDEV); break; 468b4844fa0SWilly Tarreau CASE_TEST(lseek_m1); EXPECT_SYSER(1, lseek(-1, 0, SEEK_SET), -1, EBADF); break; 469b4844fa0SWilly Tarreau CASE_TEST(lseek_0); EXPECT_SYSER(1, lseek(0, 0, SEEK_SET), -1, ESPIPE); break; 470b4844fa0SWilly Tarreau CASE_TEST(mkdir_root); EXPECT_SYSER(1, mkdir("/", 0755), -1, EEXIST); break; 471b4844fa0SWilly Tarreau CASE_TEST(open_tty); EXPECT_SYSNE(1, tmp = open("/dev/null", 0), -1); if (tmp != -1) close(tmp); break; 472b4844fa0SWilly Tarreau CASE_TEST(open_blah); EXPECT_SYSER(1, tmp = open("/proc/self/blah", 0), -1, ENOENT); if (tmp != -1) close(tmp); break; 473b4844fa0SWilly Tarreau CASE_TEST(poll_null); EXPECT_SYSZR(1, poll(NULL, 0, 0)); break; 474b4844fa0SWilly Tarreau CASE_TEST(poll_stdout); EXPECT_SYSNE(1, ({ struct pollfd fds = { 1, POLLOUT, 0}; poll(&fds, 1, 0); }), -1); break; 475b4844fa0SWilly Tarreau CASE_TEST(poll_fault); EXPECT_SYSER(1, poll((void *)1, 1, 0), -1, EFAULT); break; 476b4844fa0SWilly Tarreau CASE_TEST(read_badf); EXPECT_SYSER(1, read(-1, &tmp, 1), -1, EBADF); break; 477b4844fa0SWilly Tarreau CASE_TEST(sched_yield); EXPECT_SYSZR(1, sched_yield()); break; 478b4844fa0SWilly Tarreau CASE_TEST(select_null); EXPECT_SYSZR(1, ({ struct timeval tv = { 0 }; select(0, NULL, NULL, NULL, &tv); })); break; 479b4844fa0SWilly Tarreau CASE_TEST(select_stdout); EXPECT_SYSNE(1, ({ fd_set fds; FD_ZERO(&fds); FD_SET(1, &fds); select(2, NULL, &fds, NULL, NULL); }), -1); break; 480b4844fa0SWilly Tarreau CASE_TEST(select_fault); EXPECT_SYSER(1, select(1, (void *)1, NULL, NULL, 0), -1, EFAULT); break; 481b4844fa0SWilly Tarreau CASE_TEST(stat_blah); EXPECT_SYSER(1, stat("/proc/self/blah", &stat_buf), -1, ENOENT); break; 482b4844fa0SWilly Tarreau CASE_TEST(stat_fault); EXPECT_SYSER(1, stat(NULL, &stat_buf), -1, EFAULT); break; 483b4844fa0SWilly Tarreau CASE_TEST(symlink_root); EXPECT_SYSER(1, symlink("/", "/"), -1, EEXIST); break; 484b4844fa0SWilly Tarreau CASE_TEST(unlink_root); EXPECT_SYSER(1, unlink("/"), -1, EISDIR); break; 485b4844fa0SWilly Tarreau CASE_TEST(unlink_blah); EXPECT_SYSER(1, unlink("/proc/self/blah"), -1, ENOENT); break; 486b4844fa0SWilly Tarreau CASE_TEST(wait_child); EXPECT_SYSER(1, wait(&tmp), -1, ECHILD); break; 487b4844fa0SWilly Tarreau CASE_TEST(waitpid_min); EXPECT_SYSER(1, waitpid(INT_MIN, &tmp, WNOHANG), -1, ESRCH); break; 488b4844fa0SWilly Tarreau CASE_TEST(waitpid_child); EXPECT_SYSER(1, waitpid(getpid(), &tmp, WNOHANG), -1, ECHILD); break; 489b4844fa0SWilly Tarreau CASE_TEST(write_badf); EXPECT_SYSER(1, write(-1, &tmp, 1), -1, EBADF); break; 490b4844fa0SWilly Tarreau CASE_TEST(write_zero); EXPECT_SYSZR(1, write(1, &tmp, 0)); break; 491b4844fa0SWilly Tarreau case __LINE__: 492b4844fa0SWilly Tarreau return ret; /* must be last */ 493b4844fa0SWilly Tarreau /* note: do not set any defaults so as to permit holes above */ 494b4844fa0SWilly Tarreau } 495b4844fa0SWilly Tarreau } 496b4844fa0SWilly Tarreau return ret; 497b4844fa0SWilly Tarreau } 498b4844fa0SWilly Tarreau 49995bc9894SWilly Tarreau int run_stdlib(int min, int max) 50095bc9894SWilly Tarreau { 50195bc9894SWilly Tarreau int test; 50295bc9894SWilly Tarreau int tmp; 50395bc9894SWilly Tarreau int ret = 0; 50495bc9894SWilly Tarreau void *p1, *p2; 50595bc9894SWilly Tarreau 50695bc9894SWilly Tarreau for (test = min; test >= 0 && test <= max; test++) { 50795bc9894SWilly Tarreau int llen = 0; // line length 50895bc9894SWilly Tarreau 50995bc9894SWilly Tarreau /* avoid leaving empty lines below, this will insert holes into 51095bc9894SWilly Tarreau * test numbers. 51195bc9894SWilly Tarreau */ 51295bc9894SWilly Tarreau switch (test + __LINE__ + 1) { 51395bc9894SWilly Tarreau CASE_TEST(getenv_TERM); EXPECT_STRNZ(1, getenv("TERM")); break; 51495bc9894SWilly Tarreau CASE_TEST(getenv_blah); EXPECT_STRZR(1, getenv("blah")); break; 51595bc9894SWilly Tarreau CASE_TEST(setcmp_blah_blah); EXPECT_EQ(1, strcmp("blah", "blah"), 0); break; 51695bc9894SWilly Tarreau CASE_TEST(setcmp_blah_blah2); EXPECT_NE(1, strcmp("blah", "blah2"), 0); break; 51795bc9894SWilly Tarreau CASE_TEST(setncmp_blah_blah); EXPECT_EQ(1, strncmp("blah", "blah", 10), 0); break; 51895bc9894SWilly Tarreau CASE_TEST(setncmp_blah_blah4); EXPECT_EQ(1, strncmp("blah", "blah4", 4), 0); break; 51995bc9894SWilly Tarreau CASE_TEST(setncmp_blah_blah5); EXPECT_NE(1, strncmp("blah", "blah5", 5), 0); break; 52095bc9894SWilly Tarreau CASE_TEST(setncmp_blah_blah6); EXPECT_NE(1, strncmp("blah", "blah6", 6), 0); break; 52195bc9894SWilly Tarreau CASE_TEST(strchr_foobar_o); EXPECT_STREQ(1, strchr("foobar", 'o'), "oobar"); break; 52295bc9894SWilly Tarreau CASE_TEST(strchr_foobar_z); EXPECT_STRZR(1, strchr("foobar", 'z')); break; 52395bc9894SWilly Tarreau CASE_TEST(strrchr_foobar_o); EXPECT_STREQ(1, strrchr("foobar", 'o'), "obar"); break; 52495bc9894SWilly Tarreau CASE_TEST(strrchr_foobar_z); EXPECT_STRZR(1, strrchr("foobar", 'z')); break; 52595bc9894SWilly Tarreau case __LINE__: 52695bc9894SWilly Tarreau return ret; /* must be last */ 52795bc9894SWilly Tarreau /* note: do not set any defaults so as to permit holes above */ 52895bc9894SWilly Tarreau } 52995bc9894SWilly Tarreau } 53095bc9894SWilly Tarreau return ret; 53195bc9894SWilly Tarreau } 53295bc9894SWilly Tarreau 533b4844fa0SWilly Tarreau 53423da7bc9SWilly Tarreau /* This is the definition of known test names, with their functions */ 53523da7bc9SWilly Tarreau static struct test test_names[] = { 53623da7bc9SWilly Tarreau /* add new tests here */ 537b4844fa0SWilly Tarreau { .name = "syscall", .func = run_syscall }, 53895bc9894SWilly Tarreau { .name = "stdlib", .func = run_stdlib }, 53923da7bc9SWilly Tarreau { 0 } 54023da7bc9SWilly Tarreau }; 54123da7bc9SWilly Tarreau 542362aecb2SWilly Tarreau int main(int argc, char **argv, char **envp) 543362aecb2SWilly Tarreau { 544362aecb2SWilly Tarreau int min = 0; 545362aecb2SWilly Tarreau int max = __INT_MAX__; 546362aecb2SWilly Tarreau int ret = 0; 54723da7bc9SWilly Tarreau int err; 54823da7bc9SWilly Tarreau int idx; 54923da7bc9SWilly Tarreau char *test; 550362aecb2SWilly Tarreau 551362aecb2SWilly Tarreau environ = envp; 552362aecb2SWilly Tarreau 55323da7bc9SWilly Tarreau /* the definition of a series of tests comes from either argv[1] or the 55423da7bc9SWilly Tarreau * "NOLIBC_TEST" environment variable. It's made of a comma-delimited 55523da7bc9SWilly Tarreau * series of test names and optional ranges: 55623da7bc9SWilly Tarreau * syscall:5-15[:.*],stdlib:8-10 55723da7bc9SWilly Tarreau */ 55823da7bc9SWilly Tarreau test = argv[1]; 55923da7bc9SWilly Tarreau if (!test) 56023da7bc9SWilly Tarreau test = getenv("NOLIBC_TEST"); 56123da7bc9SWilly Tarreau 56223da7bc9SWilly Tarreau if (test) { 56323da7bc9SWilly Tarreau char *comma, *colon, *dash, *value; 56423da7bc9SWilly Tarreau 56523da7bc9SWilly Tarreau do { 56623da7bc9SWilly Tarreau comma = strchr(test, ','); 56723da7bc9SWilly Tarreau if (comma) 56823da7bc9SWilly Tarreau *(comma++) = '\0'; 56923da7bc9SWilly Tarreau 57023da7bc9SWilly Tarreau colon = strchr(test, ':'); 57123da7bc9SWilly Tarreau if (colon) 57223da7bc9SWilly Tarreau *(colon++) = '\0'; 57323da7bc9SWilly Tarreau 57423da7bc9SWilly Tarreau for (idx = 0; test_names[idx].name; idx++) { 57523da7bc9SWilly Tarreau if (strcmp(test, test_names[idx].name) == 0) 57623da7bc9SWilly Tarreau break; 57723da7bc9SWilly Tarreau } 57823da7bc9SWilly Tarreau 57923da7bc9SWilly Tarreau if (test_names[idx].name) { 58023da7bc9SWilly Tarreau /* The test was named, it will be called at least 58123da7bc9SWilly Tarreau * once. We may have an optional range at <colon> 58223da7bc9SWilly Tarreau * here, which defaults to the full range. 58323da7bc9SWilly Tarreau */ 58423da7bc9SWilly Tarreau do { 58523da7bc9SWilly Tarreau min = 0; max = __INT_MAX__; 58623da7bc9SWilly Tarreau value = colon; 58723da7bc9SWilly Tarreau if (value && *value) { 58823da7bc9SWilly Tarreau colon = strchr(value, ':'); 58923da7bc9SWilly Tarreau if (colon) 59023da7bc9SWilly Tarreau *(colon++) = '\0'; 59123da7bc9SWilly Tarreau 59223da7bc9SWilly Tarreau dash = strchr(value, '-'); 59323da7bc9SWilly Tarreau if (dash) 59423da7bc9SWilly Tarreau *(dash++) = '\0'; 59523da7bc9SWilly Tarreau 59623da7bc9SWilly Tarreau /* support :val: :min-max: :min-: :-max: */ 59723da7bc9SWilly Tarreau if (*value) 59823da7bc9SWilly Tarreau min = atoi(value); 59923da7bc9SWilly Tarreau if (!dash) 60023da7bc9SWilly Tarreau max = min; 60123da7bc9SWilly Tarreau else if (*dash) 60223da7bc9SWilly Tarreau max = atoi(dash); 60323da7bc9SWilly Tarreau 60423da7bc9SWilly Tarreau value = colon; 60523da7bc9SWilly Tarreau } 60623da7bc9SWilly Tarreau 60723da7bc9SWilly Tarreau /* now's time to call the test */ 60823da7bc9SWilly Tarreau printf("Running test '%s'\n", test_names[idx].name); 60923da7bc9SWilly Tarreau err = test_names[idx].func(min, max); 61023da7bc9SWilly Tarreau ret += err; 61123da7bc9SWilly Tarreau printf("Errors during this test: %d\n\n", err); 61223da7bc9SWilly Tarreau } while (colon && *colon); 61323da7bc9SWilly Tarreau } else 61423da7bc9SWilly Tarreau printf("Ignoring unknown test name '%s'\n", test); 61523da7bc9SWilly Tarreau 61623da7bc9SWilly Tarreau test = comma; 61723da7bc9SWilly Tarreau } while (test && *test); 61823da7bc9SWilly Tarreau } else { 61923da7bc9SWilly Tarreau /* no test mentioned, run everything */ 62023da7bc9SWilly Tarreau for (idx = 0; test_names[idx].name; idx++) { 62123da7bc9SWilly Tarreau printf("Running test '%s'\n", test_names[idx].name); 62223da7bc9SWilly Tarreau err = test_names[idx].func(min, max); 62323da7bc9SWilly Tarreau ret += err; 62423da7bc9SWilly Tarreau printf("Errors during this test: %d\n\n", err); 62523da7bc9SWilly Tarreau } 62623da7bc9SWilly Tarreau } 62723da7bc9SWilly Tarreau 628362aecb2SWilly Tarreau printf("Total number of errors: %d\n", ret); 629*f49896d7SWilly Tarreau 630*f49896d7SWilly Tarreau if (getpid() == 1) { 631*f49896d7SWilly Tarreau /* we're running as init, there's no other process on the 632*f49896d7SWilly Tarreau * system, thus likely started from a VM for a quick check. 633*f49896d7SWilly Tarreau * Exiting will provoke a kernel panic that may be reported 634*f49896d7SWilly Tarreau * as an error by Qemu or the hypervisor, while stopping 635*f49896d7SWilly Tarreau * cleanly will often be reported as a success. This allows 636*f49896d7SWilly Tarreau * to use the output of this program for bisecting kernels. 637*f49896d7SWilly Tarreau */ 638*f49896d7SWilly Tarreau printf("Leaving init with final status: %d\n", !!ret); 639*f49896d7SWilly Tarreau if (ret == 0) 640*f49896d7SWilly Tarreau reboot(LINUX_REBOOT_CMD_POWER_OFF); 641*f49896d7SWilly Tarreau } 642*f49896d7SWilly Tarreau 643362aecb2SWilly Tarreau printf("Exiting with status %d\n", !!ret); 644362aecb2SWilly Tarreau return !!ret; 645362aecb2SWilly Tarreau } 646