Codebase list dillo / upstream/0.8.6 dpid / misc_new.c
upstream/0.8.6

Tree @upstream/0.8.6 (Download .tar.gz)

misc_new.c @upstream/0.8.6raw · history · blame

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <glib.h>
#include "dpid_common.h"

#include "misc_new.h"  /* for function prototypes */

/* define to 1 when checking for memory leaks
 * \todo
 * Eliminate need for a_Misc_get_home and a_Misc_get_user when testing for
 * memory leaks by using ld --wrap option to replace g_get_home_dir and
 * g_get_user_name with wrapper functions.
 */
#ifndef TEST
#define TEST 0
#endif


/*
 * Close a FD handling EINTR.
 */
gint a_Misc_close_fd(gint fd)
{
   gint st;

   do {
      st = close(fd);
   } while (st < 0 && errno == EINTR);
   return st;
}

/*
 * Return the user's home directory.
 * Don't free the returned string!
 */
gchar *a_Misc_get_home(void)
{
   gchar *ret;
   ret = (TEST) ? getenv("HOME") : g_get_home_dir();
   return ret;
}

/*
 * Return the user.
 * Don't free the returned string!
 */
gchar *a_Misc_get_user(void)
{
   gchar *ret;
   ret = (TEST) ? getenv("USER") : g_get_user_name();
   return ret;
}

/*
 * Prepend the users home-dir to 'file' string i.e,
 * pass in .dillo/bookmarks.html and it will return
 * /home/imain/.dillo/bookmarks.html
 *
 * Remember to g_free() returned value!
 * copied from misc.c
 */
gchar *a_Misc_prepend_user_home(const char *file)
{
   return (g_strconcat(a_Misc_get_home(), "/", file, NULL));
}

/*
 * Read a line of text up to the newline character, store it into a newly
 * allocated string and return it.
 * (copied from dpi/bm_srv12.c)
 */
char *a_Misc_get_line(FILE *stream)
{
   guint i, size = 64;
   int ch;
   char *buf;

   buf = g_new(char, size);

   for (i = 0; (ch = fgetc(stream)) != EOF; ++i) {
      if (i + 1 == size) {
         size *= 2;
         buf = g_realloc(buf, size);
      }
      if ((buf[i] = ch) == '\n' && ++i)
         break;
   }
   buf[i] = 0;

   if (i > 0) {
      buf = g_realloc(buf, i + 1);
   } else {
      g_free(buf);
      buf = NULL;
   }
   return buf;
}

/*! Reads a dpi tag from a socket
 * \li Continues after a signal interrupt
 * \Return
 * Gstring pointer to tag on success, NULL on failure
 * \important Caller is responsible for freeing the returned GString *
 */
GString *a_Misc_rdtag(int socket)
{
   char c = '\0';
   ssize_t rdlen;
   GString *tag;

   tag = g_string_new(NULL);

   errno = 0;

   do {
      rdlen = read(socket, &c, 1);
      if (rdlen == -1 && errno != EINTR)
         break;
      g_string_append_c(tag, c);
   } while (c != '>');

   if (rdlen == -1) {
      perror("a_Misc_rdtag");
      g_string_free(tag, TRUE);
      return (NULL);
   }
   return (tag);
}

/*!
 * Read a dpi tag from sock
 * \return
 * pointer to dynamically allocated request tag
 */
char *a_Misc_readtag(int sock)
{
   char *tag, c, buf[10];
   size_t buflen, i;
   size_t taglen = 0, tagmem = 10;
   ssize_t rdln = 1;

   tag = NULL;
   buf[0] = '\0';
   buflen = sizeof(buf) / sizeof(buf[0]);
   /* new start */
   tag = (char *) g_malloc(tagmem + 1);
   for (i = 0; (rdln = read(sock, &c, 1)) != 0; i++) {
      if (i == tagmem) {
         tagmem += tagmem;
         tag = (char *) g_realloc(tag, tagmem + 1);
      }
      tag[i] = c;
      taglen += rdln;
      if (c == '>') {
         tag[i + 1] = '\0';
         break;
      }
   }
   /* new end */
   if (rdln == -1) {
      ERRMSG("a_Misc_readtag", "read", errno);
   }

   return (tag);
}

/*! Reads a dpi tag from a socket without hanging on read.
 * \li Continues after a signal interrupt
 * \Return
 * \li 1 on success
 * \li 0 if input is not available within timeout microseconds.
 * \li -1 on failure
 * \important Caller is responsible for freeing the returned GString *
 */
/* Is this useful?
int a_Misc_nohang_rdtag(int socket, int timeout, GString **tag)
{
   int n_fd;
   fd_set sock_set, select_set;
   struct timeval tout;

   FD_ZERO(&sock_set);
   FD_SET(socket, &sock_set);

   errno = 0;
   do {
      select_set = sock_set;
      tout.tv_sec = 0;
      tout.tv_usec = timeout;
      n_fd = select(socket + 1, &select_set, NULL, NULL, &tout);
   } while (n_fd == -1 && errno == EINTR);

   if (n_fd == -1) {
      fprintf(stderr, "%s:%d: a_Misc_nohang_rdtag: %s\n",
              __FILE__, __LINE__, g_strerror(errno));
      return(-1);
   }
   if (n_fd == 0) {
      return(0);
   } else {
      *tag = a_Misc_rdtag(socket);
      return(1);
   }
}
*/

/*
 * Alternative to mkdtemp().
 * Not as strong as mkdtemp, but enough for creating a directory.
 * (adapted from dietlibc)
 */
char *a_Misc_mkdtemp(char *template)
{
   char *tmp = template + strlen(template) - 6;
   int i;
   unsigned int random;

   if (tmp < template)
      goto error;
   for (i = 0; i < 6; ++i)
      if (tmp[i] != 'X') {
       error:
         errno = EINVAL;
         return 0;
      }
   srand((guint)(time(0) ^ getpid()));
   for (;;) {
      random = (unsigned) rand();
      for (i = 0; i < 6; ++i) {
         int hexdigit = (random >> (i * 5)) & 0x1f;

         tmp[i] = hexdigit > 9 ? hexdigit + 'a' - 10 : hexdigit + '0';
      }
      if (mkdir(template, 0700) == 0)
         break;
      if (errno == EEXIST)
         continue;
      return 0;
   }
   return template;
}