blob: 78e500b1f85e21bddb45a243e6110561b03541dc [file] [log] [blame]
/* portability.c - code to workaround the deficiencies of various platforms.
*
* Copyright 2012 Rob Landley <rob@landley.net>
* Copyright 2012 Georgi Chorbadzhiyski <gf@unixsol.org>
*/
#include "toys.h"
// We can't fork() on nommu systems, and vfork() requires an exec() or exit()
// before resuming the parent (because they share a heap until then). And no,
// we can't implement our own clone() call that does the equivalent of fork()
// because nommu heaps use physical addresses so if we copy the heap all our
// pointers are wrong. (You need an mmu in order to map two heaps to the same
// address range without interfering with each other.) In the absence of
// a portable way to tell malloc() to start a new heap without freeing the old
// one, you pretty much need the exec().)
// So we exec ourselves (via /proc/self/exe, if anybody knows a way to
// re-exec self without depending on the filesystem, I'm all ears),
// and use the arguments to signal reentry.
#if CFG_TOYBOX_FORK
pid_t xfork(void)
{
pid_t pid = fork();
if (pid < 0) perror_exit("fork");
return pid;
}
#endif
#if defined(__APPLE__)
ssize_t getdelim(char **linep, size_t *np, int delim, FILE *stream)
{
int ch;
size_t new_len;
ssize_t i = 0;
char *line, *new_line;
// Invalid input
if (!linep || !np) {
errno = EINVAL;
return -1;
}
if (*linep == NULL || *np == 0) {
*np = 1024;
*linep = calloc(1, *np);
if (*linep == NULL) return -1;
}
line = *linep;
while ((ch = getc(stream)) != EOF) {
if (i > *np) {
// Need more space
new_len = *np + 1024;
new_line = realloc(*linep, new_len);
if (!new_line) return -1;
*np = new_len;
line = *linep = new_line;
}
line[i] = ch;
if (ch == delim) break;
i += 1;
}
if (i > *np) {
// Need more space
new_len = i + 2;
new_line = realloc(*linep, new_len);
if (!new_line) return -1;
*np = new_len;
line = *linep = new_line;
}
line[i + 1] = '\0';
return i > 0 ? i : -1;
}
ssize_t getline(char **linep, size_t *np, FILE *stream)
{
return getdelim(linep, np, '\n', stream);
}
extern char **environ;
int clearenv(void)
{
*environ = NULL;
return 0;
}
#endif