toybox/lib/portability.c
<<
>>
Prefs
   1/* portability.c - code to workaround the deficiencies of various platforms.
   2 *
   3 * Copyright 2012 Rob Landley <rob@landley.net>
   4 * Copyright 2012 Georgi Chorbadzhiyski <gf@unixsol.org>
   5 */
   6
   7#include "toys.h"
   8
   9// We can't fork() on nommu systems, and vfork() requires an exec() or exit()
  10// before resuming the parent (because they share a heap until then). And no,
  11// we can't implement our own clone() call that does the equivalent of fork()
  12// because nommu heaps use physical addresses so if we copy the heap all our
  13// pointers are wrong. (You need an mmu in order to map two heaps to the same
  14// address range without interfering with each other.) In the absence of
  15// a portable way to tell malloc() to start a new heap without freeing the old
  16// one, you pretty much need the exec().)
  17
  18// So we exec ourselves (via /proc/self/exe, if anybody knows a way to
  19// re-exec self without depending on the filesystem, I'm all ears),
  20// and use the arguments to signal reentry.
  21
  22#if CFG_TOYBOX_FORK
  23pid_t xfork(void)
  24{
  25  pid_t pid = fork();
  26
  27  if (pid < 0) perror_exit("fork");
  28
  29  return pid;
  30}
  31#endif
  32
  33void xgetrandom(void *buf, unsigned buflen, unsigned flags)
  34{
  35  int fd;
  36
  37#if CFG_TOYBOX_GETRANDOM
  38  if (buflen == getrandom(buf, buflen, flags)) return;
  39  if (!CFG_TOYBOX_ON_ANDROID || errno!=ENOSYS) perror_exit("getrandom");
  40#endif
  41
  42  fd = xopen(flags ? "/dev/random" : "/dev/urandom", O_RDONLY);
  43  xreadall(fd, buf, buflen);
  44  close(fd);
  45}
  46
  47#if defined(__APPLE__)
  48ssize_t getdelim(char **linep, size_t *np, int delim, FILE *stream)
  49{
  50  int ch;
  51  size_t new_len;
  52  ssize_t i = 0;
  53  char *line, *new_line;
  54
  55  // Invalid input
  56  if (!linep || !np) {
  57    errno = EINVAL;
  58    return -1;
  59  }
  60
  61  if (*linep == NULL || *np == 0) {
  62    *np = 1024;
  63    *linep = calloc(1, *np);
  64    if (*linep == NULL) return -1;
  65  }
  66  line = *linep;
  67
  68  while ((ch = getc(stream)) != EOF) {
  69    if (i > *np) {
  70      // Need more space
  71      new_len = *np + 1024;
  72      new_line = realloc(*linep, new_len);
  73      if (!new_line) return -1;
  74      *np = new_len;
  75      line = *linep = new_line;
  76    }
  77
  78    line[i++] = ch;
  79    if (ch == delim) break;
  80  }
  81
  82  if (i > *np) {
  83    // Need more space
  84    new_len  = i + 2;
  85    new_line = realloc(*linep, new_len);
  86    if (!new_line) return -1;
  87    *np = new_len;
  88    line = *linep = new_line;
  89  }
  90  line[i] = '\0';
  91
  92  return i > 0 ? i : -1;
  93}
  94
  95ssize_t getline(char **linep, size_t *np, FILE *stream)
  96{
  97  return getdelim(linep, np, '\n', stream);
  98}
  99
 100extern char **environ;
 101
 102int clearenv(void)
 103{
 104  *environ = NULL;
 105  return 0;
 106}
 107#endif
 108