diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT index bd3e4d4e5..d698133a3 100644 --- a/libc/SYSCALLS.TXT +++ b/libc/SYSCALLS.TXT @@ -174,6 +174,7 @@ int __timer_gettime:timer_gettime(timer_t, struct itimerspec*) int __timer_getoverrun:timer_getoverrun(timer_t) 260,262 int __timer_delete:timer_delete(timer_t) 261,263 int utimes(const char*, const struct timeval tvp[2]) 269, 271 +int utimensat(int, const char *, const struct timespec times[2], int) 348, 320, 320 # signals int sigaction(int, const struct sigaction *, struct sigaction *) 67 diff --git a/libc/arch-arm/syscalls.mk b/libc/arch-arm/syscalls.mk index 5210d6c39..e6c84f60f 100644 --- a/libc/arch-arm/syscalls.mk +++ b/libc/arch-arm/syscalls.mk @@ -124,6 +124,7 @@ syscall_src += arch-arm/syscalls/__timer_gettime.S syscall_src += arch-arm/syscalls/__timer_getoverrun.S syscall_src += arch-arm/syscalls/__timer_delete.S syscall_src += arch-arm/syscalls/utimes.S +syscall_src += arch-arm/syscalls/utimensat.S syscall_src += arch-arm/syscalls/sigaction.S syscall_src += arch-arm/syscalls/sigprocmask.S syscall_src += arch-arm/syscalls/__sigsuspend.S diff --git a/libc/arch-arm/syscalls/utimensat.S b/libc/arch-arm/syscalls/utimensat.S new file mode 100644 index 000000000..ceae7fafd --- /dev/null +++ b/libc/arch-arm/syscalls/utimensat.S @@ -0,0 +1,14 @@ +/* autogenerated by gensyscalls.py */ +#include +#include + +ENTRY(utimensat) + .save {r4, r7} + stmfd sp!, {r4, r7} + ldr r7, =__NR_utimensat + swi #0 + ldmfd sp!, {r4, r7} + movs r0, r0 + bxpl lr + b __set_syscall_errno +END(utimensat) diff --git a/libc/arch-sh/syscalls.mk b/libc/arch-sh/syscalls.mk index 9575905f9..1d8760087 100644 --- a/libc/arch-sh/syscalls.mk +++ b/libc/arch-sh/syscalls.mk @@ -127,6 +127,7 @@ syscall_src += arch-sh/syscalls/__timer_gettime.S syscall_src += arch-sh/syscalls/__timer_getoverrun.S syscall_src += arch-sh/syscalls/__timer_delete.S syscall_src += arch-sh/syscalls/utimes.S +syscall_src += arch-sh/syscalls/utimensat.S syscall_src += arch-sh/syscalls/sigaction.S syscall_src += arch-sh/syscalls/sigprocmask.S syscall_src += arch-sh/syscalls/__sigsuspend.S diff --git a/libc/arch-sh/syscalls/utimensat.S b/libc/arch-sh/syscalls/utimensat.S new file mode 100644 index 000000000..28e7ec643 --- /dev/null +++ b/libc/arch-sh/syscalls/utimensat.S @@ -0,0 +1,32 @@ +/* autogenerated by gensyscalls.py */ +#include + + .text + .type utimensat, @function + .globl utimensat + .align 4 + +utimensat: + + /* invoke trap */ + mov.l 0f, r3 /* trap num */ + trapa #(4 + 0x10) + + /* check return value */ + cmp/pz r0 + bt __NR_utimensat_end + + /* keep error number */ + sts.l pr, @-r15 + mov.l 1f, r1 + jsr @r1 + mov r0, r4 + lds.l @r15+, pr + +__NR_utimensat_end: + rts + nop + + .align 2 +0: .long __NR_utimensat +1: .long __set_syscall_errno diff --git a/libc/arch-x86/syscalls.mk b/libc/arch-x86/syscalls.mk index e8c6a77d2..3b85025dd 100644 --- a/libc/arch-x86/syscalls.mk +++ b/libc/arch-x86/syscalls.mk @@ -127,6 +127,7 @@ syscall_src += arch-x86/syscalls/__timer_gettime.S syscall_src += arch-x86/syscalls/__timer_getoverrun.S syscall_src += arch-x86/syscalls/__timer_delete.S syscall_src += arch-x86/syscalls/utimes.S +syscall_src += arch-x86/syscalls/utimensat.S syscall_src += arch-x86/syscalls/sigaction.S syscall_src += arch-x86/syscalls/sigprocmask.S syscall_src += arch-x86/syscalls/__sigsuspend.S diff --git a/libc/arch-x86/syscalls/utimensat.S b/libc/arch-x86/syscalls/utimensat.S new file mode 100644 index 000000000..e2032b5b4 --- /dev/null +++ b/libc/arch-x86/syscalls/utimensat.S @@ -0,0 +1,32 @@ +/* autogenerated by gensyscalls.py */ +#include + + .text + .type utimensat, @function + .globl utimensat + .align 4 + +utimensat: + pushl %ebx + pushl %ecx + pushl %edx + pushl %esi + mov 20(%esp), %ebx + mov 24(%esp), %ecx + mov 28(%esp), %edx + mov 32(%esp), %esi + movl $__NR_utimensat, %eax + int $0x80 + cmpl $-129, %eax + jb 1f + negl %eax + pushl %eax + call __set_errno + addl $4, %esp + orl $-1, %eax +1: + popl %esi + popl %edx + popl %ecx + popl %ebx + ret diff --git a/libc/bionic/system_properties.c b/libc/bionic/system_properties.c index 767baa3a6..c40950fbc 100644 --- a/libc/bionic/system_properties.c +++ b/libc/bionic/system_properties.c @@ -38,13 +38,14 @@ #include #include #include +#include #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ #include #include -static const char property_service_name[] = PROP_SERVICE_NAME; +static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME; static unsigned dummy_props = 0; @@ -152,6 +153,114 @@ int __system_property_get(const char *name, char *value) } } + +static int send_prop_msg(prop_msg *msg) +{ + struct sockaddr_un addr; + socklen_t alen; + size_t namelen; + int s; + int r; + + s = socket(AF_LOCAL, SOCK_STREAM, 0); + if(s < 0) { + return -1; + } + + memset(&addr, 0, sizeof(addr)); + namelen = strlen(property_service_socket); + strlcpy(addr.sun_path, property_service_socket, sizeof addr.sun_path); + addr.sun_family = AF_LOCAL; + alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1; + + if(TEMP_FAILURE_RETRY(connect(s, (struct sockaddr *) &addr, alen) < 0)) { + close(s); + return -1; + } + + r = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg), 0)); + + if(r == sizeof(prop_msg)) { + r = 0; + } else { + r = -1; + } + + close(s); + return r; +} + +int __system_property_set(const char *key, const char *value) +{ + unsigned old_serial; + volatile unsigned *serial; + prop_msg msg; + int err; + prop_area *pa = __system_property_area__; + int tries = 0; + int update_seen = 0; + + if(key == 0) return -1; + if(value == 0) value = ""; + if(strlen(key) >= PROP_NAME_MAX) return -1; + if(strlen(value) >= PROP_VALUE_MAX) return -1; + + memset(&msg, 0, sizeof msg); + msg.cmd = PROP_MSG_SETPROP; + strlcpy(msg.name, key, sizeof msg.name); + strlcpy(msg.value, value, sizeof msg.value); + + /* Note the system properties serial number before we do our update. */ + const prop_info *pi = __system_property_find(key); + if(pi != NULL) { + serial = &pi->serial; + } else { + serial = &pa->serial; + } + old_serial = *serial; + + err = send_prop_msg(&msg); + if(err < 0) { + return err; + } + + /** + * Wait for the shared memory page to be written back and be + * visible in our address space before returning to the caller + * who might reasonably expect subsequent reads to match what was + * just written. + * + * Sleep 5 ms after failed checks and only wait up to a 500 ms + * total, just in case the system property server fails to update + * for whatever reason. + */ + do { + struct timespec timeout; + timeout.tv_sec = 0; + timeout.tv_nsec = 2500000; // 2.5 ms + + if(tries++ > 0) { + usleep(2500); // 2.5 ms + } + __futex_wait(serial, old_serial, &timeout); + if(pi != NULL) { + unsigned new_serial = *serial; + /* Waiting on a specific prop_info to be updated. */ + if (old_serial != new_serial && !SERIAL_DIRTY(new_serial)) { + update_seen = 1; + } + } else { + /* Waiting for a prop_info to be created. */ + const prop_info *new_pi = __system_property_find(key); + if(new_pi != NULL && !SERIAL_DIRTY(new_pi->serial)) { + update_seen = 1; + } + } + } while (!update_seen && tries < 100); + + return 0; +} + int __system_property_wait(const prop_info *pi) { unsigned n; diff --git a/libc/include/sys/linux-syscalls.h b/libc/include/sys/linux-syscalls.h index 5b8e2b48d..7b74a4b82 100644 --- a/libc/include/sys/linux-syscalls.h +++ b/libc/include/sys/linux-syscalls.h @@ -162,6 +162,7 @@ #define __NR_timer_getoverrun (__NR_SYSCALL_BASE + 260) #define __NR_timer_delete (__NR_SYSCALL_BASE + 261) #define __NR_utimes (__NR_SYSCALL_BASE + 269) +#define __NR_utimensat (__NR_SYSCALL_BASE + 348) #define __NR_socket (__NR_SYSCALL_BASE + 281) #define __NR_socketpair (__NR_SYSCALL_BASE + 288) #define __NR_bind (__NR_SYSCALL_BASE + 282) @@ -221,6 +222,7 @@ #define __NR_timer_getoverrun (__NR_SYSCALL_BASE + 262) #define __NR_timer_delete (__NR_SYSCALL_BASE + 263) #define __NR_utimes (__NR_SYSCALL_BASE + 271) +#define __NR_utimensat (__NR_SYSCALL_BASE + 320) #define __NR_socketcall (__NR_SYSCALL_BASE + 102) #define __NR_getcpu (__NR_SYSCALL_BASE + 318) #define __NR_ioprio_set (__NR_SYSCALL_BASE + 289) @@ -265,6 +267,7 @@ #define __NR_timer_getoverrun (__NR_SYSCALL_BASE + 262) #define __NR_timer_delete (__NR_SYSCALL_BASE + 263) #define __NR_utimes (__NR_SYSCALL_BASE + 271) +#define __NR_utimensat (__NR_SYSCALL_BASE + 320) #define __NR_socketcall (__NR_SYSCALL_BASE + 102) #define __NR_socketcall (__NR_SYSCALL_BASE + 102) #define __NR_socketcall (__NR_SYSCALL_BASE + 102) diff --git a/libc/include/sys/linux-unistd.h b/libc/include/sys/linux-unistd.h index f706d00cd..ae9077ffb 100644 --- a/libc/include/sys/linux-unistd.h +++ b/libc/include/sys/linux-unistd.h @@ -138,6 +138,7 @@ int __timer_gettime (timer_t, struct itimerspec*); int __timer_getoverrun (timer_t); int __timer_delete (timer_t); int utimes (const char*, const struct timeval tvp[2]); +int utimensat (int, const char *, const struct timespec times[2], int); int sigaction (int, const struct sigaction *, struct sigaction *); int sigprocmask (int, const sigset_t *, sigset_t *); int __sigsuspend (int unused1, int unused2, unsigned mask); diff --git a/libc/include/sys/stat.h b/libc/include/sys/stat.h index 091ee6d5e..87fcfd07d 100644 --- a/libc/include/sys/stat.h +++ b/libc/include/sys/stat.h @@ -103,6 +103,10 @@ extern int fchownat(int dirfd, const char *path, uid_t owner, gid_t group, int f extern int fchmodat(int dirfd, const char *path, mode_t mode, int flags); extern int renameat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath); +# define UTIME_NOW ((1l << 30) - 1l) +# define UTIME_OMIT ((1l << 30) - 2l) +extern int utimensat (int fd, const char *path, const struct timespec times[2], int flags); + __END_DECLS #endif /* _SYS_STAT_H_ */ diff --git a/libc/include/sys/system_properties.h b/libc/include/sys/system_properties.h index 4fdc9447f..85915b2de 100644 --- a/libc/include/sys/system_properties.h +++ b/libc/include/sys/system_properties.h @@ -46,6 +46,10 @@ typedef struct prop_info prop_info; */ int __system_property_get(const char *name, char *value); +/* Set a system property by name. +**/ +int __system_property_set(const char *key, const char *value); + /* Return a pointer to the system property named name, if it ** exists, or NULL if there is no such property. Use ** __system_property_read() to obtain the string value from diff --git a/libc/kernel/common/linux/usb/f_accessory.h b/libc/kernel/common/linux/usb/f_accessory.h index 84a89172b..7ee9b7fe7 100644 --- a/libc/kernel/common/linux/usb/f_accessory.h +++ b/libc/kernel/common/linux/usb/f_accessory.h @@ -24,15 +24,20 @@ #define USB_ACCESSORY_ADB_PRODUCT_ID 0x2D01 #define ACCESSORY_STRING_MANUFACTURER 0 #define ACCESSORY_STRING_MODEL 1 -#define ACCESSORY_STRING_TYPE 2 +#define ACCESSORY_STRING_DESCRIPTION 2 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ #define ACCESSORY_STRING_VERSION 3 +#define ACCESSORY_STRING_URI 4 +#define ACCESSORY_STRING_SERIAL 5 +#define ACCESSORY_GET_PROTOCOL 51 #define ACCESSORY_SEND_STRING 52 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ #define ACCESSORY_START 53 #define ACCESSORY_GET_STRING_MANUFACTURER _IOW('M', 1, char[256]) -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ #define ACCESSORY_GET_STRING_MODEL _IOW('M', 2, char[256]) -#define ACCESSORY_GET_STRING_TYPE _IOW('M', 3, char[256]) -#define ACCESSORY_GET_STRING_VERSION _IOW('M', 4, char[256]) -#endif +#define ACCESSORY_GET_STRING_DESCRIPTION _IOW('M', 3, char[256]) /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define ACCESSORY_GET_STRING_VERSION _IOW('M', 4, char[256]) +#define ACCESSORY_GET_STRING_URI _IOW('M', 5, char[256]) +#define ACCESSORY_GET_STRING_SERIAL _IOW('M', 6, char[256]) +#endif diff --git a/libc/netbsd/resolv/res_init.c b/libc/netbsd/resolv/res_init.c index 2158f2062..ffd4054cd 100644 --- a/libc/netbsd/resolv/res_init.c +++ b/libc/netbsd/resolv/res_init.c @@ -225,6 +225,9 @@ __res_vinit(res_state statp, int preinit) { char dnsProperty[PROP_VALUE_MAX]; #endif + if ((statp->options & RES_INIT) != 0U) + res_ndestroy(statp); + if (!preinit) { statp->retrans = RES_TIMEOUT; statp->retry = RES_DFLRETRY; @@ -232,9 +235,6 @@ __res_vinit(res_state statp, int preinit) { statp->id = res_randomid(); } - if ((statp->options & RES_INIT) != 0U) - res_ndestroy(statp); - memset(u, 0, sizeof(u)); #ifdef USELOOPBACK u[nserv].sin.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1); diff --git a/libc/netbsd/resolv/res_state.c b/libc/netbsd/resolv/res_state.c index 3209b6f1c..322ace966 100644 --- a/libc/netbsd/resolv/res_state.c +++ b/libc/netbsd/resolv/res_state.c @@ -38,21 +38,32 @@ #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ #include +/* Set to 1 to enable debug traces */ +#define DEBUG 0 + +#if DEBUG +# include +# include /* for gettid() */ +# define D(...) __libc_android_log_print(ANDROID_LOG_DEBUG,"libc", __VA_ARGS__) +#else +# define D(...) do{}while(0) +#endif + static pthread_key_t _res_key; static pthread_once_t _res_once; typedef struct { - int _h_errno; - struct __res_state _nres[1]; - unsigned _serial; - struct prop_info* _pi; - struct res_static _rstatic[1]; + int _h_errno; + struct __res_state _nres[1]; + unsigned _serial; + struct prop_info* _pi; + struct res_static _rstatic[1]; } _res_thread; static _res_thread* _res_thread_alloc(void) { - _res_thread* rt = malloc(sizeof(*rt)); + _res_thread* rt = calloc(1, sizeof(*rt)); if (rt) { rt->_h_errno = 0; @@ -62,12 +73,7 @@ _res_thread_alloc(void) if (rt->_pi) { rt->_serial = rt->_pi->serial; } - if ( res_ninit( rt->_nres ) < 0 ) { - free(rt); - rt = NULL; - } else { - memset(rt->_rstatic, 0, sizeof rt->_rstatic); - } + memset(rt->_rstatic, 0, sizeof rt->_rstatic); } return rt; } @@ -91,6 +97,8 @@ _res_thread_free( void* _rt ) { _res_thread* rt = _rt; + D("%s: rt=%p for thread=%d", __FUNCTION__, rt, gettid()); + _res_static_done(rt->_rstatic); res_ndestroy(rt->_nres); free(rt); @@ -108,27 +116,59 @@ _res_thread_get(void) _res_thread* rt; pthread_once( &_res_once, _res_init_key ); rt = pthread_getspecific( _res_key ); - if (rt == NULL) { - if ((rt = _res_thread_alloc()) == NULL) { - return NULL; + + if (rt != NULL) { + /* We already have one thread-specific DNS state object. + * Check the serial value for any changes to net.* properties */ + D("%s: Called for tid=%d rt=%p rt->pi=%p rt->serial=%d", + __FUNCTION__, gettid(), rt, rt->_pi, rt->_serial); + if (rt->_pi == NULL) { + /* The property wasn't created when _res_thread_get() was + * called the last time. This should only happen very + * early during the boot sequence. First, let's try to see if it + * is here now. */ + rt->_pi = (struct prop_info*) __system_property_find("net.change"); + if (rt->_pi == NULL) { + /* Still nothing, return current state */ + D("%s: exiting for tid=%d rt=%d since system property not found", + __FUNCTION__, gettid(), rt); + return rt; + } } - rt->_h_errno = 0; - rt->_serial = 0; - pthread_setspecific( _res_key, rt ); + if (rt->_serial == rt->_pi->serial) { + /* Nothing changed, so return the current state */ + D("%s: tid=%d rt=%p nothing changed, returning", + __FUNCTION__, gettid(), rt); + return rt; + } + /* Update the recorded serial number, and go reset the state */ + rt->_serial = rt->_pi->serial; + goto RESET_STATE; } - /* Check the serial value for any chanes to net.* properties. */ - if (rt->_pi == NULL) { - rt->_pi = (struct prop_info*) __system_property_find("net.change"); + + /* It is the first time this function is called in this thread, + * we need to create a new thread-specific DNS resolver state. */ + rt = _res_thread_alloc(); + if (rt == NULL) { + return NULL; } - if (rt->_pi == NULL || rt->_serial == rt->_pi->serial) { - return rt; - } - rt->_serial = rt->_pi->serial; - /* Reload from system properties. */ + pthread_setspecific( _res_key, rt ); + D("%s: tid=%d Created new DNS state rt=%p", + __FUNCTION__, gettid(), rt); + +RESET_STATE: + /* Reset the state, note that res_ninit() can now properly reset + * an existing state without leaking memory. + */ + D("%s: tid=%d, rt=%p, resetting DNS state (options RES_INIT=%d)", + __FUNCTION__, gettid(), rt, (rt->_nres->options & RES_INIT) != 0); if ( res_ninit( rt->_nres ) < 0 ) { - free(rt); - rt = NULL; - pthread_setspecific( _res_key, rt ); + /* This should not happen */ + D("%s: tid=%d rt=%p, woot, res_ninit() returned < 0", + __FUNCTION__, gettid(), rt); + _res_thread_free(rt); + pthread_setspecific( _res_key, NULL ); + return NULL; } _resolv_cache_reset(rt->_serial); return rt;