tags 516774 = patch tags 516294 = upstream thanks Hi! Please find attached a diff closing #516774 by adding mkstemp(3), again with a minimalistic pseudo-arc4random(3) behind it. I?ve revisited the code. An mkstemp testsuite from the ?net shows it works, except for not caring how many ?X?en are in the template. Addressing #516294, it allows compiling and linking an mksh from today?s CVS against it: tg at tg-sidvm:~/b $ CPPFLAGS=-DMKSH_NO_LIMITS CC=klcc dash ../mksh/Build.sh -r However, the signal problem persists: tg at tg-sidvm:~/b $ ./mksh -c 'print hi' hi tg at tg-sidvm:~/b $ ./mksh -c 'ls' Rebuild.sh eval.o expr.o histrap.o lalloc.o main.o mksh signames.inc test.sh var.o edit.o exec.o funcs.o jobs.o lex.o misc.o shf.o syn.o tree.o ^C^\ 130|tg at tg-sidvm:~/b $ This basically means: builtins can run fine, external programmes never return (Haiku used to have the same problem, they fixed a signal delivery related kernel bug of theirs to solve it; Syllable Desktop and Plan 9 still have this problem). Some more details (add -g to Build.sh to get a debugging executable): GNU gdb (GDB) 7.2-debian Copyright (C) 2010 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "i486-linux-gnu". For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>... Reading symbols from /home/tg/b/mksh...done. Attaching to program: /home/tg/b/mksh, process 18642 0x08072b76 in __syscall_common () (gdb) bt #0 0x08072b76 in __syscall_common () #1 0x00000048 in ?? () #2 0x08060aac in j_waitj (j=0x0, flags=<value optimized out>, where=0x413 <Address 0x413 out of bounds>) at ../mksh/jobs.c:987 Backtrace stopped: previous frame inner to this frame (corrupt stack?) (gdb) info r eax 0xfffffdfe -514 ecx 0x413 1043 edx 0x8075b17 134699799 ebx 0x807dd48 134733128 esp 0xbfcf9618 0xbfcf9618 ebp 0xbfcf9688 0xbfcf9688 esi 0xbfcf9650 -1076914608 edi 0xb770e0e4 -1217339164 eip 0x8072b76 0x8072b76 <__syscall_common+26> eflags 0x246 [ PF ZF IF ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0 The part of the source: 987 sigsuspend(&sm_default); As I already stated, an 1.5.15 patched with C99, getrusage, arc4random and mkstemp used to work, so a regression was introduced later. (I had hoped for 1.5.21 to work, as maks? blog posting said something about signal fixes.) However, I can no longer get one of the older klibc to build on a newer Debian unstable due to kernel headers related changes, so bisecting is almost impossible (for me, that is). I would greatly appreciate if someone could look at the second issue and, addressing the first, accept the patch adding mkstemp() as a feature. Thanks in advance, //mirabilos -- 15:41?<Lo-lan-do:#fusionforge> Somebody write a testsuite for helloworld :-) -------------- next part -------------- diff -Nru klibc-1.5.21/debian/changelog klibc-1.5.21/debian/changelog --- klibc-1.5.21/debian/changelog 2011-01-25 22:47:03.000000000 +0000 +++ klibc-1.5.21/debian/changelog 2011-01-28 12:59:52.000000000 +0000 @@ -1,3 +1,12 @@ +klibc (1.5.21-1+tg.1) unstable; urgency=low + + * debian/patches/add-{arc4random,mkstemp}: add a minimalistic + implementation of the arc4random() API on top of jrand48(3) + to have a self-seeding PRNG; add simple mkstemp(3) implemen- + tation using it. (Closes: #516774) + + -- Thorsten Glaser <tg at mirbsd.de> Fri, 28 Jan 2011 12:59:06 +0000 + klibc (1.5.21-1) unstable; urgency=low * New upstream release (i386 signal(), make 3.82, cleanups) diff -Nru klibc-1.5.21/debian/patches/add-arc4random klibc-1.5.21/debian/patches/add-arc4random --- klibc-1.5.21/debian/patches/add-arc4random 1970-01-01 00:00:00.000000000 +0000 +++ klibc-1.5.21/debian/patches/add-arc4random 2011-01-28 12:54:21.000000000 +0000 @@ -0,0 +1,206 @@ +* Include a helper function needed by add-mkstemp + implementing a minimal arc4random(3) API on top + of jrand48; self-seeding when /proc is mounted. + + Entropy sources: + - 36 bytes from /proc/sys/kernel/random/uuid + - position of temp. buffer on stack (randomised on recent kernels) + + Additional variation (non-random) via: + - PID of last stir call + - PID of current stir call + - count of arc4random() calls since last stir + - time of current stir call + - size of user-provided data + - position of arc4random_addrandom() argument on stack + - filedescriptor of /proc/sys/kernel/random/uuid + - count of bytes read from /proc/sys/kernel/random/uuid + + After stirring, it's good for 65535 arc4random() calls. + The first call to arc4random() after fork() re-stirs. + +Index: klibc-1.5.21/usr/include/stdlib.h +==================================================================+--- klibc-1.5.21.orig/usr/include/stdlib.h 2011-01-28 12:00:27.000000000 +0000 ++++ klibc-1.5.21/usr/include/stdlib.h 2011-01-28 12:00:36.000000000 +0000 +@@ -8,6 +8,7 @@ + #include <klibc/extern.h> + #include <klibc/compiler.h> + #include <stddef.h> ++#include <bitsize/stdint.h> + + #include <malloc.h> + +@@ -61,6 +62,11 @@ + __extern unsigned short *seed48(const unsigned short *); + __extern void srand48(long); + ++/* arc4random API emulation on top of jrand48 algorithm */ ++__extern uint32_t arc4random(void); ++__extern void arc4random_stir(void); ++__extern void arc4random_addrandom(unsigned char *, int); ++ + #define RAND_MAX 0x7fffffff + static __inline__ int rand(void) + { +Index: klibc-1.5.21/usr/klibc/Kbuild +==================================================================+--- klibc-1.5.21.orig/usr/klibc/Kbuild 2011-01-28 12:00:27.000000000 +0000 ++++ klibc-1.5.21/usr/klibc/Kbuild 2011-01-28 12:01:27.000000000 +0000 +@@ -47,6 +47,7 @@ + time.o utime.o llseek.o nice.o getpriority.o \ + qsort.o bsearch.o \ + lrand48.o jrand48.o mrand48.o nrand48.o srand48.o seed48.o \ ++ arc4random.o \ + inet/inet_ntoa.o inet/inet_aton.o inet/inet_addr.o \ + inet/inet_ntop.o inet/inet_pton.o inet/bindresvport.o \ + send.o recv.o \ +Index: klibc-1.5.21/usr/klibc/arc4random.c +==================================================================+--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ klibc-1.5.21/usr/klibc/arc4random.c 2011-01-28 12:35:21.000000000 +0000 +@@ -0,0 +1,144 @@ ++/*- ++ * Minimum self-seeding PRNG/SRNG implementation, exposed ++ * via the standard BSD arc4random(3) API, for klibc ++ * ++ * Copyright (c) 2009, 2011 ++ * Thorsten Glaser <tg at mirbsd.de> ++ * ++ * This file is available under the same terms ("historic ++ * permission clause") as klibc itself or under the terms ++ * of The MirOS Licence (dual licenced). ++ */ ++ ++#include <sys/types.h> ++#include <sys/time.h> ++#include <errno.h> ++#include <fcntl.h> ++#include <stdint.h> ++#include <stdlib.h> ++#include <unistd.h> ++ ++static struct arc4random_state { ++ unsigned short seed[3]; /* for jrand48 */ ++ unsigned short cnt; /* invocation count */ ++ pid_t proc; /* PID of last seed */ ++} arc4_state = { { 0, 0, 0 }, 0, 0 }; ++ ++static void arc4_stir(pid_t); ++ ++/* Jenkins one-at-a-time hash */ ++#define OAAT_Update(h, buf, siz) do { \ ++ register const uint8_t *OAATcp; \ ++ register int OAATn = (siz); \ ++ \ ++ OAATcp = (const void *)(buf); \ ++ while (OAATn--) { \ ++ (h) += *OAATcp++; \ ++ (h) += (h) << 10; \ ++ (h) ^= (h) >> 6; \ ++ } \ ++} while (/* CONSTCOND */ 0) ++#define OAAT_Final(h) do { \ ++ (h) += (h) << 3; \ ++ (h) ^= (h) >> 11; \ ++ (h) += (h) << 15; \ ++} while (/* CONSTCOND */ 0) ++ ++void ++arc4random_addrandom(unsigned char *dat, int datlen) ++{ ++ register uint32_t h; ++ struct { ++ struct timeval tv; /* brings variety if not entropy */ ++ const void *sp; /* stack is randomised by kernel */ ++ uint32_t v; /* datlen on first pass */ ++ } additional_data; ++ ++ gettimeofday(&additional_data.tv, NULL); ++ additional_data.sp = &additional_data; ++ additional_data.v = (uint32_t)datlen; ++ ++ h = 0x100; /* ideal start value for OAAT */ ++ /* hash over additional data which introduces variety */ ++ OAAT_Update(h, &additional_data, sizeof(additional_data)); ++ /* and the data passed */ ++ OAAT_Update(h, dat, datlen); ++ /* and the old state (including PID) */ ++ OAAT_Update(h, &arc4_state, sizeof(arc4_state)); ++ /* reassign part of additional_data for more variety */ ++ additional_data.sp = dat; /* argument address also varies */ ++ additional_data.v = h; /* keep some of h (dat, old state) */ ++ ++ /* split the hash into the new seed (first pass) */ ++ OAAT_Final(h); ++ arc4_state.seed[1] = (unsigned short)(h & 0xFFFF); ++ arc4_state.seed[2] = (unsigned short)(h >> 16); ++ ++ /* split half a hash of new additional_data into the new seed */ ++ h = 0x100; ++ OAAT_Update(h, &additional_data, sizeof(additional_data)); ++ OAAT_Final(h); ++ arc4_state.seed[0] = (unsigned short)(h & 0xFFFF); ++} ++ ++static void ++arc4_stir(pid_t ourpid) ++{ ++ /* define a "stir buffer" */ ++#define UUID_LEN 36 ++ struct { ++ union { ++ ssize_t numb; ++ pid_t newpid; ++ } u; ++ int fd; ++ int count; ++ char uuid[UUID_LEN]; ++ } s; ++ ++ if ((s.fd = open("/proc/sys/kernel/random/uuid", O_RDONLY)) != -1) { ++ s.count = 0; ++ while (s.count < UUID_LEN) { ++ s.u.numb = read(s.fd, s.uuid + s.count, ++ UUID_LEN - s.count); ++ if (s.u.numb == -1) { ++ if (errno == EINTR) { ++ errno = 0; ++ continue; ++ } ++ break; ++ } else if (s.u.numb == 0) ++ break; ++ s.count += s.u.numb; ++ } ++ close(s.fd); ++ } ++ /* else, we are desperate and just use the stack content */ ++#undef UUID_LEN ++ ++ /* s.u.newpid != arc4_state.proc directly after fork(2) */ ++ s.u.newpid = ourpid; ++ ++ /* hash the stir buffer into the PRNG state */ ++ arc4random_addrandom((unsigned char *)&s, sizeof(s)); ++ ++ /* ready to be used for a while */ ++ arc4_state.proc = ourpid; ++ arc4_state.cnt = 0xFFFF; ++} ++ ++void ++arc4random_stir(void) ++{ ++ arc4_stir(getpid()); ++} ++ ++uint32_t ++arc4random(void) ++{ ++ pid_t ourpid; ++ ++ if (arc4_state.proc != (ourpid = getpid()) || arc4_state.cnt-- == 0) ++ arc4_stir(ourpid); ++ return ((uint32_t)(jrand48(arc4_state.seed) & 0xFFFFFFFF)); ++} diff -Nru klibc-1.5.21/debian/patches/add-mkstemp klibc-1.5.21/debian/patches/add-mkstemp --- klibc-1.5.21/debian/patches/add-mkstemp 1970-01-01 00:00:00.000000000 +0000 +++ klibc-1.5.21/debian/patches/add-mkstemp 2011-01-28 12:54:52.000000000 +0000 @@ -0,0 +1,110 @@ +* Address #516774 by adding a relatively minimal mkstemp(3) implementation. + Requires add-arc4random to be applied first. + +Index: klibc-1.5.21/usr/include/stdlib.h +==================================================================+--- klibc-1.5.21.orig/usr/include/stdlib.h 2011-01-28 12:37:06.000000000 +0000 ++++ klibc-1.5.21/usr/include/stdlib.h 2011-01-28 12:37:20.000000000 +0000 +@@ -85,6 +85,8 @@ + srand48(__s); + } + ++__extern int mkstemp(char *); ++ + /* Basic PTY functions. These only work if devpts is mounted! */ + + __extern int unlockpt(int); +Index: klibc-1.5.21/usr/klibc/Kbuild +==================================================================+--- klibc-1.5.21.orig/usr/klibc/Kbuild 2011-01-28 12:37:06.000000000 +0000 ++++ klibc-1.5.21/usr/klibc/Kbuild 2011-01-28 12:37:39.000000000 +0000 +@@ -47,7 +47,7 @@ + time.o utime.o llseek.o nice.o getpriority.o \ + qsort.o bsearch.o \ + lrand48.o jrand48.o mrand48.o nrand48.o srand48.o seed48.o \ +- arc4random.o \ ++ arc4random.o mkstemp.o \ + inet/inet_ntoa.o inet/inet_aton.o inet/inet_addr.o \ + inet/inet_ntop.o inet/inet_pton.o inet/bindresvport.o \ + send.o recv.o \ +Index: klibc-1.5.21/usr/klibc/mkstemp.c +==================================================================+--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ klibc-1.5.21/usr/klibc/mkstemp.c 2011-01-28 12:48:37.000000000 +0000 +@@ -0,0 +1,76 @@ ++/*- ++ * Compact mkstemp(3)-only implementation, for klibc ++ * ++ * Copyright (c) 2009, 2011 ++ * Thorsten Glaser <tg at mirbsd.de> ++ * ++ * This file is available under the same terms ("historic ++ * permission clause") as klibc itself or under the terms ++ * of The MirOS Licence (dual licenced). ++ */ ++ ++#include <sys/types.h> ++#include <sys/stat.h> ++#include <errno.h> ++#include <fcntl.h> ++#include <stdint.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <unistd.h> ++ ++int ++mkstemp(char *template) ++{ ++ int i; ++ char *cp, *sp; ++ struct stat sbuf; ++ ++ cp = template; ++ while (*cp) ++ ++cp; ++ ++ sp = cp; ++ /* generate random suffix */ ++ while (sp > template && sp[-1] == 'X') { ++ i = arc4random() % (26 + 26); ++ *--sp = i < 26 ? 'A' + i : 'a' + i - 26; ++ } ++ if (sp == cp) { ++ /* zero-length template or no X at its end */ ++ errno = EINVAL; ++ return (-1); ++ } ++ ++ /* check the target directory */ ++ cp = sp; ++ while (cp > template && *cp != '/') ++ --cp; ++ if (cp > template) { ++ *cp = '\0'; ++ i = stat(template, &sbuf); ++ *cp = '/'; ++ ++ if (i != 0) ++ /* stat failed, pass errno */ ++ return (-1); ++ if (!S_ISDIR(sbuf.st_mode)) { ++ errno = ENOTDIR; ++ return (-1); ++ } ++ } ++ ++ while (1) { ++ if ((i = open(template, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0 || ++ errno != EEXIST) ++ break; ++ ++ while (*cp == 'Z') ++ if (!*++cp) ++ return (-1); ++ if (*cp == 'z') ++ *cp = 'A'; ++ else ++ ++*cp; ++ } ++ return (i); ++} diff -Nru klibc-1.5.21/debian/patches/series klibc-1.5.21/debian/patches/series --- klibc-1.5.21/debian/patches/series 2011-01-25 22:50:06.000000000 +0000 +++ klibc-1.5.21/debian/patches/series 2011-01-28 12:36:52.000000000 +0000 @@ -2,3 +2,5 @@ klibc-linux-libc-dev insmod debian-changes-1.5.21-1 +add-arc4random +add-mkstemp
Thorsten Glaser
2011-Jan-29 17:31 UTC
[klibc] [PATCH 1/2] Add minimal arc4random(3) API; self-seeding if /proc is mounted.
This patch adds a minimalistic implementation of the BSD arc4random(3) API on top of jrand48(3) (which is already there, for size reasons) to have a simple, self-seeding PRNG (actually SRNG, stretching RNG, since it uses proper entropy from the kernel, just with an algorithm not usable for cryptography). Entropy sources: - 36 bytes from /proc/sys/kernel/random/uuid - position of temp. buffer on stack (randomised on recent kernels) Additional variation (non-random) via: - PID of last stir call - PID of current stir call - count of arc4random() calls since last stir - time of current stir call - size of user-provided data - position of arc4random_addrandom() argument on stack - filedescriptor of /proc/sys/kernel/random/uuid - count of bytes read from /proc/sys/kernel/random/uuid After stirring, it's good for 65535 arc4random() calls. The first call to arc4random() after fork() re-stirs. Signed-off-by: Thorsten Glaser <tg at mirbsd.de> --- usr/include/stdlib.h | 6 ++ usr/klibc/Kbuild | 1 + usr/klibc/arc4random.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+), 0 deletions(-) create mode 100644 usr/klibc/arc4random.c diff --git a/usr/include/stdlib.h b/usr/include/stdlib.h index 406f446..28c7150 100644 --- a/usr/include/stdlib.h +++ b/usr/include/stdlib.h @@ -8,6 +8,7 @@ #include <klibc/extern.h> #include <klibc/compiler.h> #include <stddef.h> +#include <bitsize/stdint.h> #include <malloc.h> @@ -61,6 +62,11 @@ __extern long lrand48(void); __extern unsigned short *seed48(const unsigned short *); __extern void srand48(long); +/* arc4random API emulation on top of jrand48 algorithm */ +__extern uint32_t arc4random(void); +__extern void arc4random_stir(void); +__extern void arc4random_addrandom(unsigned char *, int); + #define RAND_MAX 0x7fffffff static __inline__ int rand(void) { diff --git a/usr/klibc/Kbuild b/usr/klibc/Kbuild index af40367..1138e6d 100644 --- a/usr/klibc/Kbuild +++ b/usr/klibc/Kbuild @@ -47,6 +47,7 @@ klib-y := vsnprintf.o snprintf.o vsprintf.o sprintf.o \ time.o utime.o llseek.o nice.o getpriority.o \ qsort.o bsearch.o \ lrand48.o jrand48.o mrand48.o nrand48.o srand48.o seed48.o \ + arc4random.o \ inet/inet_ntoa.o inet/inet_aton.o inet/inet_addr.o \ inet/inet_ntop.o inet/inet_pton.o inet/bindresvport.o \ send.o recv.o \ diff --git a/usr/klibc/arc4random.c b/usr/klibc/arc4random.c new file mode 100644 index 0000000..1be3629 --- /dev/null +++ b/usr/klibc/arc4random.c @@ -0,0 +1,144 @@ +/*- + * Minimum self-seeding PRNG/SRNG implementation, exposed + * via the standard BSD arc4random(3) API, for klibc + * + * Copyright (c) 2009, 2011 + * Thorsten Glaser <tg at mirbsd.de> + * + * This file is available under the same terms ("historic + * permission clause") as klibc itself or under the terms + * of The MirOS Licence (dual licenced). + */ + +#include <sys/types.h> +#include <sys/time.h> +#include <errno.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdlib.h> +#include <unistd.h> + +static struct arc4random_state { + unsigned short seed[3]; /* for jrand48 */ + unsigned short cnt; /* invocation count */ + pid_t proc; /* PID of last seed */ +} arc4_state = { { 0, 0, 0 }, 0, 0 }; + +static void arc4_stir(pid_t); + +/* Jenkins one-at-a-time hash */ +#define OAAT_Update(h, buf, siz) do { \ + register const uint8_t *OAATcp; \ + register int OAATn = (siz); \ + \ + OAATcp = (const void *)(buf); \ + while (OAATn--) { \ + (h) += *OAATcp++; \ + (h) += (h) << 10; \ + (h) ^= (h) >> 6; \ + } \ +} while (/* CONSTCOND */ 0) +#define OAAT_Final(h) do { \ + (h) += (h) << 3; \ + (h) ^= (h) >> 11; \ + (h) += (h) << 15; \ +} while (/* CONSTCOND */ 0) + +void +arc4random_addrandom(unsigned char *dat, int datlen) +{ + register uint32_t h; + struct { + struct timeval tv; /* brings variety if not entropy */ + const void *sp; /* stack is randomised by kernel */ + uint32_t v; /* datlen on first pass */ + } additional_data; + + gettimeofday(&additional_data.tv, NULL); + additional_data.sp = &additional_data; + additional_data.v = (uint32_t)datlen; + + h = 0x100; /* ideal start value for OAAT */ + /* hash over additional data which introduces variety */ + OAAT_Update(h, &additional_data, sizeof(additional_data)); + /* and the data passed */ + OAAT_Update(h, dat, datlen); + /* and the old state (including PID) */ + OAAT_Update(h, &arc4_state, sizeof(arc4_state)); + /* reassign part of additional_data for more variety */ + additional_data.sp = dat; /* argument address also varies */ + additional_data.v = h; /* keep some of h (dat, old state) */ + + /* split the hash into the new seed (first pass) */ + OAAT_Final(h); + arc4_state.seed[1] = (unsigned short)(h & 0xFFFF); + arc4_state.seed[2] = (unsigned short)(h >> 16); + + /* split half a hash of new additional_data into the new seed */ + h = 0x100; + OAAT_Update(h, &additional_data, sizeof(additional_data)); + OAAT_Final(h); + arc4_state.seed[0] = (unsigned short)(h & 0xFFFF); +} + +static void +arc4_stir(pid_t ourpid) +{ + /* define a "stir buffer" */ +#define UUID_LEN 36 + struct { + union { + ssize_t numb; + pid_t newpid; + } u; + int fd; + int count; + char uuid[UUID_LEN]; + } s; + + if ((s.fd = open("/proc/sys/kernel/random/uuid", O_RDONLY)) != -1) { + s.count = 0; + while (s.count < UUID_LEN) { + s.u.numb = read(s.fd, s.uuid + s.count, + UUID_LEN - s.count); + if (s.u.numb == -1) { + if (errno == EINTR) { + errno = 0; + continue; + } + break; + } else if (s.u.numb == 0) + break; + s.count += s.u.numb; + } + close(s.fd); + } + /* else, we are desperate and just use the stack content */ +#undef UUID_LEN + + /* s.u.newpid != arc4_state.proc directly after fork(2) */ + s.u.newpid = ourpid; + + /* hash the stir buffer into the PRNG state */ + arc4random_addrandom((unsigned char *)&s, sizeof(s)); + + /* ready to be used for a while */ + arc4_state.proc = ourpid; + arc4_state.cnt = 0xFFFF; +} + +void +arc4random_stir(void) +{ + arc4_stir(getpid()); +} + +uint32_t +arc4random(void) +{ + pid_t ourpid; + + if (arc4_state.proc != (ourpid = getpid()) || arc4_state.cnt-- == 0) + arc4_stir(ourpid); + return ((uint32_t)(jrand48(arc4_state.seed) & 0xFFFFFFFF)); +} -- 1.7.2.3
Thorsten Glaser
2011-Jan-29 17:31 UTC
[klibc] [PATCH 2/2] Add a relatively minimal mkstemp(3) implementation.
Requires arc4random. Debian: (Closes: #516774) Signed-off-by: Thorsten Glaser <tg at mirbsd.de> --- usr/include/stdlib.h | 2 + usr/klibc/Kbuild | 2 +- usr/klibc/mkstemp.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletions(-) create mode 100644 usr/klibc/mkstemp.c diff --git a/usr/include/stdlib.h b/usr/include/stdlib.h index 28c7150..74c9bf3 100644 --- a/usr/include/stdlib.h +++ b/usr/include/stdlib.h @@ -85,6 +85,8 @@ static __inline__ void srandom(unsigned int __s) srand48(__s); } +__extern int mkstemp(char *); + /* Basic PTY functions. These only work if devpts is mounted! */ __extern int unlockpt(int); diff --git a/usr/klibc/Kbuild b/usr/klibc/Kbuild index 1138e6d..783ed69 100644 --- a/usr/klibc/Kbuild +++ b/usr/klibc/Kbuild @@ -47,7 +47,7 @@ klib-y := vsnprintf.o snprintf.o vsprintf.o sprintf.o \ time.o utime.o llseek.o nice.o getpriority.o \ qsort.o bsearch.o \ lrand48.o jrand48.o mrand48.o nrand48.o srand48.o seed48.o \ - arc4random.o \ + arc4random.o mkstemp.o \ inet/inet_ntoa.o inet/inet_aton.o inet/inet_addr.o \ inet/inet_ntop.o inet/inet_pton.o inet/bindresvport.o \ send.o recv.o \ diff --git a/usr/klibc/mkstemp.c b/usr/klibc/mkstemp.c new file mode 100644 index 0000000..ef575da --- /dev/null +++ b/usr/klibc/mkstemp.c @@ -0,0 +1,76 @@ +/*- + * Compact mkstemp(3)-only implementation, for klibc + * + * Copyright (c) 2009, 2011 + * Thorsten Glaser <tg at mirbsd.de> + * + * This file is available under the same terms ("historic + * permission clause") as klibc itself or under the terms + * of The MirOS Licence (dual licenced). + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +int +mkstemp(char *template) +{ + int i; + char *cp, *sp; + struct stat sbuf; + + cp = template; + while (*cp) + ++cp; + + sp = cp; + /* generate random suffix */ + while (sp > template && sp[-1] == 'X') { + i = arc4random() % (26 + 26); + *--sp = i < 26 ? 'A' + i : 'a' + i - 26; + } + if (sp == cp) { + /* zero-length template or no X at its end */ + errno = EINVAL; + return (-1); + } + + /* check the target directory */ + cp = sp; + while (cp > template && *cp != '/') + --cp; + if (cp > template) { + *cp = '\0'; + i = stat(template, &sbuf); + *cp = '/'; + + if (i != 0) + /* stat failed, pass errno */ + return (-1); + if (!S_ISDIR(sbuf.st_mode)) { + errno = ENOTDIR; + return (-1); + } + } + + while (1) { + if ((i = open(template, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0 || + errno != EEXIST) + break; + + while (*cp == 'Z') + if (!*++cp) + return (-1); + if (*cp == 'z') + *cp = 'A'; + else + ++*cp; + } + return (i); +} -- 1.7.2.3