diff options
-rw-r--r-- | main/musl/0001-v1.1.1-to-76f440cf.patch | 3459 | ||||
-rw-r--r-- | main/musl/APKBUILD | 14 |
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 |