]> git.draconx.ca Git - rarpd-dx.git/blob - src/iputils_common.c
Get rid of IPUTILS_VERSION macro.
[rarpd-dx.git] / src / iputils_common.c
1 #include <errno.h>
2 #include <stdarg.h>
3 #include <stdio_ext.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <time.h>
8 #include <unistd.h>
9
10 #if HAVE_GETRANDOM
11 # include <sys/random.h>
12 #endif
13
14 #ifdef HAVE_ERROR_H
15 # include <error.h>
16 #else
17 void error(int status, int errnum, const char *format, ...)
18 {
19         va_list ap;
20
21         fprintf(stderr, "%s: ", program_invocation_short_name);
22         va_start(ap, format);
23         vfprintf(stderr, format, ap);
24         va_end(ap);
25         if (errnum)
26                 fprintf(stderr, ": %s\n", strerror(errnum));
27         else
28                 fprintf(stderr, "\n");
29         if (status)
30                 exit(status);
31 }
32 #endif
33
34 int close_stream(FILE *stream)
35 {
36         const int flush_status = fflush(stream);
37 #ifdef HAVE___FPENDING
38         const int some_pending = (__fpending(stream) != 0);
39 #endif
40         const int prev_fail = (ferror(stream) != 0);
41         const int fclose_fail = (fclose(stream) != 0);
42
43         if (flush_status ||
44             prev_fail || (fclose_fail && (
45 #ifdef HAVE___FPENDING
46                                           some_pending ||
47 #endif
48                                           errno != EBADF))) {
49                 if (!fclose_fail && !(errno == EPIPE))
50                         errno = 0;
51                 return EOF;
52         }
53         return 0;
54 }
55
56 void close_stdout(void)
57 {
58         if (close_stream(stdout) != 0 && !(errno == EPIPE)) {
59                 if (errno)
60                         error(0, errno, "write error");
61                 else
62                         error(0, 0, "write error");
63                 _exit(EXIT_FAILURE);
64         }
65         if (close_stream(stderr) != 0)
66                 _exit(EXIT_FAILURE);
67 }
68
69 long strtol_or_err(char const *const str, char const *const errmesg,
70                    const long min, const long max)
71 {
72         long num;
73         char *end = NULL;
74
75         errno = 0;
76         if (str == NULL || *str == '\0')
77                 goto err;
78         num = strtol(str, &end, 10);
79         if (errno || str == end || (end && *end))
80                 goto err;
81         if (num < min || max < num)
82                 error(EXIT_FAILURE, 0, "%s: '%s': out of range: %lu <= value <= %lu",
83                       errmesg, str,  min, max);
84         return num;
85  err:
86         error(EXIT_FAILURE, errno, "%s: '%s'", errmesg, str);
87         abort();
88 }
89
90 static unsigned int iputil_srand_fallback(void)
91 {
92         struct timespec ts;
93
94         clock_gettime(CLOCK_REALTIME, &ts);
95         return ((getpid() << 16) ^ getuid() ^ ts.tv_sec ^ ts.tv_nsec);
96 }
97
98 void iputils_srand(void)
99 {
100         unsigned int i;
101
102 #if HAVE_GETRANDOM
103         ssize_t ret;
104
105         do {
106                 errno = 0;
107                 ret = getrandom(&i, sizeof(i), GRND_NONBLOCK);
108                 switch (errno) {
109                 case 0:
110                         break;
111                 case EINTR:
112                         continue;
113                 default:
114                         i = iputil_srand_fallback();
115                         goto done;
116                 }
117         } while (ret != sizeof(i));
118  done:
119 #else
120         i = iputil_srand_fallback();
121 #endif
122         srand(i);
123         /* Consume up to 31 random numbers */
124         i = rand() & 0x1F;
125         while (0 < i) {
126                 rand();
127                 i--;
128         }
129 }
130
131 void timespecsub(struct timespec *a, struct timespec *b, struct timespec *res)
132 {
133         res->tv_sec = a->tv_sec - b->tv_sec;
134         res->tv_nsec = a->tv_nsec - b->tv_nsec;
135
136         if (res->tv_nsec < 0) {
137                 res->tv_sec--;
138                 res->tv_nsec += 1000000000L;
139         }
140 }