| #define _GNU_SOURCE |
| |
| #include <errno.h> |
| #include <stdarg.h> |
| #include <stdio_ext.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <time.h> |
| #include <unistd.h> |
| |
| #if HAVE_GETRANDOM |
| # include <sys/random.h> |
| #endif |
| |
| #ifdef HAVE_ERROR_H |
| # include <error.h> |
| #else |
| void error(int status, int errnum, const char *format, ...) |
| { |
| va_list ap; |
| |
| fprintf(stderr, "%s: ", program_invocation_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"); |
| } |