aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--main/musl/0001-v1.1.1-to-76f440cf.patch3459
-rw-r--r--main/musl/APKBUILD14
2 files changed, 3464 insertions, 9 deletions
diff --git a/main/musl/0001-v1.1.1-to-76f440cf.patch b/main/musl/0001-v1.1.1-to-76f440cf.patch
new file mode 100644
index 0000000000..e4025585ef
--- /dev/null
+++ b/main/musl/0001-v1.1.1-to-76f440cf.patch
@@ -0,0 +1,3459 @@
+diff --git a/arch/arm/bits/syscall.h b/arch/arm/bits/syscall.h
+index dc54bde..0b6ea7d 100644
+--- a/arch/arm/bits/syscall.h
++++ b/arch/arm/bits/syscall.h
+@@ -333,6 +333,8 @@
+ #define __NR_process_vm_writev 377
+ #define __NR_kcmp 378
+ #define __NR_finit_module 379
++#define __NR_sched_setattr 380
++#define __NR_sched_getattr 381
+
+
+ /* Repeated with SYS_ prefix */
+@@ -672,3 +674,5 @@
+ #define SYS_process_vm_writev 377
+ #define SYS_kcmp 378
+ #define SYS_finit_module 379
++#define SYS_sched_setattr 380
++#define SYS_sched_getattr 381
+diff --git a/arch/i386/bits/syscall.h b/arch/i386/bits/syscall.h
+index 2af242b..7e48791 100644
+--- a/arch/i386/bits/syscall.h
++++ b/arch/i386/bits/syscall.h
+@@ -349,6 +349,8 @@
+ #define __NR_process_vm_writev 348
+ #define __NR_kcmp 349
+ #define __NR_finit_module 350
++#define __NR_sched_setattr 351
++#define __NR_sched_getattr 352
+
+
+ /* Repeated with SYS_ prefix */
+@@ -704,3 +706,5 @@
+ #define SYS_process_vm_writev 348
+ #define SYS_kcmp 349
+ #define SYS_finit_module 350
++#define SYS_sched_setattr 351
++#define SYS_sched_getattr 352
+diff --git a/arch/microblaze/bits/syscall.h b/arch/microblaze/bits/syscall.h
+index 712d47a..b8b1d2e 100644
+--- a/arch/microblaze/bits/syscall.h
++++ b/arch/microblaze/bits/syscall.h
+@@ -375,6 +375,8 @@
+ #define __NR_process_vm_writev 378
+ #define __NR_kcmp 379
+ #define __NR_finit_module 380
++#define __NR_sched_setattr 381
++#define __NR_sched_getattr 382
+
+ /* Repeated with SYS_ prefix */
+
+@@ -756,3 +758,5 @@
+ #define SYS_process_vm_writev 378
+ #define SYS_kcmp 379
+ #define SYS_finit_module 380
++#define SYS_sched_setattr 381
++#define SYS_sched_getattr 382
+diff --git a/arch/mips/bits/syscall.h b/arch/mips/bits/syscall.h
+index 574d603..f3d30d0 100644
+--- a/arch/mips/bits/syscall.h
++++ b/arch/mips/bits/syscall.h
+@@ -346,6 +346,8 @@
+ #define __NR_process_vm_writev 4346
+ #define __NR_kcmp 4347
+ #define __NR_finit_module 4348
++#define __NR_sched_setattr 4349
++#define __NR_sched_getattr 4350
+
+
+ /* Repeated with SYS_ prefix */
+@@ -697,3 +699,5 @@
+ #define SYS_process_vm_writev 4346
+ #define SYS_kcmp 4347
+ #define SYS_finit_module 4348
++#define SYS_sched_setattr 4349
++#define SYS_sched_getattr 4350
+diff --git a/arch/mips/syscall_arch.h b/arch/mips/syscall_arch.h
+index c52976e..e62c339 100644
+--- a/arch/mips/syscall_arch.h
++++ b/arch/mips/syscall_arch.h
+@@ -5,6 +5,8 @@
+
+ long (__syscall)(long, ...);
+
++#define SYSCALL_RLIM_INFINITY (-1UL/2)
++
+ #ifndef __clang__
+
+ #define __asm_syscall(...) do { \
+diff --git a/arch/powerpc/bits/syscall.h b/arch/powerpc/bits/syscall.h
+index 385860b..16f0abe 100644
+--- a/arch/powerpc/bits/syscall.h
++++ b/arch/powerpc/bits/syscall.h
+@@ -368,6 +368,8 @@
+ #define __NR_process_vm_writev 352
+ #define __NR_finit_module 353
+ #define __NR_kcmp 354
++#define __NR_sched_setattr 355
++#define __NR_sched_getattr 356
+
+ /*
+ * repeated with SYS prefix
+@@ -742,3 +744,5 @@
+ #define SYS_process_vm_writev 352
+ #define SYS_finit_module 353
+ #define SYS_kcmp 354
++#define SYS_sched_setattr 355
++#define SYS_sched_getattr 356
+diff --git a/arch/x32/bits/syscall.h b/arch/x32/bits/syscall.h
+index 95e2d2f..1c245e7 100644
+--- a/arch/x32/bits/syscall.h
++++ b/arch/x32/bits/syscall.h
+@@ -271,6 +271,9 @@
+ #define __NR_getcpu (__X32_SYSCALL_BIT + 309)
+ #define __NR_kcmp (__X32_SYSCALL_BIT + 312)
+ #define __NR_finit_module (__X32_SYSCALL_BIT + 313)
++#define __NR_sched_setattr (__X32_SYSCALL_BIT + 314)
++#define __NR_sched_getattr (__X32_SYSCALL_BIT + 315)
++
+ #define __NR_rt_sigaction (__X32_SYSCALL_BIT + 512)
+ #define __NR_rt_sigreturn (__X32_SYSCALL_BIT + 513)
+ #define __NR_ioctl (__X32_SYSCALL_BIT + 514)
+@@ -591,6 +594,9 @@
+ #define SYS_getcpu __NR_getcpu
+ #define SYS_kcmp __NR_kcmp
+ #define SYS_finit_module __NR_finit_module
++#define SYS_sched_setattr __NR_sched_setattr
++#define SYS_sched_getattr __NR_sched_getattr
++
+ #define SYS_rt_sigaction __NR_rt_sigaction
+ #define SYS_rt_sigreturn __NR_rt_sigreturn
+ #define SYS_ioctl __NR_ioctl
+diff --git a/arch/x86_64/bits/syscall.h b/arch/x86_64/bits/syscall.h
+index 5eb9b83..7bcb711 100644
+--- a/arch/x86_64/bits/syscall.h
++++ b/arch/x86_64/bits/syscall.h
+@@ -312,6 +312,8 @@
+ #define __NR_process_vm_writev 311
+ #define __NR_kcmp 312
+ #define __NR_finit_module 313
++#define __NR_sched_setattr 314
++#define __NR_sched_getattr 315
+
+ #undef __NR_fstatat
+ #undef __NR_pread
+@@ -641,6 +643,8 @@
+ #define SYS_process_vm_writev 311
+ #define SYS_kcmp 312
+ #define SYS_finit_module 313
++#define SYS_sched_setattr 314
++#define SYS_sched_getattr 315
+
+ #undef SYS_fstatat
+ #undef SYS_pread
+diff --git a/include/netinet/in.h b/include/netinet/in.h
+index ee6e19f..89188c7 100644
+--- a/include/netinet/in.h
++++ b/include/netinet/in.h
+@@ -198,6 +198,7 @@ uint16_t ntohs(uint16_t);
+ #define IP_ORIGDSTADDR 20
+ #define IP_RECVORIGDSTADDR IP_ORIGDSTADDR
+ #define IP_MINTTL 21
++#define IP_NODEFRAG 22
+ #define IP_MULTICAST_IF 32
+ #define IP_MULTICAST_TTL 33
+ #define IP_MULTICAST_LOOP 34
+@@ -218,6 +219,7 @@ uint16_t ntohs(uint16_t);
+ #define IP_PMTUDISC_DO 2
+ #define IP_PMTUDISC_PROBE 3
+ #define IP_PMTUDISC_INTERFACE 4
++#define IP_PMTUDISC_OMIT 5
+
+ #define IP_DEFAULT_MULTICAST_TTL 1
+ #define IP_DEFAULT_MULTICAST_LOOP 1
+@@ -351,9 +353,17 @@ struct ip6_mtuinfo
+ #define IPV6_RTHDR 57
+ #define IPV6_RECVDSTOPTS 58
+ #define IPV6_DSTOPTS 59
+-
++#define IPV6_RECVPATHMTU 60
++#define IPV6_PATHMTU 61
++#define IPV6_DONTFRAG 62
+ #define IPV6_RECVTCLASS 66
+ #define IPV6_TCLASS 67
++#define IPV6_ADDR_PREFERENCES 72
++#define IPV6_MINHOPCOUNT 73
++#define IPV6_ORIGDSTADDR 74
++#define IPV6_RECVORIGDSTADDR IPV6_ORIGDSTADDR
++#define IPV6_TRANSPARENT 75
++#define IPV6_UNICAST_IF 76
+
+ #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
+ #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
+@@ -364,6 +374,16 @@ struct ip6_mtuinfo
+ #define IPV6_PMTUDISC_WANT 1
+ #define IPV6_PMTUDISC_DO 2
+ #define IPV6_PMTUDISC_PROBE 3
++#define IPV6_PMTUDISC_INTERFACE 4
++#define IPV6_PMTUDISC_OMIT 5
++
++#define IPV6_PREFER_SRC_TMP 0x0001
++#define IPV6_PREFER_SRC_PUBLIC 0x0002
++#define IPV6_PREFER_SRC_PUBTMP_DEFAULT 0x0100
++#define IPV6_PREFER_SRC_COA 0x0004
++#define IPV6_PREFER_SRC_HOME 0x0400
++#define IPV6_PREFER_SRC_CGA 0x0008
++#define IPV6_PREFER_SRC_NONCGA 0x0800
+
+ #define IPV6_RTHDR_LOOSE 0
+ #define IPV6_RTHDR_STRICT 1
+diff --git a/include/sched.h b/include/sched.h
+index 105dac9..4394b64 100644
+--- a/include/sched.h
++++ b/include/sched.h
+@@ -38,6 +38,7 @@ int sched_yield(void);
+ #define SCHED_RR 2
+ #define SCHED_BATCH 3
+ #define SCHED_IDLE 5
++#define SCHED_DEADLINE 6
+ #define SCHED_RESET_ON_FORK 0x40000000
+
+ #ifdef _GNU_SOURCE
+diff --git a/include/signal.h b/include/signal.h
+index 3fb21b2..c36e4d5 100644
+--- a/include/signal.h
++++ b/include/signal.h
+@@ -89,19 +89,24 @@ typedef struct {
+ union {
+ char __pad[128 - 2*sizeof(int) - sizeof(long)];
+ struct {
+- pid_t si_pid;
+- uid_t si_uid;
+- union sigval si_sigval;
+- } __rt;
+- struct {
+- unsigned int si_timer1, si_timer2;
+- } __timer;
+- struct {
+- pid_t si_pid;
+- uid_t si_uid;
+- int si_status;
+- clock_t si_utime, si_stime;
+- } __sigchld;
++ union {
++ struct {
++ pid_t si_pid;
++ uid_t si_uid;
++ } __piduid;
++ struct {
++ int si_timerid;
++ int si_overrun;
++ } __timer;
++ } __first;
++ union {
++ union sigval si_value;
++ struct {
++ int si_status;
++ clock_t si_utime, si_stime;
++ } __sigchld;
++ } __second;
++ } __si_common;
+ struct {
+ void *si_addr;
+ short si_addr_lsb;
+@@ -117,20 +122,20 @@ typedef struct {
+ } __sigsys;
+ } __si_fields;
+ } siginfo_t;
+-#define si_pid __si_fields.__sigchld.si_pid
+-#define si_uid __si_fields.__sigchld.si_uid
+-#define si_status __si_fields.__sigchld.si_status
+-#define si_utime __si_fields.__sigchld.si_utime
+-#define si_stime __si_fields.__sigchld.si_stime
+-#define si_value __si_fields.__rt.si_sigval
++#define si_pid __si_fields.__si_common.__first.__piduid.si_pid
++#define si_uid __si_fields.__si_common.__first.__piduid.si_uid
++#define si_status __si_fields.__si_common.__second.__sigchld.si_status
++#define si_utime __si_fields.__si_common.__second.__sigchld.si_utime
++#define si_stime __si_fields.__si_common.__second.__sigchld.si_stime
++#define si_value __si_fields.__si_common.__second.si_value
+ #define si_addr __si_fields.__sigfault.si_addr
+ #define si_addr_lsb __si_fields.__sigfault.si_addr_lsb
+ #define si_band __si_fields.__sigpoll.si_band
+ #define si_fd __si_fields.__sigpoll.si_fd
+-#define si_timer1 __si_fields.__timer.si_timer1
+-#define si_timer2 __si_fields.__timer.si_timer2
+-#define si_ptr __si_fields.__rt.si_sigval.sival_ptr
+-#define si_int __si_fields.__rt.si_sigval.sival_int
++#define si_timerid __si_fields.__si_common.__first.__timer.si_timerid
++#define si_overrun __si_fields.__si_common.__first.__timer.si_overrun
++#define si_ptr si_value.sival_ptr
++#define si_int si_value.sival_int
+ #define si_call_addr __si_fields.__sigsys.si_call_addr
+ #define si_syscall __si_fields.__sigsys.si_syscall
+ #define si_arch __si_fields.__sigsys.si_arch
+diff --git a/include/sys/socket.h b/include/sys/socket.h
+index 8e8c9e9..d752791 100644
+--- a/include/sys/socket.h
++++ b/include/sys/socket.h
+@@ -203,6 +203,7 @@ struct linger
+ #define SO_SELECT_ERR_QUEUE 45
+ #define SO_BUSY_POLL 46
+ #define SO_MAX_PACING_RATE 47
++#define SO_BPF_EXTENSIONS 48
+
+ #ifndef SOL_SOCKET
+ #define SOL_SOCKET 1
+diff --git a/include/sys/types.h b/include/sys/types.h
+index 27170f6..f00db03 100644
+--- a/include/sys/types.h
++++ b/include/sys/types.h
+@@ -20,11 +20,6 @@ extern "C" {
+ #define __NEED_timer_t
+ #define __NEED_clockid_t
+
+-#define __NEED_int8_t
+-#define __NEED_int16_t
+-#define __NEED_int32_t
+-#define __NEED_int64_t
+-
+ #define __NEED_blkcnt_t
+ #define __NEED_fsblkcnt_t
+ #define __NEED_fsfilcnt_t
+@@ -49,19 +44,22 @@ extern "C" {
+ #define __NEED_pthread_key_t
+ #define __NEED_pthread_once_t
+ #define __NEED_useconds_t
+-#define __NEED_u_int64_t
+
+ #if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
++#define __NEED_int8_t
++#define __NEED_int16_t
++#define __NEED_int32_t
++#define __NEED_int64_t
++#define __NEED_u_int64_t
+ #define __NEED_register_t
+ #endif
+
+ #include <bits/alltypes.h>
+
++#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+ typedef unsigned char u_int8_t;
+ typedef unsigned short u_int16_t;
+ typedef unsigned u_int32_t;
+-
+-#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+ typedef char *caddr_t;
+ typedef unsigned char u_char;
+ typedef unsigned short u_short, ushort;
+@@ -87,5 +85,3 @@ typedef unsigned long long u_quad_t;
+ }
+ #endif
+ #endif
+-
+-
+diff --git a/src/env/__libc_start_main.c b/src/env/__libc_start_main.c
+index 3498afb..c10a3f3 100644
+--- a/src/env/__libc_start_main.c
++++ b/src/env/__libc_start_main.c
+@@ -1,6 +1,7 @@
+ #include <elf.h>
+ #include <poll.h>
+ #include <fcntl.h>
++#include <signal.h>
+ #include "syscall.h"
+ #include "atomic.h"
+ #include "libc.h"
+@@ -48,9 +49,13 @@ void __init_libc(char **envp, char *pn)
+ && !aux[AT_SECURE]) return;
+
+ struct pollfd pfd[3] = { {.fd=0}, {.fd=1}, {.fd=2} };
++#ifdef SYS_poll
+ __syscall(SYS_poll, pfd, 3, 0);
++#else
++ __syscall(SYS_ppoll, pfd, 3, &(struct timespec){0}, 0, _NSIG/8);
++#endif
+ for (i=0; i<3; i++) if (pfd[i].revents&POLLNVAL)
+- if (__syscall(SYS_open, "/dev/null", O_RDWR|O_LARGEFILE)<0)
++ if (__sys_open("/dev/null", O_RDWR)<0)
+ a_crash();
+ libc.secure = 1;
+ }
+diff --git a/src/exit/exit.c b/src/exit/exit.c
+index 353f50b..695bdc0 100644
+--- a/src/exit/exit.c
++++ b/src/exit/exit.c
+@@ -1,8 +1,6 @@
+ #include <stdlib.h>
+ #include <stdint.h>
+ #include "libc.h"
+-#include "atomic.h"
+-#include "syscall.h"
+
+ static void dummy()
+ {
+@@ -21,11 +19,6 @@ extern void (*const __fini_array_end)() __attribute__((weak));
+
+ _Noreturn void exit(int code)
+ {
+- static int lock;
+-
+- /* If more than one thread calls exit, hang until _Exit ends it all */
+- while (a_swap(&lock, 1)) __syscall(SYS_pause);
+-
+ __funcs_on_exit();
+
+ #ifndef SHARED
+diff --git a/src/exit/quick_exit.c b/src/exit/quick_exit.c
+index 1175d80..ada9134 100644
+--- a/src/exit/quick_exit.c
++++ b/src/exit/quick_exit.c
+@@ -1,6 +1,4 @@
+ #include <stdlib.h>
+-#include "syscall.h"
+-#include "atomic.h"
+ #include "libc.h"
+
+ static void dummy() { }
+@@ -8,8 +6,6 @@ weak_alias(dummy, __funcs_on_quick_exit);
+
+ _Noreturn void quick_exit(int code)
+ {
+- static int lock;
+- while (a_swap(&lock, 1)) __syscall(SYS_pause);
+ __funcs_on_quick_exit();
+ _Exit(code);
+ }
+diff --git a/src/fcntl/open.c b/src/fcntl/open.c
+index be44208..0594ed7 100644
+--- a/src/fcntl/open.c
++++ b/src/fcntl/open.c
+@@ -10,7 +10,7 @@ int open(const char *filename, int flags, ...)
+ va_start(ap, flags);
+ mode = va_arg(ap, mode_t);
+ va_end(ap);
+- return syscall_cp(SYS_open, filename, flags|O_LARGEFILE, mode);
++ return sys_open_cp(filename, flags, mode);
+ }
+
+ LFS64(open);
+diff --git a/src/internal/syscall.h b/src/internal/syscall.h
+index 914b0d1..0a2840a 100644
+--- a/src/internal/syscall.h
++++ b/src/internal/syscall.h
+@@ -4,6 +4,10 @@
+ #include <sys/syscall.h>
+ #include "syscall_arch.h"
+
++#ifndef SYSCALL_RLIM_INFINITY
++#define SYSCALL_RLIM_INFINITY (~0ULL)
++#endif
++
+ #ifndef __scc
+ #define __scc(X) ((long) (X))
+ typedef long syscall_arg_t;
+@@ -122,14 +126,26 @@ long __syscall_ret(unsigned long), __syscall(syscall_arg_t, ...),
+
+ #ifdef SYS_stat64
+ #undef SYS_stat
+-#undef SYS_fstat
+-#undef SYS_lstat
+-#undef SYS_statfs
+-#undef SYS_fstatfs
+ #define SYS_stat SYS_stat64
++#endif
++
++#ifdef SYS_fstat64
++#undef SYS_fstat
+ #define SYS_fstat SYS_fstat64
++#endif
++
++#ifdef SYS_lstat64
++#undef SYS_lstat
+ #define SYS_lstat SYS_lstat64
++#endif
++
++#ifdef SYS_statfs64
++#undef SYS_statfs
+ #define SYS_statfs SYS_statfs64
++#endif
++
++#ifdef SYS_fstatfs64
++#undef SYS_fstatfs
+ #define SYS_fstatfs SYS_fstatfs64
+ #endif
+
+@@ -163,6 +179,9 @@ long __syscall_ret(unsigned long), __syscall(syscall_arg_t, ...),
+ #define SYS_fadvise SYS_fadvise64_64
+ #endif
+
++#ifdef SYS_sendfile64
++#undef SYS_sendfile
++#define SYS_sendfile SYS_sendfile64
+ #endif
+
+ /* socketcall calls */
+@@ -187,3 +206,23 @@ long __syscall_ret(unsigned long), __syscall(syscall_arg_t, ...),
+ #define __SC_accept4 18
+ #define __SC_recvmmsg 19
+ #define __SC_sendmmsg 20
++
++#ifdef SYS_open
++#define __sys_open2(x,pn,fl) __syscall2(SYS_open, pn, (fl)|O_LARGEFILE)
++#define __sys_open3(x,pn,fl,mo) __syscall3(SYS_open, pn, (fl)|O_LARGEFILE, mo)
++#define __sys_open_cp2(x,pn,fl) __syscall_cp2(SYS_open, pn, (fl)|O_LARGEFILE)
++#define __sys_open_cp3(x,pn,fl,mo) __syscall_cp3(SYS_open, pn, (fl)|O_LARGEFILE, mo)
++#else
++#define __sys_open2(x,pn,fl) __syscall3(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE)
++#define __sys_open3(x,pn,fl,mo) __syscall4(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE, mo)
++#define __sys_open_cp2(x,pn,fl) __syscall_cp3(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE)
++#define __sys_open_cp3(x,pn,fl,mo) __syscall_cp4(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE, mo)
++#endif
++
++#define __sys_open(...) __SYSCALL_DISP(__sys_open,,__VA_ARGS__)
++#define sys_open(...) __syscall_ret(__sys_open(__VA_ARGS__))
++
++#define __sys_open_cp(...) __SYSCALL_DISP(__sys_open_cp,,__VA_ARGS__)
++#define sys_open_cp(...) __syscall_ret(__sys_open_cp(__VA_ARGS__))
++
++#endif
+diff --git a/src/linux/epoll.c b/src/linux/epoll.c
+index 030786d..deff5b1 100644
+--- a/src/linux/epoll.c
++++ b/src/linux/epoll.c
+@@ -1,15 +1,20 @@
+ #include <sys/epoll.h>
+ #include <signal.h>
++#include <errno.h>
+ #include "syscall.h"
+
+ int epoll_create(int size)
+ {
+- return syscall(SYS_epoll_create, size);
++ return epoll_create1(0);
+ }
+
+ int epoll_create1(int flags)
+ {
+- return syscall(SYS_epoll_create1, flags);
++ int r = __syscall(SYS_epoll_create1, flags);
++#ifdef SYS_epoll_create
++ if (r==-ENOSYS && !flags) r = __syscall(SYS_epoll_create, 1);
++#endif
++ return __syscall_ret(r);
+ }
+
+ int epoll_ctl(int fd, int op, int fd2, struct epoll_event *ev)
+@@ -19,10 +24,14 @@ int epoll_ctl(int fd, int op, int fd2, struct epoll_event *ev)
+
+ int epoll_pwait(int fd, struct epoll_event *ev, int cnt, int to, const sigset_t *sigs)
+ {
+- return syscall(SYS_epoll_pwait, fd, ev, cnt, to, sigs, _NSIG/8);
++ int r = __syscall(SYS_epoll_pwait, fd, ev, cnt, to, sigs, _NSIG/8);
++#ifdef SYS_epoll_wait
++ if (r==-ENOSYS && !sigs) r = __syscall(SYS_epoll_wait, fd, ev, cnt, to);
++#endif
++ return __syscall_ret(r);
+ }
+
+ int epoll_wait(int fd, struct epoll_event *ev, int cnt, int to)
+ {
+- return syscall(SYS_epoll_wait, fd, ev, cnt, to);
++ return epoll_pwait(fd, ev, cnt, to, 0);
+ }
+diff --git a/src/linux/eventfd.c b/src/linux/eventfd.c
+index 5306648..68e489c 100644
+--- a/src/linux/eventfd.c
++++ b/src/linux/eventfd.c
+@@ -1,10 +1,15 @@
+ #include <sys/eventfd.h>
+ #include <unistd.h>
++#include <errno.h>
+ #include "syscall.h"
+
+ int eventfd(unsigned int count, int flags)
+ {
+- return syscall(flags ? SYS_eventfd2 : SYS_eventfd, count, flags);
++ int r = __syscall(SYS_eventfd2, count, flags);
++#ifdef SYS_eventfd
++ if (r==-ENOSYS && !flags) r = __syscall(SYS_eventfd, count);
++#endif
++ return __syscall_ret(r);
+ }
+
+ int eventfd_read(int fd, eventfd_t *value)
+diff --git a/src/linux/inotify.c b/src/linux/inotify.c
+index a417c89..df5e48b 100644
+--- a/src/linux/inotify.c
++++ b/src/linux/inotify.c
+@@ -1,13 +1,18 @@
+ #include <sys/inotify.h>
++#include <errno.h>
+ #include "syscall.h"
+
+ int inotify_init()
+ {
+- return syscall(SYS_inotify_init);
++ return inotify_init1(0);
+ }
+ int inotify_init1(int flags)
+ {
+- return syscall(SYS_inotify_init1, flags);
++ int r = __syscall(SYS_inotify_init1, flags);
++#ifdef SYS_inotify_init
++ if (r==-ENOSYS && !flags) r = __syscall(SYS_inotify_init);
++#endif
++ return __syscall_ret(r);
+ }
+
+ int inotify_add_watch(int fd, const char *pathname, uint32_t mask)
+diff --git a/src/linux/prlimit.c b/src/linux/prlimit.c
+index d1639cc..0fe28e1 100644
+--- a/src/linux/prlimit.c
++++ b/src/linux/prlimit.c
+@@ -3,9 +3,24 @@
+ #include "syscall.h"
+ #include "libc.h"
+
++#define FIX(x) do{ if ((x)>=SYSCALL_RLIM_INFINITY) (x)=RLIM_INFINITY; }while(0)
++
+ int prlimit(pid_t pid, int resource, const struct rlimit *new_limit, struct rlimit *old_limit)
+ {
+- return syscall(SYS_prlimit64, pid, resource, new_limit, old_limit);
++ struct rlimit tmp;
++ int r;
++ if (new_limit && SYSCALL_RLIM_INFINITY != RLIM_INFINITY) {
++ tmp = *new_limit;
++ FIX(tmp.rlim_cur);
++ FIX(tmp.rlim_max);
++ new_limit = &tmp;
++ }
++ r = syscall(SYS_prlimit64, pid, resource, new_limit, old_limit);
++ if (!r && old_limit && SYSCALL_RLIM_INFINITY != RLIM_INFINITY) {
++ FIX(old_limit->rlim_cur);
++ FIX(old_limit->rlim_max);
++ }
++ return r;
+ }
+
+ #undef prlimit64
+diff --git a/src/linux/signalfd.c b/src/linux/signalfd.c
+index da6bced..4bf4332 100644
+--- a/src/linux/signalfd.c
++++ b/src/linux/signalfd.c
+@@ -7,6 +7,7 @@
+ int signalfd(int fd, const sigset_t *sigs, int flags)
+ {
+ int ret = __syscall(SYS_signalfd4, fd, sigs, _NSIG/8, flags);
++#ifdef SYS_signalfd
+ if (ret != -ENOSYS) return __syscall_ret(ret);
+ ret = __syscall(SYS_signalfd, fd, sigs, _NSIG/8);
+ if (ret >= 0) {
+@@ -15,5 +16,6 @@ int signalfd(int fd, const sigset_t *sigs, int flags)
+ if (flags & SFD_NONBLOCK)
+ __syscall(SYS_fcntl, ret, F_SETFL, O_NONBLOCK);
+ }
++#endif
+ return __syscall_ret(ret);
+ }
+diff --git a/src/linux/utimes.c b/src/linux/utimes.c
+index 70c0695..b814c88 100644
+--- a/src/linux/utimes.c
++++ b/src/linux/utimes.c
+@@ -1,7 +1,10 @@
+ #include <sys/time.h>
++#include "fcntl.h"
+ #include "syscall.h"
+
++int __futimesat(int, const char *, const struct timeval [2]);
++
+ int utimes(const char *path, const struct timeval times[2])
+ {
+- return syscall(SYS_utimes, path, times);
++ return __futimesat(AT_FDCWD, path, times);
+ }
+diff --git a/src/misc/getrlimit.c b/src/misc/getrlimit.c
+index b7bbd06..b073677 100644
+--- a/src/misc/getrlimit.c
++++ b/src/misc/getrlimit.c
+@@ -3,16 +3,24 @@
+ #include "syscall.h"
+ #include "libc.h"
+
++#define FIX(x) do{ if ((x)>=SYSCALL_RLIM_INFINITY) (x)=RLIM_INFINITY; }while(0)
++
+ int getrlimit(int resource, struct rlimit *rlim)
+ {
+ unsigned long k_rlim[2];
+ int ret = syscall(SYS_prlimit64, 0, resource, 0, rlim);
++ if (!ret) {
++ FIX(rlim->rlim_cur);
++ FIX(rlim->rlim_max);
++ }
+ if (!ret || errno != ENOSYS)
+ return ret;
+ if (syscall(SYS_getrlimit, resource, k_rlim) < 0)
+ return -1;
+ rlim->rlim_cur = k_rlim[0] == -1UL ? RLIM_INFINITY : k_rlim[0];
+ rlim->rlim_max = k_rlim[1] == -1UL ? RLIM_INFINITY : k_rlim[1];
++ FIX(rlim->rlim_cur);
++ FIX(rlim->rlim_max);
+ return 0;
+ }
+
+diff --git a/src/misc/realpath.c b/src/misc/realpath.c
+index 4cc7e7d..88c849c 100644
+--- a/src/misc/realpath.c
++++ b/src/misc/realpath.c
+@@ -22,7 +22,7 @@ char *realpath(const char *restrict filename, char *restrict resolved)
+ return 0;
+ }
+
+- fd = syscall(SYS_open, filename, O_PATH|O_NONBLOCK|O_CLOEXEC|O_LARGEFILE);
++ fd = sys_open(filename, O_PATH|O_NONBLOCK|O_CLOEXEC);
+ if (fd < 0) return 0;
+ __procfdname(buf, fd);
+
+diff --git a/src/misc/setrlimit.c b/src/misc/setrlimit.c
+index ddc13e9..8a1b8cc 100644
+--- a/src/misc/setrlimit.c
++++ b/src/misc/setrlimit.c
+@@ -4,14 +4,22 @@
+ #include "libc.h"
+
+ #define MIN(a, b) ((a)<(b) ? (a) : (b))
++#define FIX(x) do{ if ((x)>=SYSCALL_RLIM_INFINITY) (x)=RLIM_INFINITY; }while(0)
+
+ int __setrlimit(int resource, const struct rlimit *rlim)
+ {
+ unsigned long k_rlim[2];
++ struct rlimit tmp;
++ if (SYSCALL_RLIM_INFINITY != RLIM_INFINITY) {
++ tmp = *rlim;
++ FIX(tmp.rlim_cur);
++ FIX(tmp.rlim_max);
++ rlim = &tmp;
++ }
+ int ret = __syscall(SYS_prlimit64, 0, resource, rlim, 0);
+ if (ret != -ENOSYS) return ret;
+- k_rlim[0] = MIN(rlim->rlim_cur, -1UL);
+- k_rlim[1] = MIN(rlim->rlim_max, -1UL);
++ k_rlim[0] = MIN(rlim->rlim_cur, MIN(-1UL, SYSCALL_RLIM_INFINITY));
++ k_rlim[1] = MIN(rlim->rlim_max, MIN(-1UL, SYSCALL_RLIM_INFINITY));
+ return __syscall(SYS_setrlimit, resource, k_rlim);
+ }
+
+diff --git a/src/network/__dns.c b/src/network/__dns.c
+deleted file mode 100644
+index 97d8031..0000000
+--- a/src/network/__dns.c
++++ /dev/null
+@@ -1,282 +0,0 @@
+-#include <stdint.h>
+-#include <netdb.h>
+-#include <stdio.h>
+-#include <fcntl.h>
+-#include <limits.h>
+-#include <string.h>
+-#include <sys/socket.h>
+-#include <poll.h>
+-#include <netinet/in.h>
+-#include <time.h>
+-#include <ctype.h>
+-#include <unistd.h>
+-#include <pthread.h>
+-#include <errno.h>
+-#include "__dns.h"
+-#include "stdio_impl.h"
+-
+-#define TIMEOUT 5
+-#define RETRY 1000
+-#define PACKET_MAX 512
+-#define PTR_MAX (64 + sizeof ".in-addr.arpa")
+-
+-static void cleanup(void *p)
+-{
+- close((intptr_t)p);
+-}
+-
+-int __dns_doqueries(unsigned char *dest, const char *name, int *rr, int rrcnt)
+-{
+- time_t t0 = time(0);
+- int fd;
+- FILE *f, _f;
+- unsigned char _buf[256];
+- char line[64], *s, *z;
+- union {
+- struct sockaddr_in sin;
+- struct sockaddr_in6 sin6;
+- } sa = {0}, ns[3] = {{0}};
+- socklen_t sl = sizeof sa.sin;
+- int nns = 0;
+- int family = AF_INET;
+- unsigned char q[280] = "", *r = dest;
+- int ql;
+- int rlen;
+- int got = 0, failed = 0;
+- int errcode = EAI_AGAIN;
+- int i, j;
+- struct timespec ts;
+- struct pollfd pfd;
+- int id;
+- int cs;
+-
+- pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
+-
+- /* Construct query template - RR and ID will be filled later */
+- if (strlen(name)-1 >= 254U) return EAI_NONAME;
+- q[2] = q[5] = 1;
+- strcpy((char *)q+13, name);
+- for (i=13; q[i]; i=j+1) {
+- for (j=i; q[j] && q[j] != '.'; j++);
+- if (j-i-1u > 62u) return EAI_NONAME;
+- q[i-1] = j-i;
+- }
+- q[i+3] = 1;
+- ql = i+4;
+-
+- /* Make a reasonably unpredictable id */
+- clock_gettime(CLOCK_REALTIME, &ts);
+- id = ts.tv_nsec + ts.tv_nsec/65536UL & 0xffff;
+-
+- /* Get nameservers from resolv.conf, fallback to localhost */
+- f = __fopen_rb_ca("/etc/resolv.conf", &_f, _buf, sizeof _buf);
+- if (f) for (nns=0; nns<3 && fgets(line, sizeof line, f); ) {
+- if (strncmp(line, "nameserver", 10) || !isspace(line[10]))
+- continue;
+- for (s=line+11; isspace(*s); s++);
+- for (z=s; *z && !isspace(*z); z++);
+- *z=0;
+- if (__ipparse(ns+nns, AF_UNSPEC, s) < 0) continue;
+- ns[nns].sin.sin_port = htons(53);
+- if (ns[nns++].sin.sin_family == AF_INET6) {
+- family = AF_INET6;
+- sl = sizeof sa.sin6;
+- }
+- }
+- if (f) __fclose_ca(f);
+- if (!nns) {
+- ns[0].sin.sin_family = family = AF_INET;
+- ns[0].sin.sin_port = htons(53);
+- ns[0].sin.sin_addr.s_addr = htonl(0x7f000001);
+- nns=1;
+- sl = sizeof sa.sin;
+- }
+-
+- /* Get local address and open/bind a socket */
+- sa.sin.sin_family = family;
+- fd = socket(family, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+-
+- /* Handle case where system lacks IPv6 support */
+- if (fd < 0 && errno == EAFNOSUPPORT) {
+- if (family != AF_INET6) return EAI_SYSTEM;
+- fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+- family = AF_INET;
+- }
+- if (fd < 0) return EAI_SYSTEM;
+-
+- /* Convert any IPv4 addresses in a mixed environment to v4-mapped */
+- if (family == AF_INET6) {
+- setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){0}, sizeof 0);
+- for (i=0; i<nns; i++) {
+- if (ns[i].sin.sin_family != AF_INET) continue;
+- memcpy(ns[i].sin6.sin6_addr.s6_addr+12,
+- &ns[i].sin.sin_addr, 4);
+- memcpy(ns[i].sin6.sin6_addr.s6_addr,
+- "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
+- ns[i].sin6.sin6_family = AF_INET6;
+- ns[i].sin6.sin6_flowinfo = 0;
+- ns[i].sin6.sin6_scope_id = 0;
+- }
+- }
+-
+- pthread_cleanup_push(cleanup, (void *)(intptr_t)fd);
+- pthread_setcancelstate(cs, 0);
+-
+- if (bind(fd, (void *)&sa, sl) < 0) {
+- errcode = EAI_SYSTEM;
+- goto out;
+- }
+-
+- pfd.fd = fd;
+- pfd.events = POLLIN;
+-
+- /* Loop until we timeout; break early on success */
+- for (; time(0)-t0 < TIMEOUT; ) {
+-
+- /* Query all configured namservers in parallel */
+- for (i=0; i<rrcnt; i++) if (rr[i]) for (j=0; j<nns; j++) {
+- q[0] = id+i >> 8;
+- q[1] = id+i;
+- q[ql-3] = rr[i];
+- sendto(fd, q, ql, MSG_NOSIGNAL, (void *)&ns[j], sl);
+- }
+-
+- /* Wait for a response, or until time to retry */
+- if (poll(&pfd, 1, RETRY) <= 0) continue;
+-
+- /* Process any and all replies */
+- while (got+failed < rrcnt && (rlen = recvfrom(fd, r, 512, 0,
+- (void *)&sa, (socklen_t[1]){sl})) >= 2)
+- {
+- /* Ignore replies from addresses we didn't send to */
+- for (i=0; i<nns; i++) if (!memcmp(ns+i, &sa, sl)) break;
+- if (i==nns) continue;
+-
+- /* Compute index of the query from id */
+- i = r[0]*256+r[1] - id & 0xffff;
+- if ((unsigned)i >= rrcnt || !rr[i]) continue;
+-
+- /* Interpret the result code */
+- switch (r[3] & 15) {
+- case 0:
+- got++;
+- break;
+- case 3:
+- if (1) errcode = EAI_NONAME; else
+- default:
+- errcode = EAI_FAIL;
+- failed++;
+- }
+-
+- /* Mark this record as answered */
+- rr[i] = 0;
+- r += 512;
+- }
+-
+- /* Check to see if we have answers to all queries */
+- if (got+failed == rrcnt) break;
+- }
+-out:
+- pthread_cleanup_pop(1);
+-
+- /* Return the number of results, or an error code if none */
+- if (got) return got;
+- return errcode;
+-}
+-
+-static void mkptr4(char *s, const unsigned char *ip)
+-{
+- sprintf(s, "%d.%d.%d.%d.in-addr.arpa",
+- ip[3], ip[2], ip[1], ip[0]);
+-}
+-
+-static void mkptr6(char *s, const unsigned char *ip)
+-{
+- static const char xdigits[] = "0123456789abcdef";
+- int i;
+- for (i=15; i>=0; i--) {
+- *s++ = xdigits[ip[i]&15]; *s++ = '.';
+- *s++ = xdigits[ip[i]>>4]; *s++ = '.';
+- }
+- strcpy(s, "ip6.arpa");
+-}
+-
+-int __dns_query(unsigned char *r, const void *a, int family, int ptr)
+-{
+- char buf[PTR_MAX];
+- int rr[2], rrcnt = 1;
+-
+- if (ptr) {
+- if (family == AF_INET6) mkptr6(buf, a);
+- else mkptr4(buf, a);
+- rr[0] = RR_PTR;
+- a = buf;
+- } else if (family == AF_INET6) {
+- rr[0] = RR_AAAA;
+- } else {
+- rr[0] = RR_A;
+- if (family != AF_INET) rr[rrcnt++] = RR_AAAA;
+- }
+-
+- return __dns_doqueries(r, a, rr, rrcnt);
+-}
+-
+-int __dn_expand(const unsigned char *, const unsigned char *, const unsigned char *, char *, int);
+-
+-int __dns_get_rr(void *dest, size_t stride, size_t maxlen, size_t limit, const unsigned char *r, int rr, int dec)
+-{
+- int qdcount, ancount;
+- const unsigned char *p;
+- char tmp[256];
+- int found = 0;
+- int len;
+-
+- if ((r[3]&15)) return 0;
+- p = r+12;
+- qdcount = r[4]*256 + r[5];
+- ancount = r[6]*256 + r[7];
+- if (qdcount+ancount > 64) return -1;
+- while (qdcount--) {
+- while (p-r < 512 && *p-1U < 127) p++;
+- if (*p>193 || (*p==193 && p[1]>254) || p>r+506)
+- return -1;
+- p += 5 + !!*p;
+- }
+- while (ancount--) {
+- while (p-r < 512 && *p-1U < 127) p++;
+- if (*p>193 || (*p==193 && p[1]>254) || p>r+506)
+- return -1;
+- p += 1 + !!*p;
+- len = p[8]*256 + p[9];
+- if (p+len > r+512) return -1;
+- if (p[1]==rr && len <= maxlen) {
+- if (dec && __dn_expand(r, r+512, p+10, tmp, sizeof tmp)<0)
+- return -1;
+- if (dest && limit) {
+- if (dec) strcpy(dest, tmp);
+- else memcpy(dest, p+10, len);
+- dest = (char *)dest + stride;
+- limit--;
+- }
+- found++;
+- }
+- p += 10 + len;
+- }
+- return found;
+-}
+-
+-int __dns_count_addrs(const unsigned char *r, int cnt)
+-{
+- int found=0, res, i;
+- static const int p[2][2] = { { 4, RR_A }, { 16, RR_AAAA } };
+-
+- while (cnt--) {
+- for (i=0; i<2; i++) {
+- res = __dns_get_rr(0, 0, p[i][0], -1, r, p[i][1], 0);
+- if (res < 0) return res;
+- found += res;
+- }
+- r += 512;
+- }
+- return found;
+-}
+diff --git a/src/network/__dns.h b/src/network/__dns.h
+deleted file mode 100644
+index 9a3f740..0000000
+--- a/src/network/__dns.h
++++ /dev/null
+@@ -1,14 +0,0 @@
+-#include <stddef.h>
+-
+-#define RR_A 1
+-#define RR_CNAME 5
+-#define RR_PTR 12
+-#define RR_AAAA 28
+-
+-int __dns_count_addrs(const unsigned char *, int);
+-int __dns_get_rr(void *, size_t, size_t, size_t, const unsigned char *, int, int);
+-
+-int __dns_query(unsigned char *, const void *, int, int);
+-int __ipparse(void *, int, const char *);
+-
+-int __dns_doqueries(unsigned char *, const char *, int *, int);
+diff --git a/src/network/__ipparse.c b/src/network/__ipparse.c
+deleted file mode 100644
+index 79f3b8c..0000000
+--- a/src/network/__ipparse.c
++++ /dev/null
+@@ -1,51 +0,0 @@
+-#include <stdlib.h>
+-#include <ctype.h>
+-#include <sys/socket.h>
+-#include <netinet/in.h>
+-#include <arpa/inet.h>
+-#include "__dns.h"
+-
+-int __ipparse(void *dest, int family, const char *s0)
+-{
+- const char *s = s0;
+- unsigned char *d = dest;
+- unsigned long a[16] = { 0 };
+- char *z;
+- int i;
+-
+- if (family == AF_INET6) goto not_v4;
+-
+- for (i=0; i<4; i++) {
+- a[i] = strtoul(s, &z, 0);
+- if (z==s || (*z && *z != '.') || !isdigit(*s)) {
+- if (family == AF_INET) return -1;
+- goto not_v4;
+- }
+- if (!*z) break;
+- s=z+1;
+- }
+- if (i==4) return -1;
+- switch (i) {
+- case 0:
+- a[1] = a[0] & 0xffffff;
+- a[0] >>= 24;
+- case 1:
+- a[2] = a[1] & 0xffff;
+- a[1] >>= 16;
+- case 2:
+- a[3] = a[2] & 0xff;
+- a[2] >>= 8;
+- }
+- ((struct sockaddr_in *)d)->sin_family = AF_INET;
+- d = (void *)&((struct sockaddr_in *)d)->sin_addr;
+- for (i=0; i<4; i++) {
+- if (a[i] > 255) return -1;
+- d[i] = a[i];
+- }
+- return 0;
+-
+-not_v4:
+- s = s0;
+- ((struct sockaddr_in6 *)d)->sin6_family = AF_INET6;
+- return inet_pton(AF_INET6, s, (void *)&((struct sockaddr_in6 *)d)->sin6_addr) <= 0 ? -1 : 0;
+-}
+diff --git a/src/network/dns_parse.c b/src/network/dns_parse.c
+new file mode 100644
+index 0000000..aa0d39f
+--- /dev/null
++++ b/src/network/dns_parse.c
+@@ -0,0 +1,31 @@
++#include <string.h>
++
++int __dns_parse(const unsigned char *r, int rlen, int (*callback)(void *, int, const void *, int, const void *), void *ctx)
++{
++ int qdcount, ancount;
++ const unsigned char *p;
++ int len;
++
++ if ((r[3]&15)) return 0;
++ p = r+12;
++ qdcount = r[4]*256 + r[5];
++ ancount = r[6]*256 + r[7];
++ if (qdcount+ancount > 64) return -1;
++ while (qdcount--) {
++ while (p-r < rlen && *p-1U < 127) p++;
++ if (*p>193 || (*p==193 && p[1]>254) || p>r+506)
++ return -1;
++ p += 5 + !!*p;
++ }
++ while (ancount--) {
++ while (p-r < rlen && *p-1U < 127) p++;
++ if (*p>193 || (*p==193 && p[1]>254) || p>r+506)
++ return -1;
++ p += 1 + !!*p;
++ len = p[8]*256 + p[9];
++ if (p+len > r+rlen) return -1;
++ if (callback(ctx, p[1], p+10, len, r) < 0) return -1;
++ p += 10 + len;
++ }
++ return 0;
++}
+diff --git a/src/network/getaddrinfo.c b/src/network/getaddrinfo.c
+index 5d45be7..70b6cfd 100644
+--- a/src/network/getaddrinfo.c
++++ b/src/network/getaddrinfo.c
+@@ -1,249 +1,115 @@
+ #include <stdlib.h>
+-#include <stdio.h>
+-#include <netdb.h>
+-#include <netinet/in.h>
+ #include <sys/socket.h>
+-#include <unistd.h>
++#include <netinet/in.h>
++#include <netdb.h>
+ #include <string.h>
+-#include <ctype.h>
+-#include "__dns.h"
+-#include "stdio_impl.h"
+-
+-static int is_valid(const char *host)
+-{
+- const unsigned char *s;
+- if (strlen(host)-1 > 254 || mbstowcs(0, host, 0) > 255) return 0;
+- for (s=(void *)host; *s>=0x80 || *s=='.' || *s=='-' || isalnum(*s); s++);
+- return !*s;
+-}
+-
+-#if 0
+-static int have_af(int family)
+-{
+- struct sockaddr_in6 sin6 = { .sin6_family = family };
+- socklen_t sl = family == AF_INET
+- ? sizeof(struct sockaddr_in)
+- : sizeof(struct sockaddr_in6);
+- int sock = socket(family, SOCK_STREAM, 0);
+- int have = !bind(sock, (void *)&sin6, sl);
+- close(sock);
+- return have;
+-}
+-#endif
+-
+-union sa {
+- struct sockaddr_in sin;
+- struct sockaddr_in6 sin6;
+-};
+-
+-struct aibuf {
+- struct addrinfo ai;
+- union sa sa;
+-};
+-
+-/* Extra slots needed for storing canonical name */
+-#define EXTRA ((256+sizeof(struct aibuf)-1)/sizeof(struct aibuf))
++#include "lookup.h"
+
+ int getaddrinfo(const char *restrict host, const char *restrict serv, const struct addrinfo *restrict hint, struct addrinfo **restrict res)
+ {
+- int flags = hint ? hint->ai_flags : 0;
+- int family = hint ? hint->ai_family : AF_UNSPEC;
+- int type = hint ? hint->ai_socktype : 0;
+- int proto = hint ? hint->ai_protocol : 0;
+- unsigned long port = 0;
+- struct aibuf *buf;
+- union sa sa = {{0}};
+- unsigned char reply[1024];
+- int i, j;
+- char line[512];
+- FILE *f, _f;
+- unsigned char _buf[1024];
+- char *z;
+- int result;
+- int cnt;
+-
+- if (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC)
+- return EAI_FAMILY;
+-
+- if (host && strlen(host)>255) return EAI_NONAME;
+- if (serv && strlen(serv)>32) return EAI_SERVICE;
+-
+- if (type && !proto)
+- proto = type==SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP;
+- if (!type && proto)
+- type = proto==IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM;
+-
+- if (serv) {
+- if (!*serv) return EAI_SERVICE;
+- port = strtoul(serv, &z, 10);
+- if (*z) {
+- size_t servlen = strlen(serv);
+- char *end = line;
+-
+- if (flags & AI_NUMERICSERV) return EAI_SERVICE;
++ struct service ports[MAXSERVS];
++ struct address addrs[MAXADDRS];
++ char canon[256], *outcanon;
++ int nservs, naddrs, nais, canon_len, i, j, k;
++ int family = AF_UNSPEC, flags = 0, proto = 0;
++ struct aibuf {
++ struct addrinfo ai;
++ union sa {
++ struct sockaddr_in sin;
++ struct sockaddr_in6 sin6;
++ } sa;
++ } *out;
++
++ if (hint) {
++ family = hint->ai_family;
++ flags = hint->ai_flags;
++ proto = hint->ai_protocol;
++
++ const int mask = AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST |
++ AI_V4MAPPED | AI_ALL | AI_ADDRCONFIG | AI_NUMERICSERV;
++ if ((flags & mask) != flags)
++ return EAI_BADFLAGS;
++
++ switch (family) {
++ case AF_INET:
++ case AF_INET6:
++ case AF_UNSPEC:
++ break;
++ default:
++ return EAI_FAMILY;
++ }
+
+- f = __fopen_rb_ca("/etc/services", &_f, _buf, sizeof _buf);
+- if (!f) return EAI_SERVICE;
+- while (fgets(line, sizeof line, f)) {
+- if (strncmp(line, serv, servlen) || !isspace(line[servlen]))
+- continue;
+- port = strtoul(line+servlen, &end, 10);
+- if (strncmp(end, proto==IPPROTO_UDP ? "/udp" : "/tcp", 4))
+- continue;
++ switch (hint->ai_socktype) {
++ case SOCK_STREAM:
++ switch (proto) {
++ case 0:
++ proto = IPPROTO_TCP;
++ case IPPROTO_TCP:
+ break;
++ default:
++ return EAI_SERVICE;
+ }
+- __fclose_ca(f);
+- if (feof(f)) return EAI_SERVICE;
+- }
+- if (port > 65535) return EAI_SERVICE;
+- port = htons(port);
+- }
+-
+- if (!host) {
+- if (family == AF_UNSPEC) {
+- cnt = 2; family = AF_INET;
+- } else {
+- cnt = 1;
+- }
+- buf = calloc(sizeof *buf, cnt);
+- if (!buf) return EAI_MEMORY;
+- for (i=0; i<cnt; i++) {
+- if (i) family = AF_INET6;
+- buf[i].ai.ai_protocol = proto;
+- buf[i].ai.ai_socktype = type;
+- buf[i].ai.ai_addr = (void *)&buf[i].sa;
+- buf[i].ai.ai_addrlen = family==AF_INET6
+- ? sizeof sa.sin6 : sizeof sa.sin;
+- buf[i].ai.ai_family = family;
+- buf[i].sa.sin.sin_family = family;
+- buf[i].sa.sin.sin_port = port;
+- if (i+1<cnt) buf[i].ai.ai_next = &buf[i+1].ai;
+- if (!(flags & AI_PASSIVE)) {
+- if (family == AF_INET) {
+- 0[(uint8_t*)&buf[i].sa.sin.sin_addr.s_addr]=127;
+- 3[(uint8_t*)&buf[i].sa.sin.sin_addr.s_addr]=1;
+- } else buf[i].sa.sin6.sin6_addr.s6_addr[15] = 1;
++ break;
++ case SOCK_DGRAM:
++ switch (proto) {
++ case 0:
++ proto = IPPROTO_UDP;
++ case IPPROTO_UDP:
++ break;
++ default:
++ return EAI_SERVICE;
+ }
++ case 0:
++ break;
++ default:
++ return EAI_SOCKTYPE;
+ }
+- *res = &buf->ai;
+- return 0;
+- }
+-
+- if (!*host) return EAI_NONAME;
+-
+- /* Try as a numeric address */
+- if (__ipparse(&sa, family, host) >= 0) {
+- buf = calloc(sizeof *buf, 1+EXTRA);
+- if (!buf) return EAI_MEMORY;
+- family = sa.sin.sin_family;
+- buf->ai.ai_protocol = proto;
+- buf->ai.ai_socktype = type;
+- buf->ai.ai_addr = (void *)&buf->sa;
+- buf->ai.ai_addrlen = family==AF_INET6 ? sizeof sa.sin6 : sizeof sa.sin;
+- buf->ai.ai_family = family;
+- buf->ai.ai_canonname = (char *)host;
+- buf->sa = sa;
+- buf->sa.sin.sin_port = port;
+- *res = &buf->ai;
+- return 0;
+ }
+
+- if (flags & AI_NUMERICHOST) return EAI_NONAME;
++ nservs = __lookup_serv(ports, serv, proto, flags);
++ if (nservs < 0) return nservs;
+
+- f = __fopen_rb_ca("/etc/hosts", &_f, _buf, sizeof _buf);
+- if (f) while (fgets(line, sizeof line, f)) {
+- char *p;
+- size_t l = strlen(host);
++ naddrs = __lookup_name(addrs, canon, host, family, flags);
++ if (naddrs < 0) return naddrs;
+
+- if ((p=strchr(line, '#'))) *p++='\n', *p=0;
+- for(p=line+1; (p=strstr(p, host)) &&
+- (!isspace(p[-1]) || !isspace(p[l])); p++);
+- if (!p) continue;
+- __fclose_ca(f);
+-
+- /* Isolate IP address to parse */
+- for (p=line; *p && !isspace(*p); p++);
+- *p++ = 0;
+- if (__ipparse(&sa, family, line) < 0) return EAI_NONAME;
+-
+- /* Allocate and fill result buffer */
+- buf = calloc(sizeof *buf, 1+EXTRA);
+- if (!buf) return EAI_MEMORY;
+- family = sa.sin.sin_family;
+- buf->ai.ai_protocol = proto;
+- buf->ai.ai_socktype = type;
+- buf->ai.ai_addr = (void *)&buf->sa;
+- buf->ai.ai_addrlen = family==AF_INET6 ? sizeof sa.sin6 : sizeof sa.sin;
+- buf->ai.ai_family = family;
+- buf->sa = sa;
+- buf->sa.sin.sin_port = port;
+-
+- /* Extract first name as canonical name */
+- for (; *p && isspace(*p); p++);
+- buf->ai.ai_canonname = (void *)(buf+1);
+- snprintf(buf->ai.ai_canonname, 256, "%s", p);
+- for (p=buf->ai.ai_canonname; *p && !isspace(*p); p++);
+- *p = 0;
+- if (!is_valid(buf->ai.ai_canonname))
+- buf->ai.ai_canonname = 0;
+-
+- *res = &buf->ai;
+- return 0;
+- }
+- if (f) __fclose_ca(f);
++ nais = nservs * naddrs;
++ canon_len = strlen(canon);
++ out = calloc(1, nais * sizeof(*out) + canon_len + 1);
++ if (!out) return EAI_MEMORY;
+
+-#if 0
+- f = __fopen_rb_ca("/etc/resolv.conf", &_f, _buf, sizeof _buf);
+- if (f) while (fgets(line, sizeof line, f)) {
+- if (!isspace(line[10]) || (strncmp(line, "search", 6)
+- && strncmp(line, "domain", 6))) continue;
++ if (canon_len) {
++ outcanon = (void *)&out[nais];
++ memcpy(outcanon, canon, canon_len+1);
++ } else {
++ outcanon = 0;
+ }
+- if (f) __fclose_ca(f);
+-#endif
+
+- /* Perform one or more DNS queries for host */
+- memset(reply, 0, sizeof reply);
+- result = __dns_query(reply, host, family, 0);
+- if (result < 0) return result;
+-
+- cnt = __dns_count_addrs(reply, result);
+- if (cnt <= 0) return EAI_NONAME;
+-
+- buf = calloc(sizeof *buf, cnt+EXTRA);
+- if (!buf) return EAI_MEMORY;
+-
+- i = 0;
+- if (family != AF_INET6) {
+- j = __dns_get_rr(&buf[i].sa.sin.sin_addr, sizeof *buf, 4, cnt-i, reply, RR_A, 0);
+- while (j--) buf[i++].sa.sin.sin_family = AF_INET;
+- }
+- if (family != AF_INET) {
+- j = __dns_get_rr(&buf[i].sa.sin6.sin6_addr, sizeof *buf, 16, cnt-i, reply, RR_AAAA, 0);
+- while (j--) buf[i++].sa.sin.sin_family = AF_INET6;
+- }
+- if (result>1) {
+- j = __dns_get_rr(&buf[i].sa.sin.sin_addr, sizeof *buf, 4, cnt-i, reply+512, RR_A, 0);
+- while (j--) buf[i++].sa.sin.sin_family = AF_INET;
+- j = __dns_get_rr(&buf[i].sa.sin6.sin6_addr, sizeof *buf, 16, cnt-i, reply+512, RR_AAAA, 0);
+- while (j--) buf[i++].sa.sin.sin_family = AF_INET6;
+- }
+-
+- if (__dns_get_rr((void *)&buf[cnt], 0, 256, 1, reply, RR_CNAME, 1) <= 0)
+- strcpy((void *)&buf[cnt], host);
+-
+- for (i=0; i<cnt; i++) {
+- buf[i].ai.ai_protocol = proto;
+- buf[i].ai.ai_socktype = type;
+- buf[i].ai.ai_addr = (void *)&buf[i].sa;
+- buf[i].ai.ai_addrlen = buf[i].sa.sin.sin_family==AF_INET6
+- ? sizeof sa.sin6 : sizeof sa.sin;
+- buf[i].ai.ai_family = buf[i].sa.sin.sin_family;
+- buf[i].sa.sin.sin_port = port;
+- buf[i].ai.ai_next = &buf[i+1].ai;
+- buf[i].ai.ai_canonname = (void *)&buf[cnt];
++ for (k=i=0; i<naddrs; i++) for (j=0; j<nservs; j++, k++) {
++ out[k].ai = (struct addrinfo){
++ .ai_family = addrs[i].family,
++ .ai_socktype = ports[j].proto == IPPROTO_TCP
++ ? SOCK_STREAM : SOCK_DGRAM,
++ .ai_protocol = ports[j].proto,
++ .ai_addrlen = addrs[i].family == AF_INET
++ ? sizeof(struct sockaddr_in)
++ : sizeof(struct sockaddr_in6),
++ .ai_addr = (void *)&out[k].sa,
++ .ai_canonname = outcanon,
++ .ai_next = &out[k+1].ai };
++ switch (addrs[i].family) {
++ case AF_INET:
++ out[k].sa.sin.sin_family = AF_INET;
++ out[k].sa.sin.sin_port = htons(ports[j].port);
++ memcpy(&out[k].sa.sin.sin_addr, &addrs[i].addr, 4);
++ break;
++ case AF_INET6:
++ out[k].sa.sin6.sin6_family = AF_INET6;
++ out[k].sa.sin6.sin6_port = htons(ports[j].port);
++ memcpy(&out[k].sa.sin6.sin6_addr, &addrs[i].addr, 16);
++ break;
++ }
+ }
+- buf[cnt-1].ai.ai_next = 0;
+- *res = &buf->ai;
+-
++ out[nais-1].ai.ai_next = 0;
++ *res = &out->ai;
+ return 0;
+ }
+diff --git a/src/network/gethostbyname2_r.c b/src/network/gethostbyname2_r.c
+index 27eb080..aa8b0a9 100644
+--- a/src/network/gethostbyname2_r.c
++++ b/src/network/gethostbyname2_r.c
+@@ -6,41 +6,31 @@
+ #include <netinet/in.h>
+ #include <errno.h>
+ #include <stdint.h>
++#include "lookup.h"
+
+ int gethostbyname2_r(const char *name, int af,
+ struct hostent *h, char *buf, size_t buflen,
+ struct hostent **res, int *err)
+ {
+- struct addrinfo hint = {
+- .ai_family = af==AF_INET6 ? af : AF_INET,
+- .ai_flags = AI_CANONNAME
+- };
+- struct addrinfo *ai, *p;
+- int i;
+- size_t need;
+- const char *canon;
++ struct address addrs[MAXADDRS];
++ char canon[256];
++ int i, cnt;
++ size_t align, need;
+
+- af = hint.ai_family;
+-
+- /* Align buffer */
+- i = (uintptr_t)buf & sizeof(char *)-1;
+- if (i) {
+- if (buflen < sizeof(char *)-i) return ERANGE;
+- buf += sizeof(char *)-i;
+- buflen -= sizeof(char *)-i;
+- }
+-
+- switch (getaddrinfo(name, 0, &hint, &ai)) {
++ cnt = __lookup_name(addrs, canon, name, af, AI_CANONNAME);
++ if (cnt<0) switch (cnt) {
+ case EAI_NONAME:
+ *err = HOST_NOT_FOUND;
+- return errno;
++ return ENOENT;
+ case EAI_AGAIN:
+ *err = TRY_AGAIN;
+- return errno;
++ return EAGAIN;
+ default:
++ case EAI_FAIL:
++ *err = NO_RECOVERY;
++ return EBADMSG;
+ case EAI_MEMORY:
+ case EAI_SYSTEM:
+- case EAI_FAIL:
+ *err = NO_RECOVERY;
+ return errno;
+ case 0:
+@@ -50,22 +40,22 @@ int gethostbyname2_r(const char *name, int af,
+ h->h_addrtype = af;
+ h->h_length = af==AF_INET6 ? 16 : 4;
+
+- canon = ai->ai_canonname ? ai->ai_canonname : name;
++ /* Align buffer */
++ align = -(uintptr_t)buf & sizeof(char *)-1;
++
+ need = 4*sizeof(char *);
+- for (i=0, p=ai; p; i++, p=p->ai_next)
+- need += sizeof(char *) + h->h_length;
++ need += (cnt + 1) * (sizeof(char *) + h->h_length);
+ need += strlen(name)+1;
+ need += strlen(canon)+1;
++ need += align;
+
+- if (need > buflen) {
+- freeaddrinfo(ai);
+- return ERANGE;
+- }
++ if (need > buflen) return ERANGE;
+
++ buf += align;
+ h->h_aliases = (void *)buf;
+ buf += 3*sizeof(char *);
+ h->h_addr_list = (void *)buf;
+- buf += (i+1)*sizeof(char *);
++ buf += (cnt+1)*sizeof(char *);
+
+ h->h_name = h->h_aliases[0] = buf;
+ strcpy(h->h_name, canon);
+@@ -79,16 +69,13 @@ int gethostbyname2_r(const char *name, int af,
+
+ h->h_aliases[2] = 0;
+
+- for (i=0, p=ai; p; i++, p=p->ai_next) {
++ for (i=0; i<cnt; i++) {
+ h->h_addr_list[i] = (void *)buf;
+ buf += h->h_length;
+- memcpy(h->h_addr_list[i],
+- &((struct sockaddr_in *)p->ai_addr)->sin_addr,
+- h->h_length);
++ memcpy(h->h_addr_list[i], addrs[i].addr, h->h_length);
+ }
+ h->h_addr_list[i] = 0;
+
+ *res = h;
+- freeaddrinfo(ai);
+ return 0;
+ }
+diff --git a/src/network/getnameinfo.c b/src/network/getnameinfo.c
+index 33f89a3..dfcf6ed 100644
+--- a/src/network/getnameinfo.c
++++ b/src/network/getnameinfo.c
+@@ -5,15 +5,50 @@
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+-#include "__dns.h"
++
++int __dns_parse(const unsigned char *, int, int (*)(void *, int, const void *, int, const void *), void *);
++int __dn_expand(const unsigned char *, const unsigned char *, const unsigned char *, char *, int);
++int __res_mkquery(int, const char *, int, int, const unsigned char *, int, const unsigned char*, unsigned char *, int);
++int __res_send(const unsigned char *, int, unsigned char *, int);
++
++#define PTR_MAX (64 + sizeof ".in-addr.arpa")
++#define RR_PTR 12
++
++static void mkptr4(char *s, const unsigned char *ip)
++{
++ sprintf(s, "%d.%d.%d.%d.in-addr.arpa",
++ ip[3], ip[2], ip[1], ip[0]);
++}
++
++static void mkptr6(char *s, const unsigned char *ip)
++{
++ static const char xdigits[] = "0123456789abcdef";
++ int i;
++ for (i=15; i>=0; i--) {
++ *s++ = xdigits[ip[i]&15]; *s++ = '.';
++ *s++ = xdigits[ip[i]>>4]; *s++ = '.';
++ }
++ strcpy(s, "ip6.arpa");
++}
++
++static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet)
++{
++ char tmp[256];
++ if (rr != RR_PTR) return 0;
++ if (__dn_expand(packet, (const unsigned char *)packet + 512,
++ data, tmp, sizeof tmp) > 0)
++ strcpy(c, tmp);
++ return 0;
++
++}
+
+ int getnameinfo(const struct sockaddr *restrict sa, socklen_t sl,
+ char *restrict node, socklen_t nodelen,
+ char *restrict serv, socklen_t servlen,
+ int flags)
+ {
++ char ptr[PTR_MAX];
+ char buf[256];
+- unsigned char reply[512];
+ int af = sa->sa_family;
+ unsigned char *a;
+
+@@ -21,20 +56,32 @@ int getnameinfo(const struct sockaddr *restrict sa, socklen_t sl,
+ case AF_INET:
+ a = (void *)&((struct sockaddr_in *)sa)->sin_addr;
+ if (sl != sizeof(struct sockaddr_in)) return EAI_FAMILY;
++ mkptr4(ptr, a);
+ break;
+ case AF_INET6:
+ a = (void *)&((struct sockaddr_in6 *)sa)->sin6_addr;
+ if (sl != sizeof(struct sockaddr_in6)) return EAI_FAMILY;
++ if (memcmp(a, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12))
++ mkptr6(ptr, a);
++ else
++ mkptr4(ptr, a+12);
+ break;
+ default:
+ return EAI_FAMILY;
+ }
+
+ if (node && nodelen) {
+- if ((flags & NI_NUMERICHOST)
+- || __dns_query(reply, a, af, 1) <= 0
+- || __dns_get_rr(buf, 0, 256, 1, reply, RR_PTR, 1) <= 0)
+- {
++ buf[0] = 0;
++ if (!(flags & NI_NUMERICHOST)) {
++ unsigned char query[18+PTR_MAX], reply[512];
++ int qlen = __res_mkquery(0, ptr, 1, RR_PTR,
++ 0, 0, 0, query, sizeof query);
++ int rlen = __res_send(query, qlen, reply, sizeof reply);
++ buf[0] = 0;
++ if (rlen > 0)
++ __dns_parse(reply, rlen, dns_parse_callback, buf);
++ }
++ if (!*buf) {
+ if (flags & NI_NAMEREQD) return EAI_NONAME;
+ inet_ntop(af, a, buf, sizeof buf);
+ }
+diff --git a/src/network/getservbyname.c b/src/network/getservbyname.c
+index 0b00ce1..dd30376 100644
+--- a/src/network/getservbyname.c
++++ b/src/network/getservbyname.c
+@@ -4,7 +4,7 @@
+ struct servent *getservbyname(const char *name, const char *prots)
+ {
+ static struct servent se;
+- static long buf[32/sizeof(long)];
++ static char *buf[2];
+ struct servent *res;
+ if (getservbyname_r(name, prots, &se, (void *)buf, sizeof buf, &res))
+ return 0;
+diff --git a/src/network/getservbyname_r.c b/src/network/getservbyname_r.c
+index 811c174..8cdf622 100644
+--- a/src/network/getservbyname_r.c
++++ b/src/network/getservbyname_r.c
+@@ -5,49 +5,43 @@
+ #include <inttypes.h>
+ #include <errno.h>
+ #include <string.h>
++#include "lookup.h"
++
++#define ALIGN (sizeof(struct { char a; char *b; }) - sizeof(char *))
+
+ int getservbyname_r(const char *name, const char *prots,
+ struct servent *se, char *buf, size_t buflen, struct servent **res)
+ {
+- struct addrinfo *ai, hint = { .ai_family = AF_INET };
+- int i;
+-
+- if (!prots) {
+- int r = getservbyname_r(name, "tcp", se, buf, buflen, res);
+- if (r) r = getservbyname_r(name, "udp", se, buf, buflen, res);
+- return r;
+- }
++ struct service servs[MAXSERVS];
++ int cnt, proto, align;
+
+ /* Align buffer */
+- i = (uintptr_t)buf & sizeof(char *)-1;
+- if (!i) i = sizeof(char *);
+- if (buflen < 3*sizeof(char *)-i)
++ align = -(uintptr_t)buf & ALIGN-1;
++ if (buflen < 2*sizeof(char *)+align)
+ return ERANGE;
+- buf += sizeof(char *)-i;
+- buflen -= sizeof(char *)-i;
++ buf += align;
+
+- if (!strcmp(prots, "tcp")) hint.ai_protocol = IPPROTO_TCP;
+- else if (!strcmp(prots, "udp")) hint.ai_protocol = IPPROTO_UDP;
++ if (!prots) proto = 0;
++ else if (!strcmp(prots, "tcp")) proto = IPPROTO_TCP;
++ else if (!strcmp(prots, "udp")) proto = IPPROTO_UDP;
+ else return EINVAL;
+
+- switch (getaddrinfo(0, name, &hint, &ai)) {
++ cnt = __lookup_serv(servs, name, proto, 0);
++ if (cnt<0) switch (cnt) {
+ case EAI_MEMORY:
+ case EAI_SYSTEM:
+ return ENOMEM;
+ default:
+ return ENOENT;
+- case 0:
+- break;
+ }
+
+ se->s_name = (char *)name;
+ se->s_aliases = (void *)buf;
+ se->s_aliases[0] = se->s_name;
+ se->s_aliases[1] = 0;
+- se->s_port = ((struct sockaddr_in *)ai->ai_addr)->sin_port;
+- se->s_proto = (char *)prots;
++ se->s_port = htons(servs[0].port);
++ se->s_proto = servs[0].proto == IPPROTO_TCP ? "tcp" : "udp";
+
+- freeaddrinfo(ai);
+ *res = se;
+ return 0;
+ }
+diff --git a/src/network/inet_addr.c b/src/network/inet_addr.c
+index ea0a8f7..10b21f2 100644
+--- a/src/network/inet_addr.c
++++ b/src/network/inet_addr.c
+@@ -1,11 +1,12 @@
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+-#include "__dns.h"
++
++int __inet_aton(const char *, struct in_addr *);
+
+ in_addr_t inet_addr(const char *p)
+ {
+- struct sockaddr_in sin;
+- if (__ipparse(&sin, AF_INET, p) < 0) return -1;
+- return sin.sin_addr.s_addr;
++ struct in_addr a;
++ if (!__inet_aton(p, &a)) return -1;
++ return a.s_addr;
+ }
+diff --git a/src/network/inet_aton.c b/src/network/inet_aton.c
+new file mode 100644
+index 0000000..0f9a45f
+--- /dev/null
++++ b/src/network/inet_aton.c
+@@ -0,0 +1,41 @@
++#include <ctype.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <arpa/inet.h>
++#include "libc.h"
++
++int __inet_aton(const char *s0, struct in_addr *dest)
++{
++ const char *s = s0;
++ unsigned char *d = (void *)dest;
++ unsigned long a[4] = { 0 };
++ char *z;
++ int i;
++
++ for (i=0; i<4; i++) {
++ a[i] = strtoul(s, &z, 0);
++ if (z==s || (*z && *z != '.') || !isdigit(*s))
++ return 0;
++ if (!*z) break;
++ s=z+1;
++ }
++ if (i==4) return 0;
++ switch (i) {
++ case 0:
++ a[1] = a[0] & 0xffffff;
++ a[0] >>= 24;
++ case 1:
++ a[2] = a[1] & 0xffff;
++ a[1] >>= 16;
++ case 2:
++ a[3] = a[2] & 0xff;
++ a[2] >>= 8;
++ }
++ for (i=0; i<4; i++) {
++ if (a[i] > 255) return 0;
++ d[i] = a[i];
++ }
++ return 1;
++}
++
++weak_alias(__inet_aton, inet_aton);
+diff --git a/src/network/inet_legacy.c b/src/network/inet_legacy.c
+index de5b75c..621b47b 100644
+--- a/src/network/inet_legacy.c
++++ b/src/network/inet_legacy.c
+@@ -1,21 +1,12 @@
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+-#include "__dns.h"
+
+ in_addr_t inet_network(const char *p)
+ {
+ return ntohl(inet_addr(p));
+ }
+
+-int inet_aton(const char *cp, struct in_addr *inp)
+-{
+- struct sockaddr_in sin;
+- if (__ipparse(&sin, AF_INET, cp) < 0) return 0;
+- *inp = sin.sin_addr;
+- return 1;
+-}
+-
+ struct in_addr inet_makeaddr(in_addr_t n, in_addr_t h)
+ {
+ if (n < 256) h |= n<<24;
+diff --git a/src/network/lookup.h b/src/network/lookup.h
+new file mode 100644
+index 0000000..82c969e
+--- /dev/null
++++ b/src/network/lookup.h
+@@ -0,0 +1,26 @@
++#ifndef LOOKUP_H
++#define LOOKUP_H
++
++#include <stdint.h>
++
++struct address {
++ int family;
++ unsigned scopeid;
++ uint8_t addr[16];
++};
++
++struct service {
++ uint16_t port;
++ char proto;
++};
++
++/* The limit of 48 results is a non-sharp bound on the number of addresses
++ * that can fit in one 512-byte DNS packet full of v4 results and a second
++ * packet full of v6 results. Due to headers, the actual limit is lower. */
++#define MAXADDRS 48
++#define MAXSERVS 2
++
++int __lookup_serv(struct service buf[static MAXSERVS], const char *name, int proto, int flags);
++int __lookup_name(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family, int flags);
++
++#endif
+diff --git a/src/network/lookup_name.c b/src/network/lookup_name.c
+new file mode 100644
+index 0000000..8d41627
+--- /dev/null
++++ b/src/network/lookup_name.c
+@@ -0,0 +1,210 @@
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <netdb.h>
++#include <arpa/inet.h>
++#include <ctype.h>
++#include <stdlib.h>
++#include <string.h>
++#include <fcntl.h>
++#include "lookup.h"
++#include "stdio_impl.h"
++#include "syscall.h"
++
++static int is_valid_hostname(const char *host)
++{
++ const unsigned char *s;
++ if (strnlen(host, 256)-1 > 254 || mbstowcs(0, host, 0) > 255) return 0;
++ for (s=(void *)host; *s>=0x80 || *s=='.' || *s=='-' || isalnum(*s); s++);
++ return !*s;
++}
++
++static int name_from_null(struct address buf[static 2], const char *name, int family, int flags)
++{
++ int cnt = 0;
++ if (name) return 0;
++ if (flags & AI_PASSIVE) {
++ if (family != AF_INET6)
++ buf[cnt++] = (struct address){ .family = AF_INET };
++ if (family != AF_INET)
++ buf[cnt++] = (struct address){ .family = AF_INET6 };
++ } else {
++ if (family != AF_INET6)
++ buf[cnt++] = (struct address){ .family = AF_INET, .addr = { 127,0,0,1 } };
++ if (family != AF_INET)
++ buf[cnt++] = (struct address){ .family = AF_INET6, .addr = { [15] = 1 } };
++ }
++ return cnt;
++}
++
++int __inet_aton(const char *, struct in_addr *);
++
++static int name_from_numeric(struct address buf[static 1], const char *name, int family)
++{
++ struct in_addr a4;
++ struct in6_addr a6;
++ if (family != AF_INET6 && __inet_aton(name, &a4)>0) {
++ memcpy(&buf[0].addr, &a4, sizeof a4);
++ buf[0].family = AF_INET;
++ return 1;
++ }
++ if (family != AF_INET && inet_pton(AF_INET6, name, &a6)>0) {
++ memcpy(&buf[0].addr, &a6, sizeof a6);
++ buf[0].family = AF_INET6;
++ return 1;
++ }
++ return 0;
++}
++
++static int name_from_hosts(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family)
++{
++ char line[512];
++ size_t l = strlen(name);
++ int cnt = 0;
++ unsigned char _buf[1032];
++ FILE _f, *f = __fopen_rb_ca("/etc/hosts", &_f, _buf, sizeof _buf);
++ if (!f) return 0;
++ while (fgets(line, sizeof line, f) && cnt < MAXADDRS) {
++ char *p, *z;
++
++ if ((p=strchr(line, '#'))) *p++='\n', *p=0;
++ for(p=line+1; (p=strstr(p, name)) &&
++ (!isspace(p[-1]) || !isspace(p[l])); p++);
++ if (!p) continue;
++
++ /* Isolate IP address to parse */
++ for (p=line; *p && !isspace(*p); p++);
++ *p++ = 0;
++ if (name_from_numeric(buf+cnt, line, family))
++ cnt++;
++
++ /* Extract first name as canonical name */
++ for (; *p && isspace(*p); p++);
++ for (z=p; *z && !isspace(*z); z++);
++ *z = 0;
++ if (is_valid_hostname(p)) memcpy(canon, p, z-p+1);
++ }
++ __fclose_ca(f);
++ return cnt;
++}
++
++struct dpc_ctx {
++ struct address *addrs;
++ char *canon;
++ int cnt;
++};
++
++int __dns_parse(const unsigned char *, int, int (*)(void *, int, const void *, int, const void *), void *);
++int __dn_expand(const unsigned char *, const unsigned char *, const unsigned char *, char *, int);
++int __res_mkquery(int, const char *, int, int, const unsigned char *, int, const unsigned char*, unsigned char *, int);
++int __res_msend(int, const unsigned char *const *, const int *, unsigned char *const *, int *, int);
++
++#define RR_A 1
++#define RR_CNAME 5
++#define RR_AAAA 28
++
++static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet)
++{
++ char tmp[256];
++ struct dpc_ctx *ctx = c;
++ switch (rr) {
++ case RR_A:
++ if (len != 4) return -1;
++ ctx->addrs[ctx->cnt].family = AF_INET;
++ memcpy(ctx->addrs[ctx->cnt++].addr, data, 4);
++ break;
++ case RR_AAAA:
++ if (len != 16) return -1;
++ ctx->addrs[ctx->cnt].family = AF_INET6;
++ memcpy(ctx->addrs[ctx->cnt++].addr, data, 16);
++ break;
++ case RR_CNAME:
++ if (__dn_expand(packet, (const unsigned char *)packet + 512,
++ data, tmp, sizeof tmp) > 0 && is_valid_hostname(tmp))
++ strcpy(ctx->canon, tmp);
++ break;
++ }
++ return 0;
++}
++
++static int name_from_dns(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family)
++{
++ unsigned char qbuf[2][280], abuf[2][512];
++ const unsigned char *qp[2] = { qbuf[0], qbuf[1] };
++ unsigned char *ap[2] = { abuf[0], abuf[1] };
++ int qlens[2], alens[2];
++ int i, nq = 0;
++ struct dpc_ctx ctx = { .addrs = buf, .canon = canon };
++
++ if (family != AF_INET6) {
++ qlens[nq] = __res_mkquery(0, name, 1, RR_A, 0, 0, 0,
++ qbuf[nq], sizeof *qbuf);
++ nq++;
++ }
++ if (family != AF_INET) {
++ qlens[nq] = __res_mkquery(0, name, 1, RR_AAAA, 0, 0, 0,
++ qbuf[nq], sizeof *qbuf);
++ nq++;
++ }
++
++ if (__res_msend(nq, qp, qlens, ap, alens, sizeof *abuf) < 0) return EAI_SYSTEM;
++
++ for (i=0; i<nq; i++)
++ __dns_parse(abuf[i], alens[i], dns_parse_callback, &ctx);
++
++ return ctx.cnt;
++}
++
++int __lookup_name(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family, int flags)
++{
++ int cnt = 0, i, j;
++
++ *canon = 0;
++ if (name) {
++ size_t l;
++ if ((l = strnlen(name, 256))-1 > 254)
++ return EAI_NONAME;
++ memcpy(canon, name, l+1);
++ }
++
++ /* Procedurally, a request for v6 addresses with the v4-mapped
++ * flag set is like a request for unspecified family, followed
++ * by filtering of the results. */
++ if (flags & AI_V4MAPPED) {
++ if (family == AF_INET6) family = AF_UNSPEC;
++ else flags -= AI_V4MAPPED;
++ }
++
++ /* Try each backend until there's at least one result. */
++ cnt = name_from_null(buf, name, family, flags);
++ if (cnt<=0) cnt = name_from_numeric(buf, name, family);
++ if (cnt<=0 && !(flags & AI_NUMERICHOST)) {
++ cnt = name_from_hosts(buf, canon, name, family);
++ if (cnt<=0) cnt = name_from_dns(buf, canon, name, family);
++ }
++ if (cnt<=0) return cnt ? cnt : EAI_NONAME;
++
++ /* Filter/transform results for v4-mapped lookup, if requested. */
++ if (flags & AI_V4MAPPED) {
++ if (!(flags & AI_ALL)) {
++ /* If any v6 results exist, remove v4 results. */
++ for (i=0; i<cnt && buf[i].family != AF_INET6; i++);
++ if (i<cnt) {
++ for (j=0; i<cnt; i++) {
++ if (buf[i].family == AF_INET6)
++ buf[j++] = buf[i];
++ }
++ cnt = i = j;
++ }
++ }
++ /* Translate any remaining v4 results to v6 */
++ for (i=0; i<cnt; i++) {
++ if (buf[i].family != AF_INET) continue;
++ memcpy(buf[i].addr+12, buf[i].addr, 4);
++ memcpy(buf[i].addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
++ buf[i].scopeid = 0;
++ buf[i].family = AF_INET6;
++ }
++ }
++
++ return cnt;
++}
+diff --git a/src/network/lookup_serv.c b/src/network/lookup_serv.c
+new file mode 100644
+index 0000000..bf4cba0
+--- /dev/null
++++ b/src/network/lookup_serv.c
+@@ -0,0 +1,72 @@
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <netdb.h>
++#include <ctype.h>
++#include <string.h>
++#include <fcntl.h>
++#include "lookup.h"
++#include "stdio_impl.h"
++
++int __lookup_serv(struct service buf[static MAXSERVS], const char *name, int proto, int flags)
++{
++ char line[128];
++ int cnt = 0;
++ char *p, *z = "";
++ unsigned long port = 0;
++
++ if (name) {
++ if (!*name) return EAI_SERVICE;
++ port = strtoul(name, &z, 10);
++ }
++ if (!*z) {
++ if (port > 65535) return EAI_SERVICE;
++ if (proto != IPPROTO_UDP) {
++ buf[cnt].port = port;
++ buf[cnt++].proto = IPPROTO_TCP;
++ }
++ if (proto != IPPROTO_TCP) {
++ buf[cnt].port = port;
++ buf[cnt++].proto = IPPROTO_UDP;
++ }
++ return cnt;
++ }
++
++ if (flags & AI_NUMERICSERV) return EAI_SERVICE;
++
++ size_t l = strlen(name);
++
++ unsigned char _buf[1032];
++ FILE _f, *f = __fopen_rb_ca("/etc/services", &_f, _buf, sizeof _buf);
++ if (!f) return EAI_SERVICE;
++
++ while (fgets(line, sizeof line, f) && cnt < MAXSERVS) {
++ if ((p=strchr(line, '#'))) *p++='\n', *p=0;
++
++ /* Find service name */
++ for(p=line; (p=strstr(p, name)); p++) {
++ if (p>line && !isspace(p[-1])) continue;
++ if (p[l] && !isspace(p[l])) continue;
++ break;
++ }
++ if (!p) continue;
++
++ /* Skip past canonical name at beginning of line */
++ for (p=line; *p && !isspace(*p); p++);
++ if (!p) continue;
++
++ port = strtoul(p, &z, 10);
++ if (port > 65535 || z==p) continue;
++ if (!strncmp(z, "/udp", 4)) {
++ if (proto == IPPROTO_TCP) continue;
++ buf[cnt].port = port;
++ buf[cnt++].proto = IPPROTO_UDP;
++ }
++ if (!strncmp(z, "/tcp", 4)) {
++ if (proto == IPPROTO_UDP) continue;
++ buf[cnt].port = port;
++ buf[cnt++].proto = IPPROTO_TCP;
++ }
++ }
++ __fclose_ca(f);
++ return cnt > 0 ? cnt : EAI_SERVICE;
++}
+diff --git a/src/network/proto.c b/src/network/proto.c
+index 3d0f584..1b51e15 100644
+--- a/src/network/proto.c
++++ b/src/network/proto.c
+@@ -14,7 +14,11 @@ static const unsigned char protos[][8] = {
+ "\021udp",
+ "\026idp",
+ "\051ipv6",
++ "\057gre",
++ "\062esp",
++ "\063ah",
+ "\072icmpv6",
++ "\136ipip",
+ "\377raw",
+ "\0\0"
+ };
+diff --git a/src/network/res_init.c b/src/network/res_init.c
+index cbd5b15..5dba9df 100644
+--- a/src/network/res_init.c
++++ b/src/network/res_init.c
+@@ -1,3 +1,5 @@
++#include <resolv.h>
++
+ int res_init()
+ {
+ return 0;
+diff --git a/src/network/res_mkquery.c b/src/network/res_mkquery.c
+new file mode 100644
+index 0000000..f7e4e9c
+--- /dev/null
++++ b/src/network/res_mkquery.c
+@@ -0,0 +1,41 @@
++#include <resolv.h>
++#include <string.h>
++#include <time.h>
++#include "libc.h"
++
++int __res_mkquery(int op, const char *dname, int class, int type,
++ const unsigned char *data, int datalen,
++ const unsigned char *newrr, unsigned char *buf, int buflen)
++{
++ int id, i, j;
++ unsigned char q[280];
++ struct timespec ts;
++ size_t l = strnlen(dname, 256);
++
++ if (l-1>=254 || buflen<18+l || op>15u || class>255u || type>255u)
++ return -1;
++
++ /* Construct query template - ID will be filled later */
++ memset(q, 0, 18+l);
++ q[2] = op*8 + 1;
++ q[5] = 1;
++ memcpy((char *)q+13, dname, l);
++ for (i=13; q[i]; i=j+1) {
++ for (j=i; q[j] && q[j] != '.'; j++);
++ if (j-i-1u > 62u) return -1;
++ q[i-1] = j-i;
++ }
++ q[i+1] = type;
++ q[i+3] = class;
++
++ /* Make a reasonably unpredictable id */
++ clock_gettime(CLOCK_REALTIME, &ts);
++ id = ts.tv_nsec + ts.tv_nsec/65536UL & 0xffff;
++ q[0] = id/256;
++ q[1] = id;
++
++ memcpy(buf, q, 18+l);
++ return 18+l;
++}
++
++weak_alias(__res_mkquery, res_mkquery);
+diff --git a/src/network/res_msend.c b/src/network/res_msend.c
+new file mode 100644
+index 0000000..a5b7793
+--- /dev/null
++++ b/src/network/res_msend.c
+@@ -0,0 +1,185 @@
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <netdb.h>
++#include <arpa/inet.h>
++#include <stdint.h>
++#include <string.h>
++#include <poll.h>
++#include <time.h>
++#include <ctype.h>
++#include <unistd.h>
++#include <errno.h>
++#include <pthread.h>
++#include "stdio_impl.h"
++#include "syscall.h"
++
++static void cleanup(void *p)
++{
++ __syscall(SYS_close, (intptr_t)p);
++}
++
++static unsigned long mtime()
++{
++ struct timespec ts;
++ clock_gettime(CLOCK_REALTIME, &ts);
++ return (unsigned long)ts.tv_sec * 1000
++ + ts.tv_nsec / 1000000;
++}
++
++int __res_msend(int nqueries, const unsigned char *const *queries,
++ const int *qlens, unsigned char *const *answers, int *alens, int asize)
++{
++ int fd;
++ FILE *f, _f;
++ unsigned char _buf[256];
++ char line[64], *s, *z;
++ int timeout = 5000, attempts = 2, retry_interval;
++ union {
++ struct sockaddr_in sin;
++ struct sockaddr_in6 sin6;
++ } sa = {0}, ns[3] = {{0}};
++ socklen_t sl = sizeof sa.sin;
++ int nns = 0;
++ int family = AF_INET;
++ int rlen;
++ int next;
++ int i, j;
++ int cs;
++ struct pollfd pfd;
++ unsigned long t0, t1, t2;
++
++ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
++
++ /* Get nameservers from resolv.conf, fallback to localhost */
++ f = __fopen_rb_ca("/etc/resolv.conf", &_f, _buf, sizeof _buf);
++ if (f) for (nns=0; nns<3 && fgets(line, sizeof line, f); ) {
++ if (!strncmp(line, "options", 7) && isspace(line[7])) {
++ unsigned long x;
++ char *p, *z;
++ p = strstr(line, "timeout:");
++ if (p && isdigit(p[8])) {
++ p += 8;
++ x = strtoul(p, &z, 10);
++ if (z != p) timeout = x < 30 ? x*1000 : 30000;
++ }
++ p = strstr(line, "attempts:");
++ if (p && isdigit(p[9])) {
++ p += 9;
++ x = strtoul(p, &z, 10);
++ if (z != p) attempts = x < 10 ? x : 10;
++ if (!attempts) attempts = 1;
++ }
++ }
++ if (strncmp(line, "nameserver", 10) || !isspace(line[10]))
++ continue;
++ for (s=line+11; isspace(*s); s++);
++ for (z=s; *z && !isspace(*z); z++);
++ *z=0;
++
++ if (inet_pton(AF_INET, s, &ns[nns].sin.sin_addr)>0) {
++ ns[nns].sin.sin_port = htons(53);
++ ns[nns++].sin.sin_family = AF_INET;
++ } else if (inet_pton(AF_INET6, s, &ns[nns].sin6.sin6_addr)>0) {
++ sl = sizeof sa.sin6;
++ ns[nns].sin6.sin6_port = htons(53);
++ ns[nns++].sin6.sin6_family = family = AF_INET6;
++ }
++ }
++ if (f) __fclose_ca(f);
++ if (!nns) {
++ ns[0].sin.sin_family = AF_INET;
++ ns[0].sin.sin_port = htons(53);
++ ns[0].sin.sin_addr.s_addr = htonl(0x7f000001);
++ nns=1;
++ }
++
++ /* Get local address and open/bind a socket */
++ sa.sin.sin_family = family;
++ fd = socket(family, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
++
++ /* Handle case where system lacks IPv6 support */
++ if (fd < 0 && family == AF_INET6 && errno == EAFNOSUPPORT) {
++ fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
++ family = AF_INET;
++ }
++ if (fd < 0 || bind(fd, (void *)&sa, sl) < 0) return -1;
++
++ /* Past this point, there are no errors. Each individual query will
++ * yield either no reply (indicated by zero length) or an answer
++ * packet which is up to the caller to interpret. */
++
++ pthread_cleanup_push(cleanup, (void *)(intptr_t)fd);
++ pthread_setcancelstate(cs, 0);
++
++ /* Convert any IPv4 addresses in a mixed environment to v4-mapped */
++ if (family == AF_INET6) {
++ setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){0}, sizeof 0);
++ for (i=0; i<nns; i++) {
++ if (ns[i].sin.sin_family != AF_INET) continue;
++ memcpy(ns[i].sin6.sin6_addr.s6_addr+12,
++ &ns[i].sin.sin_addr, 4);
++ memcpy(ns[i].sin6.sin6_addr.s6_addr,
++ "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
++ ns[i].sin6.sin6_family = AF_INET6;
++ ns[i].sin6.sin6_flowinfo = 0;
++ ns[i].sin6.sin6_scope_id = 0;
++ }
++ }
++
++ memset(alens, 0, sizeof *alens * nqueries);
++
++ pfd.fd = fd;
++ pfd.events = POLLIN;
++ retry_interval = timeout / attempts;
++ next = 0;
++ t0 = t2 = mtime();
++ t1 = t2 - retry_interval;
++
++ for (; t2-t0 < timeout; t2=mtime()) {
++ if (t2-t1 >= retry_interval) {
++ /* Query all configured namservers in parallel */
++ for (i=0; i<nqueries; i++)
++ if (!alens[i])
++ for (j=0; j<nns; j++)
++ sendto(fd, queries[i],
++ qlens[i], MSG_NOSIGNAL,
++ (void *)&ns[j], sl);
++ t1 = t2;
++ }
++
++ /* Wait for a response, or until time to retry */
++ if (poll(&pfd, 1, t1+retry_interval-t2) <= 0) continue;
++
++ while ((rlen = recvfrom(fd, answers[next], asize, 0,
++ (void *)&sa, (socklen_t[1]){sl})) >= 0) {
++
++ /* Ignore non-identifiable packets (no query id) */
++ if (rlen < 2) continue;
++
++ /* Ignore replies from addresses we didn't send to */
++ for (i=0; i<nns && memcmp(ns+i, &sa, sl); i++);
++ if (i==nns) continue;
++
++ /* Find which query this answer goes with, if any */
++ for (i=next; i<nqueries && (
++ answers[next][0] != queries[i][0] ||
++ answers[next][1] != queries[i][1] ); i++);
++ if (i==nqueries) continue;
++ if (alens[i]) continue;
++
++ /* Store answer in the right slot, or update next
++ * available temp slot if it's already in place. */
++ alens[i] = rlen;
++ if (i == next)
++ for (; next<nqueries && alens[next]; next++);
++ else
++ memcpy(answers[i], answers[next], rlen);
++
++ if (next == nqueries) goto out;
++ }
++ }
++out:
++ pthread_cleanup_pop(1);
++
++ return 0;
++}
+diff --git a/src/network/res_query.c b/src/network/res_query.c
+index 3847da3..2b4e4bb 100644
+--- a/src/network/res_query.c
++++ b/src/network/res_query.c
+@@ -1,25 +1,17 @@
+-#define _GNU_SOURCE
+ #include <resolv.h>
+ #include <netdb.h>
+-#include "__dns.h"
+ #include "libc.h"
+
+-int res_query(const char *name, int class, int type, unsigned char *dest, int len)
++int __res_mkquery(int, const char *, int, int, const unsigned char *, int, const unsigned char*, unsigned char *, int);
++int __res_send(const unsigned char *, int, unsigned char *, int);
++
++int __res_query(const char *name, int class, int type, unsigned char *dest, int len)
+ {
+- if (class != 1 || len < 512)
+- return -1;
+- switch(__dns_doqueries(dest, name, &type, 1)) {
+- case EAI_NONAME:
+- h_errno = HOST_NOT_FOUND;
+- return -1;
+- case EAI_AGAIN:
+- h_errno = TRY_AGAIN;
+- return -1;
+- case EAI_FAIL:
+- h_errno = NO_RECOVERY;
+- return -1;
+- }
+- return 512;
++ unsigned char q[280];
++ int ql = __res_mkquery(0, name, class, type, 0, 0, 0, q, sizeof q);
++ if (ql < 0) return ql;
++ return __res_send(q, ql, dest, len);
+ }
+
+-weak_alias(res_query, res_search);
++weak_alias(__res_query, res_query);
++weak_alias(__res_query, res_search);
+diff --git a/src/network/res_querydomain.c b/src/network/res_querydomain.c
+new file mode 100644
+index 0000000..c746dbe
+--- /dev/null
++++ b/src/network/res_querydomain.c
+@@ -0,0 +1,14 @@
++#include <resolv.h>
++#include <string.h>
++
++int res_querydomain(const char *name, const char *domain, int class, int type, unsigned char *dest, int len)
++{
++ char tmp[256];
++ size_t nl = strnlen(name, 256);
++ size_t dl = strnlen(domain, 256);
++ if (nl+dl+1 > 255) return -1;
++ memcpy(tmp, name, nl);
++ tmp[nl] = '.';
++ memcpy(tmp+nl+1, domain, dl+1);
++ return res_query(tmp, class, type, dest, len);
++}
+diff --git a/src/network/res_send.c b/src/network/res_send.c
+new file mode 100644
+index 0000000..19cfe0f
+--- /dev/null
++++ b/src/network/res_send.c
+@@ -0,0 +1,12 @@
++#include <resolv.h>
++#include "libc.h"
++
++int __res_msend(int, const unsigned char *const *, const int *, unsigned char *const *, int *, int);
++
++int __res_send(const unsigned char *msg, int msglen, unsigned char *answer, int anslen)
++{
++ int r = __res_msend(1, &msg, &msglen, &answer, &anslen, anslen);
++ return r<0 ? r : anslen;
++}
++
++weak_alias(__res_send, res_send);
+diff --git a/src/process/fork.c b/src/process/fork.c
+index 864c7d7..f8cf21e 100644
+--- a/src/process/fork.c
++++ b/src/process/fork.c
+@@ -1,5 +1,6 @@
+ #include <unistd.h>
+ #include <string.h>
++#include <signal.h>
+ #include "syscall.h"
+ #include "libc.h"
+ #include "pthread_impl.h"
+@@ -16,7 +17,11 @@ pid_t fork(void)
+ sigset_t set;
+ __fork_handler(-1);
+ __block_all_sigs(&set);
++#ifdef SYS_fork
+ ret = syscall(SYS_fork);
++#else
++ ret = syscall(SYS_clone, SIGCHLD, 0);
++#endif
+ if (libc.has_thread_pointer && !ret) {
+ pthread_t self = __pthread_self();
+ self->tid = self->pid = __syscall(SYS_getpid);
+diff --git a/src/process/posix_spawn.c b/src/process/posix_spawn.c
+index f675a13..08928b0 100644
+--- a/src/process/posix_spawn.c
++++ b/src/process/posix_spawn.c
+@@ -22,6 +22,20 @@ struct args {
+
+ void __get_handler_set(sigset_t *);
+
++static int __sys_dup2(int old, int new)
++{
++#ifdef SYS_dup2
++ return __syscall(SYS_dup2, old, new);
++#else
++ if (old==new) {
++ int r = __syscall(SYS_fcntl, old, F_GETFD);
++ return r<0 ? r : old;
++ } else {
++ return __syscall(SYS_dup3, old, new, 0);
++ }
++#endif
++}
++
+ static int child(void *args_vp)
+ {
+ int i, ret;
+@@ -92,15 +106,14 @@ static int child(void *args_vp)
+ goto fail;
+ break;
+ case FDOP_DUP2:
+- if ((ret=__syscall(SYS_dup2, op->srcfd, op->fd))<0)
++ if ((ret=__sys_dup2(op->srcfd, op->fd))<0)
+ goto fail;
+ break;
+ case FDOP_OPEN:
+- fd = __syscall(SYS_open, op->path,
+- op->oflag | O_LARGEFILE, op->mode);
++ fd = __sys_open(op->path, op->oflag, op->mode);
+ if ((ret=fd) < 0) goto fail;
+ if (fd != op->fd) {
+- if ((ret=__syscall(SYS_dup2, fd, op->fd))<0)
++ if ((ret=__sys_dup2(fd, op->fd))<0)
+ goto fail;
+ __syscall(SYS_close, fd);
+ }
+diff --git a/src/process/vfork.c b/src/process/vfork.c
+index fc4adb4..ac95465 100644
+--- a/src/process/vfork.c
++++ b/src/process/vfork.c
+@@ -1,12 +1,17 @@
+ #define _GNU_SOURCE
+ #include <unistd.h>
++#include <signal.h>
+ #include "syscall.h"
+ #include "libc.h"
+
+ pid_t __vfork(void)
+ {
+ /* vfork syscall cannot be made from C code */
++#ifdef SYS_fork
+ return syscall(SYS_fork);
++#else
++ return syscall(SYS_clone, SIGCHLD, 0);
++#endif
+ }
+
+ weak_alias(__vfork, vfork);
+diff --git a/src/select/poll.c b/src/select/poll.c
+index f1e73e8..9e0bcbd 100644
+--- a/src/select/poll.c
++++ b/src/select/poll.c
+@@ -1,8 +1,16 @@
+ #include <poll.h>
++#include <time.h>
++#include <signal.h>
+ #include "syscall.h"
+ #include "libc.h"
+
+ int poll(struct pollfd *fds, nfds_t n, int timeout)
+ {
++#ifdef SYS_poll
+ return syscall_cp(SYS_poll, fds, n, timeout);
++#else
++ return syscall_cp(SYS_ppoll, fds, n, timeout>=0 ?
++ &((struct timespec){ .tv_sec = timeout/1000,
++ .tv_nsec = timeout%1000*1000000 }) : 0, 0, _NSIG/8);
++#endif
+ }
+diff --git a/src/select/pselect.c b/src/select/pselect.c
+index a19e153..4e2d7b0 100644
+--- a/src/select/pselect.c
++++ b/src/select/pselect.c
+@@ -1,11 +1,12 @@
+ #include <sys/select.h>
+ #include <signal.h>
++#include <stdint.h>
+ #include "syscall.h"
+ #include "libc.h"
+
+ int pselect(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict efds, const struct timespec *restrict ts, const sigset_t *restrict mask)
+ {
+- long data[2] = { (long)mask, _NSIG/8 };
++ syscall_arg_t data[2] = { (uintptr_t)mask, _NSIG/8 };
+ struct timespec ts_tmp;
+ if (ts) ts_tmp = *ts;
+ return syscall_cp(SYS_pselect6, n, rfds, wfds, efds, ts ? &ts_tmp : 0, data);
+diff --git a/src/select/select.c b/src/select/select.c
+index f93597b..7b5f6dc 100644
+--- a/src/select/select.c
++++ b/src/select/select.c
+@@ -1,8 +1,26 @@
+ #include <sys/select.h>
++#include <signal.h>
++#include <stdint.h>
++#include <errno.h>
+ #include "syscall.h"
+ #include "libc.h"
+
+ int select(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict efds, struct timeval *restrict tv)
+ {
++#ifdef SYS_select
+ return syscall_cp(SYS_select, n, rfds, wfds, efds, tv);
++#else
++ syscall_arg_t data[2] = { 0, _NSIG/8 };
++ struct timespec ts;
++ if (tv) {
++ if (tv->tv_sec < 0 || tv->tv_usec < 0)
++ return __syscall_ret(-EINVAL);
++ time_t extra_secs = tv->tv_usec / 1000000;
++ ts.tv_nsec = tv->tv_usec % 1000000 * 1000;
++ const time_t max_time = (1ULL<<8*sizeof(time_t)-1)-1;
++ ts.tv_sec = extra_secs > max_time - tv->tv_sec ?
++ max_time : tv->tv_sec + extra_secs;
++ }
++ return syscall_cp(SYS_pselect6, n, rfds, wfds, efds, tv ? &ts : 0, data);
++#endif
+ }
+diff --git a/src/stat/chmod.c b/src/stat/chmod.c
+index beb66e5..d4f53c5 100644
+--- a/src/stat/chmod.c
++++ b/src/stat/chmod.c
+@@ -1,7 +1,12 @@
+ #include <sys/stat.h>
++#include <fcntl.h>
+ #include "syscall.h"
+
+ int chmod(const char *path, mode_t mode)
+ {
++#ifdef SYS_chmod
+ return syscall(SYS_chmod, path, mode);
++#else
++ return syscall(SYS_fchmodat, AT_FDCWD, path, mode);
++#endif
+ }
+diff --git a/src/stat/fchmod.c b/src/stat/fchmod.c
+index 6d28141..93e1b64 100644
+--- a/src/stat/fchmod.c
++++ b/src/stat/fchmod.c
+@@ -13,5 +13,9 @@ int fchmod(int fd, mode_t mode)
+
+ char buf[15+3*sizeof(int)];
+ __procfdname(buf, fd);
++#ifdef SYS_chmod
+ return syscall(SYS_chmod, buf, mode);
++#else
++ return syscall(SYS_fchmodat, AT_FDCWD, buf, mode);
++#endif
+ }
+diff --git a/src/stat/fchmodat.c b/src/stat/fchmodat.c
+index 12e7ff0..afa6d44 100644
+--- a/src/stat/fchmodat.c
++++ b/src/stat/fchmodat.c
+@@ -28,8 +28,9 @@ int fchmodat(int fd, const char *path, mode_t mode, int flag)
+ }
+
+ __procfdname(proc, fd2);
+- if (!(ret = __syscall(SYS_stat, proc, &st)) && !S_ISLNK(st.st_mode))
+- ret = __syscall(SYS_chmod, proc, mode);
++ ret = __syscall(SYS_fstatat, AT_FDCWD, proc, &st, 0);
++ if (!ret && !S_ISLNK(st.st_mode))
++ ret = __syscall(SYS_fchmodat, AT_FDCWD, proc, mode);
+
+ __syscall(SYS_close, fd2);
+ return __syscall_ret(ret);
+diff --git a/src/stat/fstat.c b/src/stat/fstat.c
+index b561176..a928986 100644
+--- a/src/stat/fstat.c
++++ b/src/stat/fstat.c
+@@ -14,7 +14,11 @@ int fstat(int fd, struct stat *st)
+
+ char buf[15+3*sizeof(int)];
+ __procfdname(buf, fd);
++#ifdef SYS_stat
+ return syscall(SYS_stat, buf, st);
++#else
++ return syscall(SYS_fstatat, AT_FDCWD, buf, st);
++#endif
+ }
+
+ LFS64(fstat);
+diff --git a/src/stat/futimesat.c b/src/stat/futimesat.c
+index dbefc84..b4eea1d 100644
+--- a/src/stat/futimesat.c
++++ b/src/stat/futimesat.c
+@@ -1,10 +1,23 @@
+ #define _GNU_SOURCE
+ #include <sys/time.h>
++#include <sys/stat.h>
++#include <errno.h>
+ #include "syscall.h"
++#include "libc.h"
+
+-#ifdef SYS_futimesat
+-int futimesat(int dirfd, const char *pathname, const struct timeval times[2])
++int __futimesat(int dirfd, const char *pathname, const struct timeval times[2])
+ {
+- return syscall(SYS_futimesat, dirfd, pathname, times);
++ struct timespec ts[2];
++ if (times) {
++ int i;
++ for (i=0; i<2; i++) {
++ if (times[i].tv_usec >= 1000000ULL)
++ return __syscall_ret(-EINVAL);
++ ts[i].tv_sec = times[i].tv_sec;
++ ts[i].tv_nsec = times[i].tv_usec * 1000;
++ }
++ }
++ return utimensat(dirfd, pathname, times ? ts : 0, 0);
+ }
+-#endif
++
++weak_alias(__futimesat, futimesat);
+diff --git a/src/stat/lstat.c b/src/stat/lstat.c
+index 8f60358..5e8b84f 100644
+--- a/src/stat/lstat.c
++++ b/src/stat/lstat.c
+@@ -1,10 +1,15 @@
+ #include <sys/stat.h>
++#include <fcntl.h>
+ #include "syscall.h"
+ #include "libc.h"
+
+ int lstat(const char *restrict path, struct stat *restrict buf)
+ {
++#ifdef SYS_lstat
+ return syscall(SYS_lstat, path, buf);
++#else
++ return syscall(SYS_fstatat, AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW);
++#endif
+ }
+
+ LFS64(lstat);
+diff --git a/src/stat/mkdir.c b/src/stat/mkdir.c
+index 770e1cc..32625b7 100644
+--- a/src/stat/mkdir.c
++++ b/src/stat/mkdir.c
+@@ -1,7 +1,12 @@
+ #include <sys/stat.h>
++#include <fcntl.h>
+ #include "syscall.h"
+
+ int mkdir(const char *path, mode_t mode)
+ {
++#ifdef SYS_mkdir
+ return syscall(SYS_mkdir, path, mode);
++#else
++ return syscall(SYS_mkdirat, AT_FDCWD, path, mode);
++#endif
+ }
+diff --git a/src/stat/mknod.c b/src/stat/mknod.c
+index c319657..beebd84 100644
+--- a/src/stat/mknod.c
++++ b/src/stat/mknod.c
+@@ -1,7 +1,12 @@
+ #include <sys/stat.h>
++#include <fcntl.h>
+ #include "syscall.h"
+
+ int mknod(const char *path, mode_t mode, dev_t dev)
+ {
++#ifdef SYS_mknod
+ return syscall(SYS_mknod, path, mode, dev);
++#else
++ return syscall(SYS_mknodat, AT_FDCWD, path, mode, dev);
++#endif
+ }
+diff --git a/src/stat/stat.c b/src/stat/stat.c
+index c6de716..b4433a0 100644
+--- a/src/stat/stat.c
++++ b/src/stat/stat.c
+@@ -1,10 +1,15 @@
+ #include <sys/stat.h>
++#include <fcntl.h>
+ #include "syscall.h"
+ #include "libc.h"
+
+ int stat(const char *restrict path, struct stat *restrict buf)
+ {
++#ifdef SYS_stat
+ return syscall(SYS_stat, path, buf);
++#else
++ return syscall(SYS_fstatat, AT_FDCWD, path, buf, 0);
++#endif
+ }
+
+ LFS64(stat);
+diff --git a/src/stat/utimensat.c b/src/stat/utimensat.c
+index 929698b..159c8be 100644
+--- a/src/stat/utimensat.c
++++ b/src/stat/utimensat.c
+@@ -1,7 +1,37 @@
+ #include <sys/stat.h>
++#include <sys/time.h>
++#include <fcntl.h>
++#include <errno.h>
+ #include "syscall.h"
+
+ int utimensat(int fd, const char *path, const struct timespec times[2], int flags)
+ {
+- return syscall(SYS_utimensat, fd, path, times, flags);
++ int r = __syscall(SYS_utimensat, fd, path, times, flags);
++#ifdef SYS_futimesat
++ if (r != -ENOSYS || flags) return __syscall_ret(r);
++ struct timeval *tv = 0, tmp[2];
++ if (times) {
++ int i;
++ tv = tmp;
++ for (i=0; i<2; i++) {
++ if (times[i].tv_nsec >= 1000000000ULL) {
++ if (times[i].tv_nsec == UTIME_NOW &&
++ times[1-i].tv_nsec == UTIME_NOW) {
++ tv = 0;
++ break;
++ }
++ if (times[i].tv_nsec == UTIME_OMIT)
++ return __syscall_ret(-ENOSYS);
++ return __syscall_ret(-EINVAL);
++ }
++ tmp[i].tv_sec = times[i].tv_sec;
++ tmp[i].tv_usec = times[i].tv_nsec / 1000;
++ }
++ }
++
++ r = __syscall(SYS_futimesat, fd, path, tv);
++ if (r != -ENOSYS || fd != AT_FDCWD) return __syscall_ret(r);
++ r = __syscall(SYS_utimes, path, tv);
++#endif
++ return __syscall_ret(r);
+ }
+diff --git a/src/stdio/__fopen_rb_ca.c b/src/stdio/__fopen_rb_ca.c
+index 9202c8c..b72c630 100644
+--- a/src/stdio/__fopen_rb_ca.c
++++ b/src/stdio/__fopen_rb_ca.c
+@@ -6,7 +6,7 @@ FILE *__fopen_rb_ca(const char *filename, FILE *f, unsigned char *buf, size_t le
+ {
+ memset(f, 0, sizeof *f);
+
+- f->fd = syscall(SYS_open, filename, O_RDONLY|O_LARGEFILE|O_CLOEXEC, 0);
++ f->fd = sys_open(filename, O_RDONLY|O_CLOEXEC);
+ if (f->fd < 0) return 0;
+
+ f->flags = F_NOWR | F_PERM;
+diff --git a/src/stdio/fopen.c b/src/stdio/fopen.c
+index da17ce8..3d97cfa 100644
+--- a/src/stdio/fopen.c
++++ b/src/stdio/fopen.c
+@@ -18,7 +18,7 @@ FILE *fopen(const char *restrict filename, const char *restrict mode)
+ /* Compute the flags to pass to open() */
+ flags = __fmodeflags(mode);
+
+- fd = syscall_cp(SYS_open, filename, flags|O_LARGEFILE, 0666);
++ fd = sys_open_cp(filename, flags, 0666);
+ if (fd < 0) return 0;
+
+ f = __fdopen(fd, mode);
+diff --git a/src/stdio/remove.c b/src/stdio/remove.c
+index e147ba2..942e301 100644
+--- a/src/stdio/remove.c
++++ b/src/stdio/remove.c
+@@ -1,9 +1,19 @@
+ #include <stdio.h>
+ #include <errno.h>
++#include <fcntl.h>
+ #include "syscall.h"
+
+ int remove(const char *path)
+ {
+- int r = syscall(SYS_unlink, path);
+- return (r && errno == EISDIR) ? syscall(SYS_rmdir, path) : r;
++#ifdef SYS_unlink
++ int r = __syscall(SYS_unlink, path);
++#else
++ int r = __syscall(SYS_unlinkat, AT_FDCWD, path, 0);
++#endif
++#ifdef SYS_rmdir
++ if (r==-EISDIR) r = __syscall(SYS_rmdir, path);
++#else
++ if (r==-EISDIR) r = __syscall(SYS_unlinkat, AT_FDCWD, path, AT_REMOVEDIR);
++#endif
++ return __syscall_ret(r);
+ }
+diff --git a/src/stdio/rename.c b/src/stdio/rename.c
+index 97f1453..04c90c0 100644
+--- a/src/stdio/rename.c
++++ b/src/stdio/rename.c
+@@ -1,7 +1,12 @@
+ #include <stdio.h>
++#include <fcntl.h>
+ #include "syscall.h"
+
+ int rename(const char *old, const char *new)
+ {
++#ifdef SYS_rename
+ return syscall(SYS_rename, old, new);
++#else
++ return syscall(SYS_renameat, AT_FDCWD, old, AT_FDCWD, new);
++#endif
+ }
+diff --git a/src/stdio/tempnam.c b/src/stdio/tempnam.c
+index f73ca9f..45a5f26 100644
+--- a/src/stdio/tempnam.c
++++ b/src/stdio/tempnam.c
+@@ -1,42 +1,48 @@
+ #include <stdio.h>
++#include <fcntl.h>
++#include <errno.h>
++#include <sys/stat.h>
++#include <limits.h>
+ #include <string.h>
+-#include <stdlib.h>
+-#include <stdint.h>
+-#include <unistd.h>
+-#include <time.h>
+-#include "libc.h"
+-#include "atomic.h"
++#include "syscall.h"
+
+ #define MAXTRIES 100
+
++char *__randname(char *);
++
+ char *tempnam(const char *dir, const char *pfx)
+ {
+- static int index;
+- char *s;
+- struct timespec ts;
+- int pid = getpid();
+- size_t l;
+- int n;
+- int try=0;
++ char s[PATH_MAX];
++ size_t l, dl, pl;
++ int try;
++ int r;
+
+ if (!dir) dir = P_tmpdir;
+ if (!pfx) pfx = "temp";
+
+- if (access(dir, R_OK|W_OK|X_OK) != 0)
+- return NULL;
+-
+- l = strlen(dir) + 1 + strlen(pfx) + 3*(sizeof(int)*3+2) + 1;
+- s = malloc(l);
+- if (!s) return s;
++ dl = strlen(dir);
++ pl = strlen(pfx);
++ l = dl + 1 + pl + 1 + 6;
+
+- do {
+- clock_gettime(CLOCK_REALTIME, &ts);
+- n = ts.tv_nsec ^ (uintptr_t)&s ^ (uintptr_t)s;
+- snprintf(s, l, "%s/%s-%d-%d-%x", dir, pfx, pid, a_fetch_add(&index, 1), n);
+- } while (!access(s, F_OK) && try++<MAXTRIES);
+- if (try>=MAXTRIES) {
+- free(s);
++ if (l >= PATH_MAX) {
++ errno = ENAMETOOLONG;
+ return 0;
+ }
+- return s;
++
++ memcpy(s, dir, dl);
++ s[dl] = '/';
++ memcpy(s+dl+1, pfx, pl);
++ s[dl+1+pl] = '_';
++
++ for (try=0; try<MAXTRIES; try++) {
++ __randname(s+l-6);
++#ifdef SYS_lstat
++ r = __syscall(SYS_lstat, s, &(struct stat){0});
++#else
++ r = __syscall(SYS_fstatat, AT_FDCWD, s,
++ &(struct stat){0}, AT_SYMLINK_NOFOLLOW);
++#endif
++ if (r == -ENOENT) return strdup(s);
++ }
++ return 0;
+ }
+diff --git a/src/stdio/tmpfile.c b/src/stdio/tmpfile.c
+index 926d660..a7d0000 100644
+--- a/src/stdio/tmpfile.c
++++ b/src/stdio/tmpfile.c
+@@ -1,23 +1,27 @@
+ #include <stdio.h>
+ #include <fcntl.h>
+-#include <unistd.h>
+ #include "stdio_impl.h"
+
+ #define MAXTRIES 100
+
++char *__randname(char *);
++
+ FILE *tmpfile(void)
+ {
+- char buf[L_tmpnam], *s;
++ char s[] = "/tmp/tmpfile_XXXXXX";
+ int fd;
+ FILE *f;
+ int try;
+ for (try=0; try<MAXTRIES; try++) {
+- s = tmpnam(buf);
+- if (!s) return 0;
+- fd = syscall(SYS_open, s, O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600);
++ __randname(s+13);
++ fd = sys_open(s, O_RDWR|O_CREAT|O_EXCL, 0600);
+ if (fd >= 0) {
+ f = __fdopen(fd, "w+");
++#ifdef SYS_unlink
+ __syscall(SYS_unlink, s);
++#else
++ __syscall(SYS_unlinkat, AT_FDCWD, s, 0);
++#endif
+ return f;
+ }
+ }
+diff --git a/src/stdio/tmpnam.c b/src/stdio/tmpnam.c
+index 2bd72b3..449eb9b 100644
+--- a/src/stdio/tmpnam.c
++++ b/src/stdio/tmpnam.c
+@@ -1,31 +1,29 @@
+ #include <stdio.h>
+-#include <stdlib.h>
+-#include <stdint.h>
+-#include <unistd.h>
+-#include <time.h>
+-#include "libc.h"
++#include <fcntl.h>
++#include <errno.h>
++#include <sys/stat.h>
++#include <string.h>
+ #include "syscall.h"
+-#include "atomic.h"
+
+ #define MAXTRIES 100
+
+-char *tmpnam(char *s)
+-{
+- static int index;
+- static char s2[L_tmpnam];
+- struct timespec ts;
+- int try = 0;
+- unsigned n;
+-
+- if (!s) s = s2;
++char *__randname(char *);
+
+- if (__syscall(SYS_access, P_tmpdir, R_OK|W_OK|X_OK) != 0)
+- return NULL;
+-
+- do {
+- __syscall(SYS_clock_gettime, CLOCK_REALTIME, &ts, 0);
+- n = ts.tv_nsec ^ (uintptr_t)&s ^ (uintptr_t)s;
+- snprintf(s, L_tmpnam, "/tmp/t%x-%x", a_fetch_add(&index, 1), n);
+- } while (!__syscall(SYS_access, s, F_OK) && try++<MAXTRIES);
+- return try>=MAXTRIES ? 0 : s;
++char *tmpnam(char *buf)
++{
++ static char internal[L_tmpnam];
++ char s[] = "/tmp/tmpnam_XXXXXX";
++ int try;
++ int r;
++ for (try=0; try<MAXTRIES; try++) {
++ __randname(s+12);
++#ifdef SYS_lstat
++ r = __syscall(SYS_lstat, s, &(struct stat){0});
++#else
++ r = __syscall(SYS_fstatat, AT_FDCWD, s,
++ &(struct stat){0}, AT_SYMLINK_NOFOLLOW);
++#endif
++ if (r == -ENOENT) return strcpy(buf ? buf : internal, s);
++ }
++ return 0;
+ }
+diff --git a/src/stdio/vfprintf.c b/src/stdio/vfprintf.c
+index f6e7f38..ea25772 100644
+--- a/src/stdio/vfprintf.c
++++ b/src/stdio/vfprintf.c
+@@ -13,8 +13,6 @@
+
+ #define MAX(a,b) ((a)>(b) ? (a) : (b))
+ #define MIN(a,b) ((a)<(b) ? (a) : (b))
+-#define CONCAT2(x,y) x ## y
+-#define CONCAT(x,y) CONCAT2(x,y)
+
+ /* Convenient bit representation for modifier flags, which all fall
+ * within 31 codepoints of the space character. */
+@@ -343,7 +341,7 @@ static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t)
+ x = *d % i;
+ /* Are there any significant digits past j? */
+ if (x || d+1!=z) {
+- long double round = CONCAT(0x1p,LDBL_MANT_DIG);
++ long double round = 2/LDBL_EPSILON;
+ long double small;
+ if (*d/i & 1) round += 2;
+ if (x<i/2) small=0x0.8p0;
+diff --git a/src/time/__map_file.c b/src/time/__map_file.c
+index 84ae839..d06a581 100644
+--- a/src/time/__map_file.c
++++ b/src/time/__map_file.c
+@@ -9,8 +9,7 @@ const char unsigned *__map_file(const char *pathname, size_t *size)
+ {
+ struct stat st;
+ const unsigned char *map = MAP_FAILED;
+- int flags = O_RDONLY|O_LARGEFILE|O_CLOEXEC|O_NONBLOCK;
+- int fd = __syscall(SYS_open, pathname, flags);
++ int fd = __sys_open(pathname, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
+ if (fd < 0) return 0;
+ if (!__syscall(SYS_fstat, fd, &st))
+ map = __mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+diff --git a/src/time/utime.c b/src/time/utime.c
+index b2b5741..e7592b2 100644
+--- a/src/time/utime.c
++++ b/src/time/utime.c
+@@ -1,14 +1,11 @@
+ #include <utime.h>
+-#include <sys/time.h>
+-#include "syscall.h"
++#include <sys/stat.h>
++#include <time.h>
++#include <fcntl.h>
+
+ int utime(const char *path, const struct utimbuf *times)
+ {
+- if (times) {
+- struct timeval tv[2] = {
+- { .tv_sec = times->actime },
+- { .tv_sec = times->modtime } };
+- return syscall(SYS_utimes, path, tv);
+- }
+- return syscall(SYS_utimes, path, 0);
++ return utimensat(AT_FDCWD, path, times ? ((struct timespec [2]){
++ { .tv_sec = times->actime }, { .tv_sec = times->modtime }})
++ : 0, 0);
+ }
+diff --git a/src/unistd/access.c b/src/unistd/access.c
+index e7ce73a..d6eed68 100644
+--- a/src/unistd/access.c
++++ b/src/unistd/access.c
+@@ -1,7 +1,12 @@
+ #include <unistd.h>
++#include <fcntl.h>
+ #include "syscall.h"
+
+ int access(const char *filename, int amode)
+ {
++#ifdef SYS_access
+ return syscall(SYS_access, filename, amode);
++#else
++ return syscall(SYS_faccessat, AT_FDCWD, filename, amode, 0);
++#endif
+ }
+diff --git a/src/unistd/chown.c b/src/unistd/chown.c
+index 95f6f61..14b0325 100644
+--- a/src/unistd/chown.c
++++ b/src/unistd/chown.c
+@@ -1,7 +1,12 @@
+ #include <unistd.h>
++#include <fcntl.h>
+ #include "syscall.h"
+
+ int chown(const char *path, uid_t uid, gid_t gid)
+ {
++#ifdef SYS_chown
+ return syscall(SYS_chown, path, uid, gid);
++#else
++ return syscall(SYS_fchownat, AT_FDCWD, path, uid, gid, 0);
++#endif
+ }
+diff --git a/src/unistd/dup2.c b/src/unistd/dup2.c
+index 87a0d44..8f43c6d 100644
+--- a/src/unistd/dup2.c
++++ b/src/unistd/dup2.c
+@@ -1,10 +1,20 @@
+ #include <unistd.h>
+ #include <errno.h>
++#include <fcntl.h>
+ #include "syscall.h"
+
+ int dup2(int old, int new)
+ {
+ int r;
++#ifdef SYS_dup2
+ while ((r=__syscall(SYS_dup2, old, new))==-EBUSY);
++#else
++ if (old==new) {
++ r = __syscall(SYS_fcntl, old, F_GETFD);
++ if (r >= 0) return old;
++ } else {
++ while ((r=__syscall(SYS_dup3, old, new, 0))==-EBUSY);
++ }
++#endif
+ return __syscall_ret(r);
+ }
+diff --git a/src/unistd/dup3.c b/src/unistd/dup3.c
+index 1f7134b..0eb6caf 100644
+--- a/src/unistd/dup3.c
++++ b/src/unistd/dup3.c
+@@ -8,6 +8,7 @@
+ int __dup3(int old, int new, int flags)
+ {
+ int r;
++#ifdef SYS_dup2
+ if (old==new) return __syscall_ret(-EINVAL);
+ if (flags & O_CLOEXEC) {
+ while ((r=__syscall(SYS_dup3, old, new, flags))==-EBUSY);
+@@ -15,6 +16,9 @@ int __dup3(int old, int new, int flags)
+ }
+ while ((r=__syscall(SYS_dup2, old, new))==-EBUSY);
+ if (flags & O_CLOEXEC) __syscall(SYS_fcntl, new, F_SETFD, FD_CLOEXEC);
++#else
++ while ((r=__syscall(SYS_dup3, old, new, flags))==-EBUSY);
++#endif
+ return __syscall_ret(r);
+ }
+
+diff --git a/src/unistd/fchown.c b/src/unistd/fchown.c
+index 36633b0..0345984 100644
+--- a/src/unistd/fchown.c
++++ b/src/unistd/fchown.c
+@@ -13,5 +13,10 @@ int fchown(int fd, uid_t uid, gid_t gid)
+
+ char buf[15+3*sizeof(int)];
+ __procfdname(buf, fd);
++#ifdef SYS_chown
+ return syscall(SYS_chown, buf, uid, gid);
++#else
++ return syscall(SYS_fchownat, AT_FDCWD, buf, uid, gid);
++#endif
++
+ }
+diff --git a/src/unistd/getpgrp.c b/src/unistd/getpgrp.c
+index 433f42e..90e9bb0 100644
+--- a/src/unistd/getpgrp.c
++++ b/src/unistd/getpgrp.c
+@@ -3,5 +3,5 @@
+
+ pid_t getpgrp(void)
+ {
+- return __syscall(SYS_getpgrp);
++ return __syscall(SYS_getpgid, 0);
+ }
+diff --git a/src/unistd/lchown.c b/src/unistd/lchown.c
+index de871ae..ccd5ee0 100644
+--- a/src/unistd/lchown.c
++++ b/src/unistd/lchown.c
+@@ -1,7 +1,12 @@
+ #include <unistd.h>
++#include <fcntl.h>
+ #include "syscall.h"
+
+ int lchown(const char *path, uid_t uid, gid_t gid)
+ {
++#ifdef SYS_lchown
+ return syscall(SYS_lchown, path, uid, gid);
++#else
++ return syscall(SYS_fchownat, AT_FDCWD, path, uid, gid, AT_SYMLINK_NOFOLLOW);
++#endif
+ }
+diff --git a/src/unistd/link.c b/src/unistd/link.c
+index 20193f2..feec18e 100644
+--- a/src/unistd/link.c
++++ b/src/unistd/link.c
+@@ -1,7 +1,12 @@
+ #include <unistd.h>
++#include <fcntl.h>
+ #include "syscall.h"
+
+ int link(const char *existing, const char *new)
+ {
++#ifdef SYS_link
+ return syscall(SYS_link, existing, new);
++#else
++ return syscall(SYS_linkat, AT_FDCWD, existing, AT_FDCWD, new, 0);
++#endif
+ }
+diff --git a/src/unistd/pause.c b/src/unistd/pause.c
+index f7ed17d..56eb171 100644
+--- a/src/unistd/pause.c
++++ b/src/unistd/pause.c
+@@ -1,8 +1,13 @@
+ #include <unistd.h>
++#include <signal.h>
+ #include "syscall.h"
+ #include "libc.h"
+
+ int pause(void)
+ {
++#ifdef SYS_pause
+ return syscall_cp(SYS_pause);
++#else
++ return syscall_cp(SYS_ppoll, 0, 0, 0, 0);
++#endif
+ }
+diff --git a/src/unistd/pipe.c b/src/unistd/pipe.c
+index 36c6f13..d07b8d2 100644
+--- a/src/unistd/pipe.c
++++ b/src/unistd/pipe.c
+@@ -3,5 +3,9 @@
+
+ int pipe(int fd[2])
+ {
++#ifdef SYS_pipe
+ return syscall(SYS_pipe, fd);
++#else
++ return syscall(SYS_pipe2, fd, 0);
++#endif
+ }
+diff --git a/src/unistd/readlink.c b/src/unistd/readlink.c
+index ec291e3..a152d52 100644
+--- a/src/unistd/readlink.c
++++ b/src/unistd/readlink.c
+@@ -1,7 +1,12 @@
+ #include <unistd.h>
++#include <fcntl.h>
+ #include "syscall.h"
+
+ ssize_t readlink(const char *restrict path, char *restrict buf, size_t bufsize)
+ {
++#ifdef SYS_readlink
+ return syscall(SYS_readlink, path, buf, bufsize);
++#else
++ return syscall(SYS_readlinkat, AT_FDCWD, path, buf, bufsize);
++#endif
+ }
+diff --git a/src/unistd/rmdir.c b/src/unistd/rmdir.c
+index dfe1605..6825ffc 100644
+--- a/src/unistd/rmdir.c
++++ b/src/unistd/rmdir.c
+@@ -1,7 +1,12 @@
+ #include <unistd.h>
++#include <fcntl.h>
+ #include "syscall.h"
+
+ int rmdir(const char *path)
+ {
++#ifdef SYS_rmdir
+ return syscall(SYS_rmdir, path);
++#else
++ return syscall(SYS_unlinkat, AT_FDCWD, path, AT_REMOVEDIR);
++#endif
+ }
+diff --git a/src/unistd/symlink.c b/src/unistd/symlink.c
+index 5902d45..0973d78 100644
+--- a/src/unistd/symlink.c
++++ b/src/unistd/symlink.c
+@@ -1,7 +1,12 @@
+ #include <unistd.h>
++#include <fcntl.h>
+ #include "syscall.h"
+
+ int symlink(const char *existing, const char *new)
+ {
++#ifdef SYS_symlink
+ return syscall(SYS_symlink, existing, new);
++#else
++ return syscall(SYS_symlinkat, existing, AT_FDCWD, new);
++#endif
+ }
+diff --git a/src/unistd/unlink.c b/src/unistd/unlink.c
+index bdb37be..c40c28d 100644
+--- a/src/unistd/unlink.c
++++ b/src/unistd/unlink.c
+@@ -1,7 +1,12 @@
+ #include <unistd.h>
++#include <fcntl.h>
+ #include "syscall.h"
+
+ int unlink(const char *path)
+ {
++#ifdef SYS_unlink
+ return syscall(SYS_unlink, path);
++#else
++ return syscall(SYS_unlinkat, AT_FDCWD, path, 0);
++#endif
+ }
diff --git a/main/musl/APKBUILD b/main/musl/APKBUILD
index 3855104852..f44f100d7c 100644
--- a/main/musl/APKBUILD
+++ b/main/musl/APKBUILD
@@ -2,7 +2,7 @@
# Maintainer: Timo Teräs <timo.teras@iki.fi>
pkgname=musl
pkgver=1.1.1
-pkgrel=0
+pkgrel=1
pkgdesc="the musl c library (libc) implementation"
url="http://www.musl-libc.org/"
arch="all"
@@ -12,8 +12,8 @@ depends_dev="!uclibc-dev"
makedepends="$depends_dev"
install=""
subpackages="$pkgname-dev $pkgname-utils"
-[ "${CTARGET#*musl}" = "$CTARGET" ] && subpackages="$subpackages musl-gcc:crosstool"
source="http://www.musl-libc.org/releases/musl-$pkgver.tar.gz
+ 0001-v1.1.1-to-76f440cf.patch
1001-add-basic-dns-record-parsing-functions.patch
1002-reimplement-if_nameindex-and-getifaddrs-using-netlin.patch
1003-implement-y-and-C-specifiers-in-strptime.patch
@@ -118,14 +118,8 @@ utils() {
install -D -m755 "$srcdir"/ldconfig "$subpkgdir"/sbin
}
-crosstool() {
- mkdir -p "$subpkgdir"/usr/bin "$subpkgdir"/usr/lib
- mv "$pkgdir"/usr/bin/musl-gcc "$subpkgdir"/usr/bin
- mv "$pkgdir"/usr/lib/musl-gcc.specs "$subpkgdir"/usr/lib
- find "$pkgdir" -type d -delete 2>/dev/null
-}
-
md5sums="dbc08d311148e095016d9bbf6c7ffda6 musl-1.1.1.tar.gz
+d4a40fe1656115b2956065ab48e0b372 0001-v1.1.1-to-76f440cf.patch
a3810683ef61ac27e2f6ec9801280c81 1001-add-basic-dns-record-parsing-functions.patch
83c3bd2a50b1de5ef948704d3f4e0583 1002-reimplement-if_nameindex-and-getifaddrs-using-netlin.patch
fc3feec4104a4b25781df92dd96b9eec 1003-implement-y-and-C-specifiers-in-strptime.patch
@@ -137,6 +131,7 @@ cb82d21fed17a116b44b830adba71c5a getconf.c
2b941c4251cac44988a4abfc50e21267 getent.c
45f92f8d59cf84d765de698a9578dbf4 iconv.c"
sha256sums="9dd75d6512e44d5a13254e246db56c90365894b05bab2b1127e44a31e4fd7c36 musl-1.1.1.tar.gz
+40f241a8aa59621d8a9e6a616df27c38e0a622243bf7346cc98ec1c37454e92a 0001-v1.1.1-to-76f440cf.patch
758390768b1bc4159d56908ca332b9640cd0552ed3b4b2b8d4a6d499c54c11a1 1001-add-basic-dns-record-parsing-functions.patch
1c25880095e869b827f02997e864fdf4bf157a4e923e52d97dbd05e657aedb70 1002-reimplement-if_nameindex-and-getifaddrs-using-netlin.patch
c22338bc33e8c0c22b280c392b37a0903e13562e671f5ebade09ed5b1d33e2ae 1003-implement-y-and-C-specifiers-in-strptime.patch
@@ -148,6 +143,7 @@ d9b644ec20bc33e81a7c52b9fcf7973d835923a69faf50f03db45534b811bd96 getopt_long.c
68373a55e89ce85c562d941ccf588337d6cc6c9c17689d695f65cd7607134bbe getent.c
f79a2930a2e5bb0624321589edf8b889d1e9b603e01e6b7ae214616605b3fdd7 iconv.c"
sha512sums="5182deb80a35c8a4009d71098c95a16e5ab9bd03186443917652f0c521d2980183e203256493a69e8230b6a0c4848ca8e44de9e8c851a511cd37d0d41f91b14f musl-1.1.1.tar.gz
+30906a5f7a01ff05693e5a2e72f6c7e75ff7939c28a32b9e777d14d59412bb9df603a09aa8dd693e9a0b70525474a62f7bc657425032a3a5f4b339667e6f62ec 0001-v1.1.1-to-76f440cf.patch
dad965258daf69371b844f76bfe5a914b0eca0ca76f3fc340b8fd7acf598b5f87bbe6d68b1f43ed0293ee0ed3bfd85d5173ccc169aa6265646248d5b8a906708 1001-add-basic-dns-record-parsing-functions.patch
72cf33738d2cf31f6ec02312bc494d754c17470b519172bb8bd7e2e29ac3b119023088a2b3fbc0dbc2fddd0078ccbae62096106cae361f8c31d6a9950043af25 1002-reimplement-if_nameindex-and-getifaddrs-using-netlin.patch
48082d2348de40bc6b455266c5552a62e1e75f926e69116c61c8a3cb35fefdff136dc771bf25ee7d43c959834921221112ed7afcc45fcadbcf07562510786916 1003-implement-y-and-C-specifiers-in-strptime.patch