"Fossies" - the Fresh Open Source Software Archive

Member "darkstat-3.0.721/conv.c" (12 Jan 2022, 9354 Bytes) of package /linux/privat/darkstat-3.0.721.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /* darkstat 3
    2  * copyright (c) 2001-2014 Emil Mikulic.
    3  *
    4  * conv.c: convenience functions.
    5  *
    6  * Permission to use, copy, modify, and distribute this file for any
    7  * purpose with or without fee is hereby granted, provided that the above
    8  * copyright notice and this permission notice appear in all copies.
    9  *
   10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   17  */
   18 
   19 #include "conv.h"
   20 
   21 #include <sys/wait.h>
   22 #include <assert.h>
   23 #include <ctype.h>
   24 #include "err.h"
   25 #include <errno.h>
   26 #include <fcntl.h>
   27 #include <grp.h>
   28 #include <limits.h>
   29 #include <pwd.h>
   30 #include <stdio.h>
   31 #include <stdlib.h>
   32 #include <string.h>
   33 #include <time.h>
   34 #include <unistd.h>
   35 
   36 #define PATH_DEVNULL "/dev/null"
   37 
   38 /* malloc() that exits on failure. */
   39 void *
   40 xmalloc(const size_t size)
   41 {
   42    void *ptr = malloc(size);
   43 
   44    if (ptr == NULL)
   45       errx(1, "malloc(): out of memory");
   46    return (ptr);
   47 }
   48 
   49 /* calloc() that exits on failure. */
   50 void *
   51 xcalloc(const size_t num, const size_t size)
   52 {
   53    void *ptr = calloc(num, size);
   54 
   55    if (ptr == NULL)
   56       errx(1, "calloc(): out of memory");
   57    return (ptr);
   58 }
   59 
   60 /* realloc() that exits on failure. */
   61 void *
   62 xrealloc(void *original, const size_t size)
   63 {
   64     void *ptr = realloc(original, size);
   65 
   66     if (ptr == NULL)
   67       errx(1, "realloc(): out of memory");
   68     return (ptr);
   69 }
   70 
   71 /* strdup() that exits on failure. */
   72 char *
   73 xstrdup(const char *s)
   74 {
   75    char *tmp = strdup(s);
   76 
   77    if (tmp == NULL)
   78       errx(1, "strdup(): out of memory");
   79    return (tmp);
   80 }
   81 
   82 /* ---------------------------------------------------------------------------
   83  * Split string out of src with range [left:right-1]
   84  */
   85 char *
   86 split_string(const char *src, const size_t left, const size_t right)
   87 {
   88     char *dest;
   89     assert(left <= right);
   90     assert(left < strlen(src));   /* [left means must be smaller */
   91     assert(right <= strlen(src)); /* right) means can be equal or smaller */
   92 
   93     dest = xmalloc(right - left + 1);
   94     memcpy(dest, src+left, right-left);
   95     dest[right-left] = '\0';
   96     return (dest);
   97 }
   98 
   99 /* ---------------------------------------------------------------------------
  100  * Uppercasify all characters in a string of given length.
  101  */
  102 void
  103 strntoupper(char *str, const size_t length)
  104 {
  105     size_t i;
  106 
  107     for (i=0; i<length; i++)
  108         str[i] = toupper(str[i]);
  109 }
  110 
  111 /* ---------------------------------------------------------------------------
  112  * Returns non-zero if haystack starts with needle.
  113  */
  114 int
  115 str_starts_with(const char *haystack, const char *needle)
  116 {
  117    int i = 0;
  118 
  119    while (needle[i] != '\0') {
  120       if ((haystack[i] == '\0') || (haystack[i] != needle[i]))
  121          return (0);
  122       i++;
  123    }
  124    return (1);
  125 }
  126 
  127 /* split - splits a string by a delimiter character into an array of
  128  * string chunks.
  129  *
  130  * The chunks and the array are dynamically allocated using xmalloc() so
  131  * it will errx() if it runs out of memory.
  132  *
  133  *    int num_chunks;
  134  *    char **chunks = split('.', "..one...two....", &num_chunks);
  135  *
  136  *    num_chunks = 2, chunks = { "one", "two", NULL }
  137  */
  138 char **
  139 split(const char delimiter, const char *str, unsigned int *num_chunks)
  140 {
  141    unsigned int num = 0;
  142    char **chunks = NULL;
  143    size_t left, right = 0;
  144 
  145    #define PUSH(c) do { num++;  chunks = (char**) xrealloc(chunks, \
  146       sizeof(*chunks) * num);  chunks[num-1] = c; } while(0)
  147 
  148    for(;;) {
  149       /* find first non-delimiter */
  150       for (left = right; str[left] == delimiter; left++)
  151             ;
  152 
  153       if (str[left] == '\0')
  154          break; /* ran out of string */
  155 
  156       /* find first delimiter or end of string */
  157       for (right=left+1;
  158          str[right] != delimiter && str[right] != '\0';
  159          right++)
  160             ;
  161 
  162       /* split chunk out */
  163       PUSH( split_string(str, left, right) );
  164 
  165       if (str[right] == '\0')
  166          break; /* ran out of string */
  167       else
  168          right++;
  169    }
  170 
  171    /* return */
  172    PUSH(NULL);
  173    if (num_chunks != NULL)
  174       *num_chunks = num-1; /* NULL doesn't count */
  175    return (chunks);
  176    #undef PUSH
  177 }
  178 
  179 /* Given an HTTP query string and a key to search for, return the value
  180  * associated with it, or NULL if there is no such key or qs is NULL.
  181  * The returned string needs to be freed.
  182  *
  183  * e.g.:
  184  * qs = "sort=in&start=20";
  185  * qs_get(sq, "sort") returns "in"
  186  * qs_get(sq, "end") returns NULL
  187  */
  188 char *
  189 qs_get(const char *qs, const char *key)
  190 {
  191    size_t pos, qslen, keylen;
  192 
  193    if (qs == NULL) return NULL;
  194 
  195    qslen = strlen(qs);
  196    keylen = strlen(key);
  197    pos = 0;
  198    while (pos < qslen) {
  199       if (!(pos + keylen + 1 < qslen))
  200          /* not enough room for "key" + "=" */
  201          return NULL;
  202       else {
  203          if (str_starts_with(qs+pos, key) && qs[pos+keylen] == '=') {
  204             /* found key= */
  205             size_t start, end;
  206 
  207             start = pos + keylen + 1;
  208             for (end=start; end<qslen && qs[end] != '&'; end++)
  209                ;
  210             return split_string(qs, start, end);
  211          } else {
  212             /* didn't find key, skip to next & */
  213             do { pos++; } while ((pos < qslen) && (qs[pos] != '&'));
  214             pos++; /* skip the ampersand */
  215          }
  216       }
  217    }
  218    return NULL; /* not found */
  219 }
  220 
  221 static int lifeline[2] = { -1, -1 };
  222 static int fd_null = -1;
  223 
  224 void
  225 daemonize_start(void)
  226 {
  227    pid_t f, w;
  228 
  229    if (pipe(lifeline) == -1)
  230       err(1, "pipe(lifeline)");
  231 
  232    fd_null = open(PATH_DEVNULL, O_RDWR, 0);
  233    if (fd_null == -1)
  234       err(1, "open(" PATH_DEVNULL ")");
  235 
  236    f = fork();
  237    if (f == -1)
  238       err(1, "fork");
  239    else if (f != 0) {
  240       /* parent: wait for child */
  241       char tmp[1];
  242       int status;
  243 
  244       verbosef("parent waiting");
  245       if (close(lifeline[1]) == -1)
  246          warn("close lifeline in parent");
  247       if (read(lifeline[0], tmp, sizeof(tmp)) != 0) /* expecting EOF */
  248          err(1, "lifeline read() failed");
  249       verbosef("parent done reading, calling waitpid");
  250       w = waitpid(f, &status, WNOHANG);
  251       verbosef("waitpid ret %d, status is %d", w, status);
  252       if (w == -1)
  253          err(1, "waitpid");
  254       else if (w == 0)
  255          /* child is running happily */
  256          exit(EXIT_SUCCESS);
  257       else
  258          /* child init failed, pass on its exit status */
  259          exit(WEXITSTATUS(status));
  260    }
  261    /* else we are the child: continue initializing */
  262 }
  263 
  264 void
  265 daemonize_finish(void)
  266 {
  267    if (fd_null == -1)
  268       return; /* didn't daemonize_start(), i.e. we're not daemonizing */
  269 
  270    if (setsid() == -1)
  271       err(1, "setsid");
  272    if (close(lifeline[0]) == -1)
  273       warn("close read end of lifeline in child");
  274    if (close(lifeline[1]) == -1)
  275       warn("couldn't cut the lifeline");
  276 
  277    /* close all our std fds */
  278    if (dup2(fd_null, STDIN_FILENO) == -1)
  279       warn("dup2(stdin)");
  280    if (dup2(fd_null, STDOUT_FILENO) == -1)
  281       warn("dup2(stdout)");
  282    if (dup2(fd_null, STDERR_FILENO) == -1)
  283       warn("dup2(stderr)");
  284    if (fd_null > 2)
  285       close(fd_null);
  286 }
  287 
  288 /*
  289  * For security, chroot (optionally) and drop privileges.
  290  * Pass a NULL chroot_dir to disable chroot() behaviour.
  291  */
  292 void privdrop(const char *chroot_dir, const char *privdrop_user) {
  293    struct passwd *pw;
  294 
  295    errno = 0;
  296    pw = getpwnam(privdrop_user);
  297 
  298    if (pw == NULL) {
  299       if (errno == 0)
  300          errx(1, "getpwnam(\"%s\") failed: no such user", privdrop_user);
  301       else
  302          err(1, "getpwnam(\"%s\") failed", privdrop_user);
  303    }
  304    if (chroot_dir == NULL) {
  305       verbosef("no --chroot dir specified, darkstat will not chroot()");
  306    } else {
  307       /* Read /etc/localtime before we chroot. This works on FreeBSD but not
  308        * on Linux / with glibc (as of 2.22) */
  309       tzset();
  310       if (chroot(chroot_dir) == -1)
  311          err(1, "chroot(\"%s\") failed", chroot_dir);
  312       if (chdir("/") == -1)
  313          err(1, "chdir(\"/\") failed");
  314       verbosef("chrooted into: %s", chroot_dir);
  315    }
  316    {
  317       gid_t list[1];
  318       list[0] = pw->pw_gid;
  319       if (setgroups(1, list) == -1)
  320          err(1, "setgroups");
  321    }
  322    if (setgid(pw->pw_gid) == -1)
  323       err(1, "setgid");
  324    if (setuid(pw->pw_uid) == -1)
  325       err(1, "setuid");
  326    verbosef("set uid/gid to %d/%d", (int)pw->pw_uid, (int)pw->pw_gid);
  327 }
  328 
  329 /* Make the specified file descriptor non-blocking. */
  330 void
  331 fd_set_nonblock(const int fd)
  332 {
  333    int flags;
  334 
  335    if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
  336       err(1, "fcntl(fd %d) to get flags", fd);
  337    flags |= O_NONBLOCK;
  338    if (fcntl(fd, F_SETFL, flags) == -1)
  339       err(1, "fcntl(fd %d) to set O_NONBLOCK", fd);
  340    assert( (fcntl(fd, F_GETFL, 0) & O_NONBLOCK ) == O_NONBLOCK );
  341 }
  342 
  343 /* Make the specified file descriptor blocking. */
  344 void
  345 fd_set_block(const int fd)
  346 {
  347    int flags;
  348 
  349    if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
  350       err(1, "fcntl(fd %d) to get flags", fd);
  351    flags &= ~O_NONBLOCK;
  352    if (fcntl(fd, F_SETFL, flags) == -1)
  353       err(1, "fcntl(fd %d) to unset O_NONBLOCK", fd);
  354    assert( (fcntl(fd, F_GETFL, 0) & O_NONBLOCK ) == 0 );
  355 }
  356 
  357 /* vim:set ts=3 sw=3 tw=78 expandtab: */