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 +#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 #include #include +#include #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 #include #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 -#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 #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 #include +#include #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 #include +#include #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 +#include #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 +#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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> 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= 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 - -#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 -#include -#include -#include -#include -#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 + +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 -#include -#include -#include #include -#include +#include +#include #include -#include -#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; iai; - 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; iai; - + 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 #include #include +#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; ih_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 #include #include -#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 #include #include +#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 #include #include -#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 +#include +#include +#include +#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 #include #include -#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 + +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 +#include +#include +#include +#include +#include +#include +#include +#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 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 +#include +#include +#include +#include +#include +#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 + 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 +#include +#include +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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= retry_interval) { + /* Query all configured namservers in parallel */ + for (i=0; i= 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 #include -#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 +#include + +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 +#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 #include +#include #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 +#include #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 +#include +#include #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 #include +#include #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 +#include +#include +#include #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 +#include #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 +#include +#include #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 +#include #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 +#include #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 +#include #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 +#include #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 +#include +#include +#include #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 #include +#include #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 +#include #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 +#include +#include +#include +#include #include -#include -#include -#include -#include -#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) { - 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 #include -#include #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= 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 -#include -#include -#include -#include -#include "libc.h" +#include +#include +#include +#include #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 ? 0 : s; +char *tmpnam(char *buf) +{ + static char internal[L_tmpnam]; + char s[] = "/tmp/tmpnam_XXXXXX"; + int try; + int r; + for (try=0; try(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 -#include -#include "syscall.h" +#include +#include +#include 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 +#include #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 +#include #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 #include +#include #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 +#include #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 +#include #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 +#include #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 +#include #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 +#include #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 +#include #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 +#include #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 }