util.c - quark - quark web server
 (HTM) git clone git://git.suckless.org/quark
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) 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 }