util.c (4808B)
1 /* See LICENSE file for copyright and license details. */ 2 #include <errno.h> 3 #include <limits.h> 4 #include <stdarg.h> 5 #include <stdint.h> 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <string.h> 9 #include <sys/types.h> 10 #include <time.h> 11 12 #ifdef __OpenBSD__ 13 #include <unistd.h> 14 #endif /* __OpenBSD__ */ 15 16 #include "util.h" 17 18 char *argv0; 19 20 static void 21 verr(const char *fmt, va_list ap) 22 { 23 if (argv0 && strncmp(fmt, "usage", sizeof("usage") - 1)) { 24 fprintf(stderr, "%s: ", argv0); 25 } 26 27 vfprintf(stderr, fmt, ap); 28 29 if (fmt[0] && fmt[strlen(fmt) - 1] == ':') { 30 fputc(' ', stderr); 31 perror(NULL); 32 } else { 33 fputc('\n', stderr); 34 } 35 } 36 37 void 38 warn(const char *fmt, ...) 39 { 40 va_list ap; 41 42 va_start(ap, fmt); 43 verr(fmt, ap); 44 va_end(ap); 45 } 46 47 void 48 die(const char *fmt, ...) 49 { 50 va_list ap; 51 52 va_start(ap, fmt); 53 verr(fmt, ap); 54 va_end(ap); 55 56 exit(1); 57 } 58 59 void 60 epledge(const char *promises, const char *execpromises) 61 { 62 (void)promises; 63 (void)execpromises; 64 65 #ifdef __OpenBSD__ 66 if (pledge(promises, execpromises) == -1) { 67 die("pledge:"); 68 } 69 #endif /* __OpenBSD__ */ 70 } 71 72 void 73 eunveil(const char *path, const char *permissions) 74 { 75 (void)path; 76 (void)permissions; 77 78 #ifdef __OpenBSD__ 79 if (unveil(path, permissions) == -1) { 80 die("unveil:"); 81 } 82 #endif /* __OpenBSD__ */ 83 } 84 85 int 86 timestamp(char *buf, size_t len, time_t t) 87 { 88 struct tm tm; 89 90 if (gmtime_r(&t, &tm) == NULL || 91 strftime(buf, len, "%a, %d %b %Y %T GMT", &tm) == 0) { 92 return 1; 93 } 94 95 return 0; 96 } 97 98 int 99 esnprintf(char *str, size_t size, const char *fmt, ...) 100 { 101 va_list ap; 102 int ret; 103 104 va_start(ap, fmt); 105 ret = vsnprintf(str, size, fmt, ap); 106 va_end(ap); 107 108 return (ret < 0 || (size_t)ret >= size); 109 } 110 111 int 112 prepend(char *str, size_t size, const char *prefix) 113 { 114 size_t len = strlen(str), prefixlen = strlen(prefix); 115 116 if (len + prefixlen + 1 > size) { 117 return 1; 118 } 119 120 memmove(str + prefixlen, str, len + 1); 121 memcpy(str, prefix, prefixlen); 122 123 return 0; 124 } 125 126 int 127 spacetok(const char *s, char **t, size_t tlen) 128 { 129 const char *tok; 130 size_t i, j, toki, spaces; 131 132 /* fill token-array with NULL-pointers */ 133 for (i = 0; i < tlen; i++) { 134 t[i] = NULL; 135 } 136 toki = 0; 137 138 /* don't allow NULL string or leading spaces */ 139 if (!s || *s == ' ') { 140 return 1; 141 } 142 start: 143 /* skip spaces */ 144 for (; *s == ' '; s++) 145 ; 146 147 /* don't allow trailing spaces */ 148 if (*s == '\0') { 149 goto err; 150 } 151 152 /* consume token */ 153 for (tok = s, spaces = 0; ; s++) { 154 if (*s == '\\' && *(s + 1) == ' ') { 155 spaces++; 156 s++; 157 continue; 158 } else if (*s == ' ') { 159 /* end of token */ 160 goto token; 161 } else if (*s == '\0') { 162 /* end of string */ 163 goto token; 164 } 165 } 166 token: 167 if (toki >= tlen) { 168 goto err; 169 } 170 if (!(t[toki] = malloc(s - tok - spaces + 1))) { 171 die("malloc:"); 172 } 173 for (i = 0, j = 0; j < s - tok - spaces + 1; i++, j++) { 174 if (tok[i] == '\\' && tok[i + 1] == ' ') { 175 i++; 176 } 177 t[toki][j] = tok[i]; 178 } 179 t[toki][s - tok - spaces] = '\0'; 180 toki++; 181 182 if (*s == ' ') { 183 s++; 184 goto start; 185 } 186 187 return 0; 188 err: 189 for (i = 0; i < tlen; i++) { 190 free(t[i]); 191 t[i] = NULL; 192 } 193 194 return 1; 195 } 196 197 198 199 #define INVALID 1 200 #define TOOSMALL 2 201 #define TOOLARGE 3 202 203 long long 204 strtonum(const char *numstr, long long minval, long long maxval, 205 const char **errstrp) 206 { 207 long long ll = 0; 208 int error = 0; 209 char *ep; 210 struct errval { 211 const char *errstr; 212 int err; 213 } ev[4] = { 214 { NULL, 0 }, 215 { "invalid", EINVAL }, 216 { "too small", ERANGE }, 217 { "too large", ERANGE }, 218 }; 219 220 ev[0].err = errno; 221 errno = 0; 222 if (minval > maxval) { 223 error = INVALID; 224 } else { 225 ll = strtoll(numstr, &ep, 10); 226 if (numstr == ep || *ep != '\0') 227 error = INVALID; 228 else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) 229 error = TOOSMALL; 230 else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) 231 error = TOOLARGE; 232 } 233 if (errstrp != NULL) 234 *errstrp = ev[error].errstr; 235 errno = ev[error].err; 236 if (error) 237 ll = 0; 238 239 return ll; 240 } 241 242 /* 243 * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX 244 * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW 245 */ 246 #define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) 247 248 void * 249 reallocarray(void *optr, size_t nmemb, size_t size) 250 { 251 if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && 252 nmemb > 0 && SIZE_MAX / nmemb < size) { 253 errno = ENOMEM; 254 return NULL; 255 } 256 return realloc(optr, size * nmemb); 257 } 258 259 int 260 buffer_appendf(struct buffer *buf, const char *suffixfmt, ...) 261 { 262 va_list ap; 263 int ret; 264 265 va_start(ap, suffixfmt); 266 ret = vsnprintf(buf->data + buf->len, 267 sizeof(buf->data) - buf->len, suffixfmt, ap); 268 va_end(ap); 269 270 if (ret < 0 || (size_t)ret >= (sizeof(buf->data) - buf->len)) { 271 /* truncation occured, discard and error out */ 272 memset(buf->data + buf->len, 0, 273 sizeof(buf->data) - buf->len); 274 return 1; 275 } 276 277 /* increase buffer length by number of bytes written */ 278 buf->len += ret; 279 280 return 0; 281 }