#define _GNU_SOURCE #include #include #include #include #include #include #include #include #if HAVE_GETRANDOM # include #endif #ifdef HAVE_ERROR_H # include #else void error(int status, int errnum, const char *format, ...) { va_list ap; fprintf(stderr, "%s: ", program_invocation_short_name); va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); if (errnum) fprintf(stderr, ": %s\n", strerror(errnum)); else fprintf(stderr, "\n"); if (status) exit(status); } #endif int close_stream(FILE *stream) { const int flush_status = fflush(stream); #ifdef HAVE___FPENDING const int some_pending = (__fpending(stream) != 0); #endif const int prev_fail = (ferror(stream) != 0); const int fclose_fail = (fclose(stream) != 0); if (flush_status || prev_fail || (fclose_fail && ( #ifdef HAVE___FPENDING some_pending || #endif errno != EBADF))) { if (!fclose_fail && !(errno == EPIPE)) errno = 0; return EOF; } return 0; } void close_stdout(void) { if (close_stream(stdout) != 0 && !(errno == EPIPE)) { if (errno) error(0, errno, "write error"); else error(0, 0, "write error"); _exit(EXIT_FAILURE); } if (close_stream(stderr) != 0) _exit(EXIT_FAILURE); } long strtol_or_err(char const *const str, char const *const errmesg, const long min, const long max) { long num; char *end = NULL; errno = 0; if (str == NULL || *str == '\0') goto err; num = strtol(str, &end, 10); if (errno || str == end || (end && *end)) goto err; if (num < min || max < num) error(EXIT_FAILURE, 0, "%s: '%s': out of range: %ld <= value <= %ld", errmesg, str, min, max); return num; err: error(EXIT_FAILURE, errno, "%s: '%s'", errmesg, str); abort(); } unsigned long strtoul_or_err(char const *const str, char const *const errmesg, const unsigned long min, const unsigned long max) { unsigned long num; char *end = NULL; errno = 0; if (str == NULL || *str == '\0') goto err; num = strtoul(str, &end, 10); if (errno || str == end || (end && *end)) goto err; if (num < min || max < num) error(EXIT_FAILURE, 0, "%s: '%s': out of range: %lu <= value <= %lu", errmesg, str, min, max); return num; err: error(EXIT_FAILURE, errno, "%s: '%s'", errmesg, str); abort(); } static unsigned int iputil_srand_fallback(void) { struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); return ((getpid() << 16) ^ getuid() ^ ts.tv_sec ^ ts.tv_nsec); } void iputils_srand(void) { unsigned int i; #if HAVE_GETRANDOM ssize_t ret; do { errno = 0; ret = getrandom(&i, sizeof(i), GRND_NONBLOCK); switch (errno) { case 0: break; case EINTR: continue; default: i = iputil_srand_fallback(); goto done; } } while (ret != sizeof(i)); done: #else i = iputil_srand_fallback(); #endif srand(i); /* Consume up to 31 random numbers */ i = rand() & 0x1F; while (0 < i) { rand(); i--; } } void timespecsub(struct timespec *a, struct timespec *b, struct timespec *res) { res->tv_sec = a->tv_sec - b->tv_sec; res->tv_nsec = a->tv_nsec - b->tv_nsec; if (res->tv_nsec < 0) { res->tv_sec--; res->tv_nsec += 1000000000L; } } void print_config(void) { printf( "libcap: " #ifdef HAVE_LIBCAP "yes" #else "no" #endif ", IDN: " #ifdef USE_IDN "yes" #else "no" #endif ", NLS: " #ifdef ENABLE_NLS "yes" #else "no" #endif ", error.h: " #ifdef HAVE_ERROR_H "yes" #else "no" #endif ", getrandom(): " #ifdef HAVE_GETRANDOM "yes" #else "no" #endif ", __fpending(): " #ifdef HAVE___FPENDING "yes" #else "no" #endif "\n"); }