quark

quark web server
git clone git://git.suckless.org/quark
Log | Files | Refs | LICENSE

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 }