portability.c (2550B)
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 23 pid_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 33 void 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__) 48 ssize_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 95 ssize_t getline(char **linep, size_t *np, FILE *stream) 96 { 97 return getdelim(linep, np, '\n', stream); 98 } 99 100 extern char **environ; 101 102 int clearenv(void) 103 { 104 *environ = NULL; 105 return 0; 106 } 107 #endif