libcore_io_Linux.cpp revision e3a3a06a94a50d31b7033e496f23becb0f1329c7
1ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes/*
2ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * Copyright (C) 2011 The Android Open Source Project
3ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes *
4ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * Licensed under the Apache License, Version 2.0 (the "License");
5ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * you may not use this file except in compliance with the License.
6ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * You may obtain a copy of the License at
7ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes *
8ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes *      http://www.apache.org/licenses/LICENSE-2.0
9ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes *
10ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * Unless required by applicable law or agreed to in writing, software
11ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
12ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * See the License for the specific language governing permissions and
14ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * limitations under the License.
15ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes */
16ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes
170965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe#define LOG_TAG "Linux"
18ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes
191c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes#include <arpa/inet.h>
20ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes#include <errno.h>
210ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes#include <fcntl.h>
2244177e6982a62506127a857070a2452956c3f0f1Enrico Granata#include <grp.h>
236d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong#include <ifaddrs.h>
248f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline#include <linux/rtnetlink.h>
25b974666d79ebc392b37ec1ae83aae57ae6331c08Elliott Hughes#include <net/if.h>
264f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes#include <netdb.h>
270a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes#include <netinet/in.h>
28a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti#include <netpacket/packet.h>
2970c820401677ca251ad09ac64cc23c760764e75dElliott Hughes#include <poll.h>
30d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes#include <pwd.h>
31a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes#include <signal.h>
32ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes#include <stdlib.h>
335744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#include <sys/capability.h>
34461d0d860814c68154d8dd06d24f94118f33d28aElliott Hughes#include <sys/ioctl.h>
357e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes#include <sys/mman.h>
365215e4c0db7530519981f1e505e6db82401802f2Nick Kralevich#include <sys/prctl.h>
37e873cd1285c04da110758df066b4bd40ad6eb93dNarayan Kamath#include <sys/resource.h>
3859e4744d27231f260271dbbca406e0cc39768116Elliott Hughes#include <sys/socket.h>
3947cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes#include <sys/stat.h>
40069525a39125c203b658c805685b6045a7d4dfebElliott Hughes#include <sys/syscall.h>
410a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes#include <sys/time.h>
420ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes#include <sys/types.h>
43bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes#include <sys/uio.h>
440ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller#include <sys/un.h>
457341b9ed7157a1e37a3e69a0974676da358b735aElliott Hughes#include <sys/utsname.h>
469e67ca71d3d4a489a157abadc5ba519ced7a0b50Elliott Hughes#include <sys/wait.h>
4790246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey#include <sys/xattr.h>
48bb5816aa1626eb2f6263bd21479600b114c8a1bdJohan Redestig#include <termios.h>
490ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes#include <unistd.h>
506d8d1ea910c1ad026b48c87424da92a250664dd2Mark Salyzyn
51b3aacde3d8af759ee4a7b395c636ea360547d92dIan Rogers#include <memory>
52efae3837b3eb79dea3400735fdcdd5a39020e0b0Ian Rogers
532cb2851f4a528e3e6e3e59cf3e854c2abf9f1811Elliott Hughes#include <android-base/file.h>
542c549f1ba3fb683ab1c4ede75bdcb312e8769672Andreas Gampe#include <android-base/logging.h>
5555dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong#include <android-base/strings.h>
56d3a88f94be9fb4d0a6da32cf3a820e5b206ded4aMark Salyzyn#include <log/log.h>
57cab01ac294bb8ded259851673baa4c6ca226f828Steven Moreland#include <nativehelper/AsynchronousCloseMonitor.h>
58cab01ac294bb8ded259851673baa4c6ca226f828Steven Moreland#include <nativehelper/JNIHelp.h>
59cab01ac294bb8ded259851673baa4c6ca226f828Steven Moreland#include <nativehelper/JniConstants.h>
60cab01ac294bb8ded259851673baa4c6ca226f828Steven Moreland#include <nativehelper/ScopedBytes.h>
61cab01ac294bb8ded259851673baa4c6ca226f828Steven Moreland#include <nativehelper/ScopedLocalRef.h>
62cab01ac294bb8ded259851673baa4c6ca226f828Steven Moreland#include <nativehelper/ScopedPrimitiveArray.h>
63cab01ac294bb8ded259851673baa4c6ca226f828Steven Moreland#include <nativehelper/ScopedUtfChars.h>
64cab01ac294bb8ded259851673baa4c6ca226f828Steven Moreland#include <nativehelper/toStringArray.h>
652cb2851f4a528e3e6e3e59cf3e854c2abf9f1811Elliott Hughes
666d8d1ea910c1ad026b48c87424da92a250664dd2Mark Salyzyn#include "ExecStrings.h"
676d8d1ea910c1ad026b48c87424da92a250664dd2Mark Salyzyn#include "JniException.h"
686d8d1ea910c1ad026b48c87424da92a250664dd2Mark Salyzyn#include "NetworkUtilities.h"
696d8d1ea910c1ad026b48c87424da92a250664dd2Mark Salyzyn#include "Portability.h"
706d8d1ea910c1ad026b48c87424da92a250664dd2Mark Salyzyn
71efae3837b3eb79dea3400735fdcdd5a39020e0b0Ian Rogers#ifndef __unused
7237dd0ac5767197bf7e3e90f1a5d4e54c8f1fe93dIan Rogers#define __unused __attribute__((__unused__))
73efae3837b3eb79dea3400735fdcdd5a39020e0b0Ian Rogers#endif
7437dd0ac5767197bf7e3e90f1a5d4e54c8f1fe93dIan Rogers
75d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes#define TO_JAVA_STRING(NAME, EXP) \
76d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes        jstring NAME = env->NewStringUTF(EXP); \
77a0b3a2c22454fad9026cff3b0173ada828bad280Chih-Hung Hsieh        if ((NAME) == NULL) return NULL;
78d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes
792c549f1ba3fb683ab1c4ede75bdcb312e8769672Andreas Gampenamespace {
802c549f1ba3fb683ab1c4ede75bdcb312e8769672Andreas Gampe
81e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias ThiererjfieldID int32RefValueFid;
82e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias ThiererjfieldID int64RefValueFid;
832c549f1ba3fb683ab1c4ede75bdcb312e8769672Andreas Gampe
842c549f1ba3fb683ab1c4ede75bdcb312e8769672Andreas Gampe}  // namespace
852c549f1ba3fb683ab1c4ede75bdcb312e8769672Andreas Gampe
861c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughesstruct addrinfo_deleter {
871c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    void operator()(addrinfo* p) const {
881c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        if (p != NULL) { // bionic's freeaddrinfo(3) crashes when passed NULL.
891c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes            freeaddrinfo(p);
901c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        }
911c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    }
921c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes};
931c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes
945d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamathstruct c_deleter {
955d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath    void operator()(void* p) const {
965d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath        free(p);
975d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath    }
985d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath};
995d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath
100b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colittistatic bool isIPv4MappedAddress(const sockaddr *sa) {
101b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti    const sockaddr_in6 *sin6 = reinterpret_cast<const sockaddr_in6*>(sa);
102b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti    return sa != NULL && sa->sa_family == AF_INET6 &&
103b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti           (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
104b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti            IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr));  // We map 0.0.0.0 to ::, so :: is mapped.
105b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti}
106b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti
107b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti/**
108b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti * Perform a socket operation that specifies an IP address, possibly falling back from specifying
109b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti * the address as an IPv4-mapped IPv6 address in a struct sockaddr_in6 to specifying it as an IPv4
110b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti * address in a struct sockaddr_in.
111b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti *
112b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti * This is needed because all sockets created by the java.net APIs are IPv6 sockets, and on those
113b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti * sockets, IPv4 operations use IPv4-mapped addresses stored in a struct sockaddr_in6. But sockets
1140965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe * created using Linux.socket(AF_INET, ...) are IPv4 sockets and only support operations using IPv4
115b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti * socket addresses structures.
116b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti */
117b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti#define NET_IPV4_FALLBACK(jni_env, return_type, syscall_name, java_fd, java_addr, port, null_addr_ok, args...) ({ \
118b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti    return_type _rc = -1; \
119b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti    do { \
120b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti        sockaddr_storage _ss; \
121b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti        socklen_t _salen; \
122a0b3a2c22454fad9026cff3b0173ada828bad280Chih-Hung Hsieh        if ((java_addr) == NULL && (null_addr_ok)) { \
123b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti            /* No IP address specified (e.g., sendto() on a connected socket). */ \
124b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti            _salen = 0; \
125b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti        } else if (!inetAddressToSockaddr(jni_env, java_addr, port, _ss, _salen)) { \
126b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti            /* Invalid socket address, return -1. inetAddressToSockaddr has already thrown. */ \
127b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti            break; \
128b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti        } \
129b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti        sockaddr* _sa = _salen ? reinterpret_cast<sockaddr*>(&_ss) : NULL; \
130b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti        /* inetAddressToSockaddr always returns an IPv6 sockaddr. Assume that java_fd was created \
131b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti         * by Java API calls, which always create IPv6 socket fds, and pass it in as is. */ \
132b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti        _rc = NET_FAILURE_RETRY(jni_env, return_type, syscall_name, java_fd, ##args, _sa, _salen); \
133b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti        if (_rc == -1 && errno == EAFNOSUPPORT && _salen && isIPv4MappedAddress(_sa)) { \
134b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti            /* We passed in an IPv4 address in an IPv6 sockaddr and the kernel told us that we got \
135b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti             * the address family wrong. Pass in the same address in an IPv4 sockaddr. */ \
136a0b3a2c22454fad9026cff3b0173ada828bad280Chih-Hung Hsieh            (jni_env)->ExceptionClear(); \
137b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti            if (!inetAddressToSockaddrVerbatim(jni_env, java_addr, port, _ss, _salen)) { \
138b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti                break; \
139b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti            } \
140b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti            _sa = reinterpret_cast<sockaddr*>(&_ss); \
141b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti            _rc = NET_FAILURE_RETRY(jni_env, return_type, syscall_name, java_fd, ##args, _sa, _salen); \
142b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti        } \
143b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti    } while (0); \
144b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti    _rc; }) \
145b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti
146996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes/**
147f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * Used to retry networking system calls that can be interrupted with a signal. Unlike
148f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * TEMP_FAILURE_RETRY, this also handles the case where
149f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * AsynchronousCloseMonitor::signalBlockedThreads(fd) is used to signal a close() or
150f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * Thread.interrupt(). Other signals that result in an EINTR result are ignored and the system call
151f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * is retried.
152996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes *
153f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * Returns the result of the system call though a Java exception will be pending if the result is
154f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * -1:  a SocketException if signaled via AsynchronousCloseMonitor, or ErrnoException for other
155f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * failures.
156996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes */
1571124a814d698ed6fd68ac501f5dddfa103d656fdElliott Hughes#define NET_FAILURE_RETRY(jni_env, return_type, syscall_name, java_fd, ...) ({ \
1581124a814d698ed6fd68ac501f5dddfa103d656fdElliott Hughes    return_type _rc = -1; \
159b4af0b52e1190846edde87f352ca722a7d9e0259Lorenzo Colitti    int _syscallErrno; \
160996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes    do { \
161f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller        bool _wasSignaled; \
162996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes        { \
1631124a814d698ed6fd68ac501f5dddfa103d656fdElliott Hughes            int _fd = jniGetFDFromFileDescriptor(jni_env, java_fd); \
164f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller            AsynchronousCloseMonitor _monitor(_fd); \
1651124a814d698ed6fd68ac501f5dddfa103d656fdElliott Hughes            _rc = syscall_name(_fd, __VA_ARGS__); \
166f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller            _syscallErrno = errno; \
167f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller            _wasSignaled = _monitor.wasSignaled(); \
168996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes        } \
169f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller        if (_wasSignaled) { \
170f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller            jniThrowException(jni_env, "java/net/SocketException", "Socket closed"); \
1715d7c0a378be3f7f505b30e634e7aabf072c4edd0Serguei Katkov            _rc = -1; \
172f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller            break; \
173f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller        } \
174f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller        if (_rc == -1 && _syscallErrno != EINTR) { \
175f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller            /* TODO: with a format string we could show the arguments too, like strace(1). */ \
176f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller            throwErrnoException(jni_env, # syscall_name); \
177f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller            break; \
178f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller        } \
179f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    } while (_rc == -1); /* _syscallErrno == EINTR && !_wasSignaled */ \
180b4af0b52e1190846edde87f352ca722a7d9e0259Lorenzo Colitti    if (_rc == -1) { \
181b4af0b52e1190846edde87f352ca722a7d9e0259Lorenzo Colitti        /* If the syscall failed, re-set errno: throwing an exception might have modified it. */ \
182b4af0b52e1190846edde87f352ca722a7d9e0259Lorenzo Colitti        errno = _syscallErrno; \
183b4af0b52e1190846edde87f352ca722a7d9e0259Lorenzo Colitti    } \
184f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    _rc; })
185f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller
186f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller/**
187f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * Used to retry system calls that can be interrupted with a signal. Unlike TEMP_FAILURE_RETRY, this
188f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * also handles the case where AsynchronousCloseMonitor::signalBlockedThreads(fd) is used to signal
189f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * a close() or Thread.interrupt(). Other signals that result in an EINTR result are ignored and the
190f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * system call is retried.
191f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller *
192f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * Returns the result of the system call though a Java exception will be pending if the result is
193f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * -1: an IOException if the file descriptor is already closed, a InterruptedIOException if signaled
194f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * via AsynchronousCloseMonitor, or ErrnoException for other failures.
195f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller */
196f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller#define IO_FAILURE_RETRY(jni_env, return_type, syscall_name, java_fd, ...) ({ \
197f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    return_type _rc = -1; \
198b4af0b52e1190846edde87f352ca722a7d9e0259Lorenzo Colitti    int _syscallErrno; \
19999a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller    do { \
20099a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller        bool _wasSignaled; \
20199a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller        { \
20299a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            int _fd = jniGetFDFromFileDescriptor(jni_env, java_fd); \
20399a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            AsynchronousCloseMonitor _monitor(_fd); \
20499a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            _rc = syscall_name(_fd, __VA_ARGS__); \
20599a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            _syscallErrno = errno; \
20699a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            _wasSignaled = _monitor.wasSignaled(); \
20799a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller        } \
20899a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller        if (_wasSignaled) { \
20999a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            jniThrowException(jni_env, "java/io/InterruptedIOException", # syscall_name " interrupted"); \
21099a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            _rc = -1; \
21199a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            break; \
21299a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller        } \
21399a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller        if (_rc == -1 && _syscallErrno != EINTR) { \
21499a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            /* TODO: with a format string we could show the arguments too, like strace(1). */ \
21599a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            throwErrnoException(jni_env, # syscall_name); \
21699a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            break; \
21799a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller        } \
21899a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller    } while (_rc == -1); /* && _syscallErrno == EINTR && !_wasSignaled */ \
219b4af0b52e1190846edde87f352ca722a7d9e0259Lorenzo Colitti    if (_rc == -1) { \
220b4af0b52e1190846edde87f352ca722a7d9e0259Lorenzo Colitti        /* If the syscall failed, re-set errno: throwing an exception might have modified it. */ \
221b4af0b52e1190846edde87f352ca722a7d9e0259Lorenzo Colitti        errno = _syscallErrno; \
222b4af0b52e1190846edde87f352ca722a7d9e0259Lorenzo Colitti    } \
223996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes    _rc; })
224996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes
225b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti#define NULL_ADDR_OK         true
226b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti#define NULL_ADDR_FORBIDDEN  false
227b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti
2284f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughesstatic void throwException(JNIEnv* env, jclass exceptionClass, jmethodID ctor3, jmethodID ctor2,
2294f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes        const char* functionName, int error) {
230ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    jthrowable cause = NULL;
231ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    if (env->ExceptionCheck()) {
232ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes        cause = env->ExceptionOccurred();
233ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes        env->ExceptionClear();
234ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    }
235ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes
2364f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    ScopedLocalRef<jstring> detailMessage(env, env->NewStringUTF(functionName));
2374f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    if (detailMessage.get() == NULL) {
238f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes        // Not really much we can do here. We're probably dead in the water,
239f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes        // but let's try to stumble on...
240f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes        env->ExceptionClear();
241f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes    }
242f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes
243ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    jobject exception;
244ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    if (cause != NULL) {
2454f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes        exception = env->NewObject(exceptionClass, ctor3, detailMessage.get(), error, cause);
246ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    } else {
2474f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes        exception = env->NewObject(exceptionClass, ctor2, detailMessage.get(), error);
248ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    }
249ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    env->Throw(reinterpret_cast<jthrowable>(exception));
250dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes}
251dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes
2524f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughesstatic void throwErrnoException(JNIEnv* env, const char* functionName) {
2534f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    int error = errno;
2544f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    static jmethodID ctor3 = env->GetMethodID(JniConstants::errnoExceptionClass,
2554f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes            "<init>", "(Ljava/lang/String;ILjava/lang/Throwable;)V");
2564f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    static jmethodID ctor2 = env->GetMethodID(JniConstants::errnoExceptionClass,
2574f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes            "<init>", "(Ljava/lang/String;I)V");
2584f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    throwException(env, JniConstants::errnoExceptionClass, ctor3, ctor2, functionName, error);
2594f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes}
2604f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes
2614f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughesstatic void throwGaiException(JNIEnv* env, const char* functionName, int error) {
262c1cee0db58ec7bc61d5caac79915d744862cbe75Elliott Hughes  // Cache the methods ids before we throw, so we don't call GetMethodID with a pending exception.
263c1cee0db58ec7bc61d5caac79915d744862cbe75Elliott Hughes  static jmethodID ctor3 = env->GetMethodID(JniConstants::gaiExceptionClass, "<init>",
264c1cee0db58ec7bc61d5caac79915d744862cbe75Elliott Hughes                                            "(Ljava/lang/String;ILjava/lang/Throwable;)V");
265c1cee0db58ec7bc61d5caac79915d744862cbe75Elliott Hughes  static jmethodID ctor2 = env->GetMethodID(JniConstants::gaiExceptionClass, "<init>",
266c1cee0db58ec7bc61d5caac79915d744862cbe75Elliott Hughes                                            "(Ljava/lang/String;I)V");
267c1cee0db58ec7bc61d5caac79915d744862cbe75Elliott Hughes  if (errno != 0) {
26875cf14944d476670f6f915e5efd849e238a16250Elliott Hughes        // EAI_SYSTEM should mean "look at errno instead", but both glibc and bionic seem to
26975cf14944d476670f6f915e5efd849e238a16250Elliott Hughes        // mess this up. In particular, if you don't have INTERNET permission, errno will be EACCES
27075cf14944d476670f6f915e5efd849e238a16250Elliott Hughes        // but you'll get EAI_NONAME or EAI_NODATA. So we want our GaiException to have a
27175cf14944d476670f6f915e5efd849e238a16250Elliott Hughes        // potentially-relevant ErrnoException as its cause even if error != EAI_SYSTEM.
27275cf14944d476670f6f915e5efd849e238a16250Elliott Hughes        // http://code.google.com/p/android/issues/detail?id=15722
2734f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes        throwErrnoException(env, functionName);
2744f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes        // Deliberately fall through to throw another exception...
2754f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    }
2764f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    throwException(env, JniConstants::gaiExceptionClass, ctor3, ctor2, functionName, error);
2774f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes}
2784f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes
279dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughestemplate <typename rc_t>
2807e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughesstatic rc_t throwIfMinusOne(JNIEnv* env, const char* name, rc_t rc) {
281dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes    if (rc == rc_t(-1)) {
2827e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes        throwErrnoException(env, name);
283dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes    }
284dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes    return rc;
28547cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes}
28647cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes
2878dc754726bb5303c25e2c48decdf76d9323ee231Elliott Hughestemplate <typename ScopedT>
288bbac92e691de7d570928ddfba639067978e55b06Elliott Hughesclass IoVec {
289bbac92e691de7d570928ddfba639067978e55b06Elliott Hughespublic:
290bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    IoVec(JNIEnv* env, size_t bufferCount) : mEnv(env), mBufferCount(bufferCount) {
291bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    }
292bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes
293bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    bool init(jobjectArray javaBuffers, jintArray javaOffsets, jintArray javaByteCounts) {
294bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        // We can't delete our local references until after the I/O, so make sure we have room.
295bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        if (mEnv->PushLocalFrame(mBufferCount + 16) < 0) {
296bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes            return false;
297bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        }
298bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        ScopedIntArrayRO offsets(mEnv, javaOffsets);
299bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        if (offsets.get() == NULL) {
300bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes            return false;
301bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        }
302bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        ScopedIntArrayRO byteCounts(mEnv, javaByteCounts);
303bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        if (byteCounts.get() == NULL) {
304bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes            return false;
305bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        }
306bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        // TODO: Linux actually has a 1024 buffer limit. glibc works around this, and we should too.
307d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes        // TODO: you can query the limit at runtime with sysconf(_SC_IOV_MAX).
308bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        for (size_t i = 0; i < mBufferCount; ++i) {
309e9f12043a1e2a29c60779cdb55c58eb156963570Elliott Hughes            jobject buffer = mEnv->GetObjectArrayElement(javaBuffers, i); // We keep this local ref.
3108dc754726bb5303c25e2c48decdf76d9323ee231Elliott Hughes            mScopedBuffers.push_back(new ScopedT(mEnv, buffer));
3118dc754726bb5303c25e2c48decdf76d9323ee231Elliott Hughes            jbyte* ptr = const_cast<jbyte*>(mScopedBuffers.back()->get());
312bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes            if (ptr == NULL) {
313bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes                return false;
314bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes            }
315bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes            struct iovec iov;
316bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes            iov.iov_base = reinterpret_cast<void*>(ptr + offsets[i]);
317bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes            iov.iov_len = byteCounts[i];
318bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes            mIoVec.push_back(iov);
319bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        }
320bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        return true;
321bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    }
322bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes
323bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    ~IoVec() {
3248dc754726bb5303c25e2c48decdf76d9323ee231Elliott Hughes        for (size_t i = 0; i < mScopedBuffers.size(); ++i) {
3258dc754726bb5303c25e2c48decdf76d9323ee231Elliott Hughes            delete mScopedBuffers[i];
326bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        }
327bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        mEnv->PopLocalFrame(NULL);
328bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    }
329bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes
330bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    iovec* get() {
331bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        return &mIoVec[0];
332bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    }
333bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes
334bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    size_t size() {
335bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        return mBufferCount;
336bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    }
337bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes
338bbac92e691de7d570928ddfba639067978e55b06Elliott Hughesprivate:
339bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    JNIEnv* mEnv;
340bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    size_t mBufferCount;
341bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    std::vector<iovec> mIoVec;
3428dc754726bb5303c25e2c48decdf76d9323ee231Elliott Hughes    std::vector<ScopedT*> mScopedBuffers;
343bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes};
344bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes
3450ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller/**
3462550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller * Returns a jbyteArray containing the sockaddr_un.sun_path from ss. As per unix(7) sa_len should be
3472550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller * the length of ss as returned by getsockname(2), getpeername(2), or accept(2).
3482550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller * If the returned array is of length 0 the sockaddr_un refers to an unnamed socket.
3492550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller * A null pointer is returned in the event of an error. See unix(7) for more information.
3500ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller */
3512550a252387631b49a00d2ee5587717cd2a6dda3Neil Fullerstatic jbyteArray getUnixSocketPath(JNIEnv* env, const sockaddr_storage& ss,
3522550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller        const socklen_t& sa_len) {
3530ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    if (ss.ss_family != AF_UNIX) {
3540ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
3550ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller                "getUnixSocketPath unsupported ss_family: %i", ss.ss_family);
3562550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller        return NULL;
3570ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    }
3582550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller
3590ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    const struct sockaddr_un* un_addr = reinterpret_cast<const struct sockaddr_un*>(&ss);
3602550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    // The length of sun_path is sa_len minus the length of the overhead (ss_family).
3612550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    // See unix(7) for details. This calculation must match that of socket_make_sockaddr_un() in
3622550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    // socket_local_client.c and javaUnixSocketAddressToSockaddr() to interoperate.
3632550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    size_t pathLength = sa_len - offsetof(struct sockaddr_un, sun_path);
3642550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller
3652550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    jbyteArray javaSunPath = env->NewByteArray(pathLength);
3662550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    if (javaSunPath == NULL) {
3672550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller        return NULL;
3680ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    }
3692550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller
3702550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    if (pathLength > 0) {
3712550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller        env->SetByteArrayRegion(javaSunPath, 0, pathLength,
3722550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller                reinterpret_cast<const jbyte*>(&un_addr->sun_path));
3732550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    }
3742550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    return javaSunPath;
3750ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller}
3760ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller
3770ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fullerstatic jobject makeSocketAddress(JNIEnv* env, const sockaddr_storage& ss, const socklen_t sa_len) {
3780ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6) {
3798f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        jint port;
3808f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        jobject inetAddress = sockaddrToInetAddress(env, ss, &port);
3818f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        if (inetAddress == NULL) {
3828f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline            return NULL;  // Exception already thrown.
3838f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        }
3848f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        static jmethodID ctor = env->GetMethodID(JniConstants::inetSocketAddressClass,
3858f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline                "<init>", "(Ljava/net/InetAddress;I)V");
38693a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        if (ctor == NULL) {
38793a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak            return NULL;
38893a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        }
3898f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        return env->NewObject(JniConstants::inetSocketAddressClass, ctor, inetAddress, port);
3900ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    } else if (ss.ss_family == AF_UNIX) {
3910ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller        static jmethodID ctor = env->GetMethodID(JniConstants::unixSocketAddressClass,
3920ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller                "<init>", "([B)V");
39393a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        if (ctor == NULL) {
39493a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak            return NULL;
39593a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        }
3962550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller        jbyteArray javaSunPath = getUnixSocketPath(env, ss, sa_len);
3972550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller        if (!javaSunPath) {
3980ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller            return NULL;
3990ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller        }
4002550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller        return env->NewObject(JniConstants::unixSocketAddressClass, ctor, javaSunPath);
4018f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    } else if (ss.ss_family == AF_NETLINK) {
4028f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        const struct sockaddr_nl* nl_addr = reinterpret_cast<const struct sockaddr_nl*>(&ss);
4038f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        static jmethodID ctor = env->GetMethodID(JniConstants::netlinkSocketAddressClass,
4048f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline                "<init>", "(II)V");
40593a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        if (ctor == NULL) {
40693a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak            return NULL;
40793a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        }
4086e888e9390649a9ab2557da5b28bb75be39e1b74Przemyslaw Szczepaniak        return env->NewObject(JniConstants::netlinkSocketAddressClass, ctor,
4096e888e9390649a9ab2557da5b28bb75be39e1b74Przemyslaw Szczepaniak                static_cast<jint>(nl_addr->nl_pid),
4108f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline                static_cast<jint>(nl_addr->nl_groups));
41100bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    } else if (ss.ss_family == AF_PACKET) {
41200bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        const struct sockaddr_ll* sll = reinterpret_cast<const struct sockaddr_ll*>(&ss);
41300bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        static jmethodID ctor = env->GetMethodID(JniConstants::packetSocketAddressClass,
41400bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti                "<init>", "(SISB[B)V");
41593a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        if (ctor == NULL) {
41693a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak            return NULL;
41793a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        }
41800bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        ScopedLocalRef<jbyteArray> byteArray(env, env->NewByteArray(sll->sll_halen));
41900bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        if (byteArray.get() == NULL) {
42000bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti            return NULL;
42100bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        }
42200bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        env->SetByteArrayRegion(byteArray.get(), 0, sll->sll_halen,
42300bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti                reinterpret_cast<const jbyte*>(sll->sll_addr));
42400bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        jobject packetSocketAddress = env->NewObject(JniConstants::packetSocketAddressClass, ctor,
42500bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti                static_cast<jshort>(ntohs(sll->sll_protocol)),
42600bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti                static_cast<jint>(sll->sll_ifindex),
42700bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti                static_cast<jshort>(sll->sll_hatype),
42800bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti                static_cast<jbyte>(sll->sll_pkttype),
42900bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti                byteArray.get());
43000bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        return packetSocketAddress;
43100bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    }
43200bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "unsupported ss_family: %d",
43300bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti            ss.ss_family);
4348f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    return NULL;
4350a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes}
4360a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes
437d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughesstatic jobject makeStructPasswd(JNIEnv* env, const struct passwd& pw) {
438d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    TO_JAVA_STRING(pw_name, pw.pw_name);
439d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    TO_JAVA_STRING(pw_dir, pw.pw_dir);
440d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    TO_JAVA_STRING(pw_shell, pw.pw_shell);
441d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    static jmethodID ctor = env->GetMethodID(JniConstants::structPasswdClass, "<init>",
442d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes            "(Ljava/lang/String;IILjava/lang/String;Ljava/lang/String;)V");
44393a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    if (ctor == NULL) {
44493a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        return NULL;
44593a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    }
446d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    return env->NewObject(JniConstants::structPasswdClass, ctor,
447d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes            pw_name, static_cast<jint>(pw.pw_uid), static_cast<jint>(pw.pw_gid), pw_dir, pw_shell);
448d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes}
449d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes
450108091b6787f37a23862c7c9bb965ccf932430abPrzemyslaw Szczepaniakstatic jobject makeStructTimespec(JNIEnv* env, const struct timespec& ts) {
451108091b6787f37a23862c7c9bb965ccf932430abPrzemyslaw Szczepaniak    static jmethodID ctor = env->GetMethodID(JniConstants::structTimespecClass, "<init>",
452108091b6787f37a23862c7c9bb965ccf932430abPrzemyslaw Szczepaniak            "(JJ)V");
45393a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    if (ctor == NULL) {
45493a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        return NULL;
45593a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    }
456108091b6787f37a23862c7c9bb965ccf932430abPrzemyslaw Szczepaniak    return env->NewObject(JniConstants::structTimespecClass, ctor,
457108091b6787f37a23862c7c9bb965ccf932430abPrzemyslaw Szczepaniak            static_cast<jlong>(ts.tv_sec), static_cast<jlong>(ts.tv_nsec));
458108091b6787f37a23862c7c9bb965ccf932430abPrzemyslaw Szczepaniak}
459108091b6787f37a23862c7c9bb965ccf932430abPrzemyslaw Szczepaniak
46013a70e6c04157064fc8a61ecfcb1d863f29c239dYi Kongstatic jobject makeStructStat(JNIEnv* env, const struct stat64& sb) {
46147cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes    static jmethodID ctor = env->GetMethodID(JniConstants::structStatClass, "<init>",
462108091b6787f37a23862c7c9bb965ccf932430abPrzemyslaw Szczepaniak            "(JJIJIIJJLandroid/system/StructTimespec;Landroid/system/StructTimespec;Landroid/system/StructTimespec;JJ)V");
46393a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    if (ctor == NULL) {
46493a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        return NULL;
46593a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    }
46693a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak
467fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak    jobject atim_timespec = makeStructTimespec(env, sb.st_atim);
468fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak    if (atim_timespec == NULL) {
469fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak        return NULL;
470fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak    }
471fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak    jobject mtim_timespec = makeStructTimespec(env, sb.st_mtim);
472fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak    if (mtim_timespec == NULL) {
473fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak        return NULL;
474fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak    }
475fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak    jobject ctim_timespec = makeStructTimespec(env, sb.st_ctim);
476fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak    if (ctim_timespec == NULL) {
477fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak        return NULL;
478fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak    }
479fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak
48047cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes    return env->NewObject(JniConstants::structStatClass, ctor,
48159fa7163774d6930a174bc038414a4b780581957Elliott Hughes            static_cast<jlong>(sb.st_dev), static_cast<jlong>(sb.st_ino),
48259fa7163774d6930a174bc038414a4b780581957Elliott Hughes            static_cast<jint>(sb.st_mode), static_cast<jlong>(sb.st_nlink),
48359fa7163774d6930a174bc038414a4b780581957Elliott Hughes            static_cast<jint>(sb.st_uid), static_cast<jint>(sb.st_gid),
48459fa7163774d6930a174bc038414a4b780581957Elliott Hughes            static_cast<jlong>(sb.st_rdev), static_cast<jlong>(sb.st_size),
485fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak            atim_timespec, mtim_timespec, ctim_timespec,
486fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak            static_cast<jlong>(sb.st_blksize), static_cast<jlong>(sb.st_blocks));
48759fa7163774d6930a174bc038414a4b780581957Elliott Hughes}
48859fa7163774d6930a174bc038414a4b780581957Elliott Hughes
489721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughesstatic jobject makeStructStatVfs(JNIEnv* env, const struct statvfs& sb) {
490721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes    static jmethodID ctor = env->GetMethodID(JniConstants::structStatVfsClass, "<init>",
491721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes            "(JJJJJJJJJJJ)V");
49293a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    if (ctor == NULL) {
49393a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        return NULL;
49493a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    }
49593a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak
496721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes    return env->NewObject(JniConstants::structStatVfsClass, ctor,
497721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes                          static_cast<jlong>(sb.f_bsize),
498721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes                          static_cast<jlong>(sb.f_frsize),
499721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes                          static_cast<jlong>(sb.f_blocks),
500721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes                          static_cast<jlong>(sb.f_bfree),
501721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes                          static_cast<jlong>(sb.f_bavail),
502721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes                          static_cast<jlong>(sb.f_files),
503721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes                          static_cast<jlong>(sb.f_ffree),
504721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes                          static_cast<jlong>(sb.f_favail),
505721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes                          static_cast<jlong>(sb.f_fsid),
506721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes                          static_cast<jlong>(sb.f_flag),
507efe42934a8523f2b051a351e5eceebf6216454aeElliott Hughes                          static_cast<jlong>(sb.f_namemax));
50847cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes}
50947cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes
5100a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughesstatic jobject makeStructLinger(JNIEnv* env, const struct linger& l) {
5110a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    static jmethodID ctor = env->GetMethodID(JniConstants::structLingerClass, "<init>", "(II)V");
51293a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    if (ctor == NULL) {
51393a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        return NULL;
51493a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    }
5150a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    return env->NewObject(JniConstants::structLingerClass, ctor, l.l_onoff, l.l_linger);
5160a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes}
5170a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes
5180a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughesstatic jobject makeStructTimeval(JNIEnv* env, const struct timeval& tv) {
5190a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    static jmethodID ctor = env->GetMethodID(JniConstants::structTimevalClass, "<init>", "(JJ)V");
52093a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    if (ctor == NULL) {
52193a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        return NULL;
52293a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    }
5230a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    return env->NewObject(JniConstants::structTimevalClass, ctor,
5240a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes            static_cast<jlong>(tv.tv_sec), static_cast<jlong>(tv.tv_usec));
5250a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes}
5260a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes
5273deabd220cf7b1ca0824987e90b8ecc07087f05aIan Rogersstatic jobject makeStructUcred(JNIEnv* env, const struct ucred& u __unused) {
52893a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    static jmethodID ctor = env->GetMethodID(JniConstants::structUcredClass, "<init>", "(III)V");
52993a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    if (ctor == NULL) {
53093a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        return NULL;
53193a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    }
53293a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    return env->NewObject(JniConstants::structUcredClass, ctor, u.pid, u.uid, u.gid);
533482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes}
534482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes
5357341b9ed7157a1e37a3e69a0974676da358b735aElliott Hughesstatic jobject makeStructUtsname(JNIEnv* env, const struct utsname& buf) {
536d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    TO_JAVA_STRING(sysname, buf.sysname);
537d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    TO_JAVA_STRING(nodename, buf.nodename);
538d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    TO_JAVA_STRING(release, buf.release);
539d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    TO_JAVA_STRING(version, buf.version);
540d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    TO_JAVA_STRING(machine, buf.machine);
5417341b9ed7157a1e37a3e69a0974676da358b735aElliott Hughes    static jmethodID ctor = env->GetMethodID(JniConstants::structUtsnameClass, "<init>",
5427341b9ed7157a1e37a3e69a0974676da358b735aElliott Hughes            "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
54393a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    if (ctor == NULL) {
54493a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        return NULL;
54593a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    }
5467341b9ed7157a1e37a3e69a0974676da358b735aElliott Hughes    return env->NewObject(JniConstants::structUtsnameClass, ctor,
5477341b9ed7157a1e37a3e69a0974676da358b735aElliott Hughes            sysname, nodename, release, version, machine);
5487341b9ed7157a1e37a3e69a0974676da358b735aElliott Hughes};
5497341b9ed7157a1e37a3e69a0974676da358b735aElliott Hughes
550a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughesstatic bool fillIfreq(JNIEnv* env, jstring javaInterfaceName, struct ifreq& req) {
551a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    ScopedUtfChars interfaceName(env, javaInterfaceName);
552a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    if (interfaceName.c_str() == NULL) {
553a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes        return false;
554a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    }
555a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    memset(&req, 0, sizeof(req));
556a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    strncpy(req.ifr_name, interfaceName.c_str(), sizeof(req.ifr_name));
557a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    req.ifr_name[sizeof(req.ifr_name) - 1] = '\0';
558a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    return true;
559a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes}
560a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes
5610ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fullerstatic bool fillUnixSocketAddress(JNIEnv* env, jobject javaUnixSocketAddress,
5620ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller        const sockaddr_storage& ss, const socklen_t& sa_len) {
5630ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    if (javaUnixSocketAddress == NULL) {
5640ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller        return true;
5650ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    }
5662550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    jbyteArray javaSunPath = getUnixSocketPath(env, ss, sa_len);
5672550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    if (!javaSunPath) {
5680ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller        return false;
5690ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    }
5700ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller
5710ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    static jfieldID sunPathFid =
5720ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller            env->GetFieldID(JniConstants::unixSocketAddressClass, "sun_path", "[B");
5732550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    env->SetObjectField(javaUnixSocketAddress, sunPathFid, javaSunPath);
5740ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    return true;
5750ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller}
5760ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller
5770ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fullerstatic bool fillInetSocketAddress(JNIEnv* env, jobject javaInetSocketAddress,
5780ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller        const sockaddr_storage& ss) {
5790ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    if (javaInetSocketAddress == NULL) {
580553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes        return true;
581553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes    }
582553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes    // Fill out the passed-in InetSocketAddress with the sender's IP address and port number.
583553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes    jint port;
584553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes    jobject sender = sockaddrToInetAddress(env, ss, &port);
585553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes    if (sender == NULL) {
586553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes        return false;
587553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes    }
5884cb97fe003dcf14ccd8f6e381cd172020248efaeNarayan Kamath    static jfieldID holderFid = env->GetFieldID(JniConstants::inetSocketAddressClass, "holder",
5894cb97fe003dcf14ccd8f6e381cd172020248efaeNarayan Kamath                                                "Ljava/net/InetSocketAddress$InetSocketAddressHolder;");
590ea544eccd7c78b693804d763dabbd8f7247dc802Piotr Jastrzebski    jobject holder = env->GetObjectField(javaInetSocketAddress, holderFid);
591ea544eccd7c78b693804d763dabbd8f7247dc802Piotr Jastrzebski
5924cb97fe003dcf14ccd8f6e381cd172020248efaeNarayan Kamath    static jfieldID addressFid = env->GetFieldID(JniConstants::inetSocketAddressHolderClass,
5934cb97fe003dcf14ccd8f6e381cd172020248efaeNarayan Kamath                                                 "addr", "Ljava/net/InetAddress;");
594ea544eccd7c78b693804d763dabbd8f7247dc802Piotr Jastrzebski    static jfieldID portFid = env->GetFieldID(JniConstants::inetSocketAddressHolderClass, "port", "I");
595ea544eccd7c78b693804d763dabbd8f7247dc802Piotr Jastrzebski    env->SetObjectField(holder, addressFid, sender);
596ea544eccd7c78b693804d763dabbd8f7247dc802Piotr Jastrzebski    env->SetIntField(holder, portFid, port);
597553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes    return true;
598553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes}
599553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes
6000ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fullerstatic bool fillSocketAddress(JNIEnv* env, jobject javaSocketAddress, const sockaddr_storage& ss,
6010ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller        const socklen_t& sa_len) {
6020ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    if (javaSocketAddress == NULL) {
6030ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller        return true;
6040ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    }
6050ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller
6060ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    if (env->IsInstanceOf(javaSocketAddress, JniConstants::inetSocketAddressClass)) {
6070ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller        return fillInetSocketAddress(env, javaSocketAddress, ss);
6080ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    } else if (env->IsInstanceOf(javaSocketAddress, JniConstants::unixSocketAddressClass)) {
6090ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller        return fillUnixSocketAddress(env, javaSocketAddress, ss, sa_len);
6100ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    }
6110ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    jniThrowException(env, "java/lang/UnsupportedOperationException",
6120ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller            "unsupported SocketAddress subclass");
6130ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    return false;
6140ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller
6150ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller}
6160ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller
617f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colittistatic void javaInetSocketAddressToInetAddressAndPort(
618f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti        JNIEnv* env, jobject javaInetSocketAddress, jobject& javaInetAddress, jint& port) {
6194cb97fe003dcf14ccd8f6e381cd172020248efaeNarayan Kamath    static jfieldID holderFid = env->GetFieldID(JniConstants::inetSocketAddressClass, "holder",
6204cb97fe003dcf14ccd8f6e381cd172020248efaeNarayan Kamath                                                "Ljava/net/InetSocketAddress$InetSocketAddressHolder;");
6214cb97fe003dcf14ccd8f6e381cd172020248efaeNarayan Kamath    jobject holder = env->GetObjectField(javaInetSocketAddress, holderFid);
6224cb97fe003dcf14ccd8f6e381cd172020248efaeNarayan Kamath
6238f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    static jfieldID addressFid = env->GetFieldID(
6244cb97fe003dcf14ccd8f6e381cd172020248efaeNarayan Kamath            JniConstants::inetSocketAddressHolderClass, "addr", "Ljava/net/InetAddress;");
6254cb97fe003dcf14ccd8f6e381cd172020248efaeNarayan Kamath    static jfieldID portFid = env->GetFieldID(JniConstants::inetSocketAddressHolderClass, "port", "I");
6264cb97fe003dcf14ccd8f6e381cd172020248efaeNarayan Kamath
6274cb97fe003dcf14ccd8f6e381cd172020248efaeNarayan Kamath    javaInetAddress = env->GetObjectField(holder, addressFid);
6284cb97fe003dcf14ccd8f6e381cd172020248efaeNarayan Kamath    port = env->GetIntField(holder, portFid);
629f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti}
630f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti
631f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colittistatic bool javaInetSocketAddressToSockaddr(
632f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti        JNIEnv* env, jobject javaSocketAddress, sockaddr_storage& ss, socklen_t& sa_len) {
633f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti    jobject javaInetAddress;
634f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti    jint port;
635f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti    javaInetSocketAddressToInetAddressAndPort(env, javaSocketAddress, javaInetAddress, port);
636f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti    return inetAddressToSockaddr(env, javaInetAddress, port, ss, sa_len);
6378f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline}
6388f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline
6398f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Klinestatic bool javaNetlinkSocketAddressToSockaddr(
6408f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        JNIEnv* env, jobject javaSocketAddress, sockaddr_storage& ss, socklen_t& sa_len) {
6418f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    static jfieldID nlPidFid = env->GetFieldID(
6428f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline            JniConstants::netlinkSocketAddressClass, "nlPortId", "I");
6438f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    static jfieldID nlGroupsFid = env->GetFieldID(
6448f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline            JniConstants::netlinkSocketAddressClass, "nlGroupsMask", "I");
6458f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline
6468f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    sockaddr_nl *nlAddr = reinterpret_cast<sockaddr_nl *>(&ss);
6478f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    nlAddr->nl_family = AF_NETLINK;
6488f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    nlAddr->nl_pid = env->GetIntField(javaSocketAddress, nlPidFid);
6498f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    nlAddr->nl_groups = env->GetIntField(javaSocketAddress, nlGroupsFid);
6508f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    sa_len = sizeof(sockaddr_nl);
6518f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    return true;
6528f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline}
6538f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline
6540ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fullerstatic bool javaUnixSocketAddressToSockaddr(
6550ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller        JNIEnv* env, jobject javaUnixSocketAddress, sockaddr_storage& ss, socklen_t& sa_len) {
6560ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    static jfieldID sunPathFid = env->GetFieldID(
6570ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller            JniConstants::unixSocketAddressClass, "sun_path", "[B");
6580ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller
6590ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    struct sockaddr_un* un_addr = reinterpret_cast<struct sockaddr_un*>(&ss);
6602550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    memset (un_addr, 0, sizeof(sockaddr_un));
6610ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    un_addr->sun_family = AF_UNIX;
6620ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller
6630ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    jbyteArray javaSunPath = (jbyteArray) env->GetObjectField(javaUnixSocketAddress, sunPathFid);
6640ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    jsize pathLength = env->GetArrayLength(javaSunPath);
6652550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    if ((size_t) pathLength > sizeof(sockaddr_un::sun_path)) {
6662550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
6672550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller                "sun_path too long: max=%i, is=%i",
6682550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller                sizeof(sockaddr_un::sun_path), pathLength);
6692550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller        return false;
6700ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    }
6712550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    env->GetByteArrayRegion(javaSunPath, 0, pathLength, (jbyte*) un_addr->sun_path);
6722550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    // sa_len is sun_path plus the length of the overhead (ss_family_t). See unix(7) for
6732550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    // details. This calculation must match that of socket_make_sockaddr_un() in
6742550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    // socket_local_client.c and getUnixSocketPath() to interoperate.
6752550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    sa_len = offsetof(struct sockaddr_un, sun_path) + pathLength;
6760ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    return true;
6770ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller}
6780ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller
67900bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colittistatic bool javaPacketSocketAddressToSockaddr(
68000bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        JNIEnv* env, jobject javaSocketAddress, sockaddr_storage& ss, socklen_t& sa_len) {
68100bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    static jfieldID protocolFid = env->GetFieldID(
68200bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti            JniConstants::packetSocketAddressClass, "sll_protocol", "S");
68300bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    static jfieldID ifindexFid = env->GetFieldID(
68400bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti            JniConstants::packetSocketAddressClass, "sll_ifindex", "I");
68500bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    static jfieldID hatypeFid = env->GetFieldID(
68600bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti            JniConstants::packetSocketAddressClass, "sll_hatype", "S");
68700bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    static jfieldID pkttypeFid = env->GetFieldID(
68800bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti            JniConstants::packetSocketAddressClass, "sll_pkttype", "B");
68900bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    static jfieldID addrFid = env->GetFieldID(
69000bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti            JniConstants::packetSocketAddressClass, "sll_addr", "[B");
69100bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti
69200bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    sockaddr_ll *sll = reinterpret_cast<sockaddr_ll *>(&ss);
69300bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    sll->sll_family = AF_PACKET;
694e0273519773d7b14680fe0aa8bc180836042f245Lorenzo Colitti    sll->sll_protocol = htons(env->GetShortField(javaSocketAddress, protocolFid));
69500bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    sll->sll_ifindex = env->GetIntField(javaSocketAddress, ifindexFid);
69600bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    sll->sll_hatype = env->GetShortField(javaSocketAddress, hatypeFid);
69700bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    sll->sll_pkttype = env->GetByteField(javaSocketAddress, pkttypeFid);
69800bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti
69900bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    jbyteArray sllAddr = (jbyteArray) env->GetObjectField(javaSocketAddress, addrFid);
70000bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    if (sllAddr == NULL) {
70100bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        sll->sll_halen = 0;
70200bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        memset(&sll->sll_addr, 0, sizeof(sll->sll_addr));
70300bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    } else {
70400bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        jsize len = env->GetArrayLength(sllAddr);
70500bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        if ((size_t) len > sizeof(sll->sll_addr)) {
70600bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti            len = sizeof(sll->sll_addr);
70700bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        }
70800bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        sll->sll_halen = len;
70900bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        env->GetByteArrayRegion(sllAddr, 0, len, (jbyte*) sll->sll_addr);
71000bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    }
71100bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    sa_len = sizeof(sockaddr_ll);
71200bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    return true;
71300bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti}
71400bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti
7158f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Klinestatic bool javaSocketAddressToSockaddr(
7168f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        JNIEnv* env, jobject javaSocketAddress, sockaddr_storage& ss, socklen_t& sa_len) {
7178f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    if (javaSocketAddress == NULL) {
7188f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        jniThrowNullPointerException(env, NULL);
7198f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        return false;
7208f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    }
7218f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline
7228f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    if (env->IsInstanceOf(javaSocketAddress, JniConstants::netlinkSocketAddressClass)) {
7238f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        return javaNetlinkSocketAddressToSockaddr(env, javaSocketAddress, ss, sa_len);
7248f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    } else if (env->IsInstanceOf(javaSocketAddress, JniConstants::inetSocketAddressClass)) {
7258f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        return javaInetSocketAddressToSockaddr(env, javaSocketAddress, ss, sa_len);
72600bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    } else if (env->IsInstanceOf(javaSocketAddress, JniConstants::packetSocketAddressClass)) {
72700bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        return javaPacketSocketAddressToSockaddr(env, javaSocketAddress, ss, sa_len);
7280ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    } else if (env->IsInstanceOf(javaSocketAddress, JniConstants::unixSocketAddressClass)) {
7290ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller        return javaUnixSocketAddressToSockaddr(env, javaSocketAddress, ss, sa_len);
7308f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    }
7318f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    jniThrowException(env, "java/lang/UnsupportedOperationException",
7328f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline            "unsupported SocketAddress subclass");
7338f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    return false;
7348f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline}
7358f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline
73647cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughesstatic jobject doStat(JNIEnv* env, jstring javaPath, bool isLstat) {
73747cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes    ScopedUtfChars path(env, javaPath);
73847cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes    if (path.c_str() == NULL) {
73947cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes        return NULL;
74047cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes    }
74113a70e6c04157064fc8a61ecfcb1d863f29c239dYi Kong    struct stat64 sb;
74213a70e6c04157064fc8a61ecfcb1d863f29c239dYi Kong    int rc = isLstat ? TEMP_FAILURE_RETRY(lstat64(path.c_str(), &sb))
74313a70e6c04157064fc8a61ecfcb1d863f29c239dYi Kong                     : TEMP_FAILURE_RETRY(stat64(path.c_str(), &sb));
744dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes    if (rc == -1) {
7457e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes        throwErrnoException(env, isLstat ? "lstat" : "stat");
74647cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes        return NULL;
74747cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes    }
74847cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes    return makeStructStat(env, sb);
749ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes}
750ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes
751482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughesstatic jobject doGetSockName(JNIEnv* env, jobject javaFd, bool is_sockname) {
752482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  int fd = jniGetFDFromFileDescriptor(env, javaFd);
753482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  sockaddr_storage ss;
754482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  sockaddr* sa = reinterpret_cast<sockaddr*>(&ss);
755482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  socklen_t byteCount = sizeof(ss);
756482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  memset(&ss, 0, byteCount);
757482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  int rc = is_sockname ? TEMP_FAILURE_RETRY(getsockname(fd, sa, &byteCount))
758482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes      : TEMP_FAILURE_RETRY(getpeername(fd, sa, &byteCount));
759482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  if (rc == -1) {
760482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes    throwErrnoException(env, is_sockname ? "getsockname" : "getpeername");
761482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes    return NULL;
762482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  }
7630ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller  return makeSocketAddress(env, ss, byteCount);
764482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes}
765482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes
766d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughesclass Passwd {
767d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughespublic:
7683b527308aae5a23ac71cf5f637b4595a9b55a2dbChih-Hung Hsieh    explicit Passwd(JNIEnv* env) : mEnv(env), mResult(NULL) {
769d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes        mBufferSize = sysconf(_SC_GETPW_R_SIZE_MAX);
770d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes        mBuffer.reset(new char[mBufferSize]);
771d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    }
772d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes
773d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    jobject getpwnam(const char* name) {
774d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes        return process("getpwnam_r", getpwnam_r(name, &mPwd, mBuffer.get(), mBufferSize, &mResult));
775d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    }
776d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes
777d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    jobject getpwuid(uid_t uid) {
778d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes        return process("getpwuid_r", getpwuid_r(uid, &mPwd, mBuffer.get(), mBufferSize, &mResult));
779d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    }
780d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes
781d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    struct passwd* get() {
782d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes        return mResult;
783d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    }
784d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes
785d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughesprivate:
786d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    jobject process(const char* syscall, int error) {
787d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes        if (mResult == NULL) {
788d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes            errno = error;
789d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes            throwErrnoException(mEnv, syscall);
790d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes            return NULL;
791d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes        }
792d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes        return makeStructPasswd(mEnv, *mResult);
793d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    }
794d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes
795d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    JNIEnv* mEnv;
796b3aacde3d8af759ee4a7b395c636ea360547d92dIan Rogers    std::unique_ptr<char[]> mBuffer;
797d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    size_t mBufferSize;
798d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    struct passwd mPwd;
799d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    struct passwd* mResult;
800d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes};
801d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes
8025744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampestatic void AssertException(JNIEnv* env) {
8035744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (env->ExceptionCheck() == JNI_FALSE) {
8045744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        env->FatalError("Expected exception");
8055744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
8065744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe}
8075744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8085744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe// Note for capabilities functions:
8095744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe// We assume the calls are rare enough that it does not make sense to cache class objects. The
8105744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe// advantage is lower maintenance burden.
8115744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8125744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampestatic bool ReadStructCapUserHeader(
8135744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        JNIEnv* env, jobject java_header, __user_cap_header_struct* c_header) {
8145744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (java_header == nullptr) {
8155744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        jniThrowNullPointerException(env, "header is null");
8165744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return false;
8175744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
8185744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8195744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    ScopedLocalRef<jclass> header_class(env, env->FindClass("android/system/StructCapUserHeader"));
8205744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (header_class.get() == nullptr) {
8215744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return false;
8225744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
8235744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8245744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    {
8255744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        static jfieldID version_fid = env->GetFieldID(header_class.get(), "version", "I");
8265744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        if (version_fid == nullptr) {
8275744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe            return false;
8285744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        }
8295744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        c_header->version = env->GetIntField(java_header, version_fid);
8305744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
8315744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8325744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    {
8335744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        static jfieldID pid_fid = env->GetFieldID(header_class.get(), "pid", "I");
8345744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        if (pid_fid == nullptr) {
8355744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe            return false;
8365744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        }
8375744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        c_header->pid = env->GetIntField(java_header, pid_fid);
8385744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
8395744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8405744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    return true;
8415744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe}
8425744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8435744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampestatic void SetStructCapUserHeaderVersion(
8445744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        JNIEnv* env, jobject java_header, __user_cap_header_struct* c_header) {
8455744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    ScopedLocalRef<jclass> header_class(env, env->FindClass("android/system/StructCapUserHeader"));
8465744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (header_class.get() == nullptr) {
8475744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        env->ExceptionClear();
8485744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return;
8495744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
8505744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8515744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    static jfieldID version_fid = env->GetFieldID(header_class.get(), "version", "I");
8525744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (version_fid == nullptr) {
8535744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        env->ExceptionClear();
8545744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return;
8555744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
8565744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    env->SetIntField(java_header, version_fid, c_header->version);
8575744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe}
8585744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8595744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampestatic jobject CreateStructCapUserData(
8605744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        JNIEnv* env, jclass data_class, __user_cap_data_struct* c_data) {
8615744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (c_data == nullptr) {
8625744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        // Should not happen.
8635744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        jniThrowNullPointerException(env, "data is null");
8645744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return nullptr;
8655744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
8665744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8675744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    static jmethodID data_cons = env->GetMethodID(data_class, "<init>", "(III)V");
8685744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (data_cons == nullptr) {
8695744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return nullptr;
8705744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
8715744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8725744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    jint e = static_cast<jint>(c_data->effective);
8735744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    jint p = static_cast<jint>(c_data->permitted);
8745744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    jint i = static_cast<jint>(c_data->inheritable);
8755744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    return env->NewObject(data_class, data_cons, e, p, i);
8765744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe}
8775744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8785744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampestatic bool ReadStructCapUserData(JNIEnv* env, jobject java_data, __user_cap_data_struct* c_data) {
8795744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (java_data == nullptr) {
8805744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        jniThrowNullPointerException(env, "data is null");
8815744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return false;
8825744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
8835744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8845744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    ScopedLocalRef<jclass> data_class(env, env->FindClass("android/system/StructCapUserData"));
8855744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (data_class.get() == nullptr) {
8865744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return false;
8875744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
8885744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8895744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    {
8905744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        static jfieldID effective_fid = env->GetFieldID(data_class.get(), "effective", "I");
8915744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        if (effective_fid == nullptr) {
8925744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe            return false;
8935744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        }
8945744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        c_data->effective = env->GetIntField(java_data, effective_fid);
8955744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
8965744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8975744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    {
8985744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        static jfieldID permitted_fid = env->GetFieldID(data_class.get(), "permitted", "I");
8995744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        if (permitted_fid == nullptr) {
9005744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe            return false;
9015744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        }
9025744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        c_data->permitted = env->GetIntField(java_data, permitted_fid);
9035744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
9045744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
9055744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
9065744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    {
9075744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        static jfieldID inheritable_fid = env->GetFieldID(data_class.get(), "inheritable", "I");
9085744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        if (inheritable_fid == nullptr) {
9095744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe            return false;
9105744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        }
9115744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        c_data->inheritable = env->GetIntField(java_data, inheritable_fid);
9125744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
9135744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
9145744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    return true;
9155744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe}
9165744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
9175744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampestatic constexpr size_t kMaxCapUserDataLength = 2U;
9185744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#ifdef _LINUX_CAPABILITY_VERSION_1
9195744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampestatic_assert(kMaxCapUserDataLength >= _LINUX_CAPABILITY_U32S_1, "Length too small.");
9205744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#endif
9215744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#ifdef _LINUX_CAPABILITY_VERSION_2
9225744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampestatic_assert(kMaxCapUserDataLength >= _LINUX_CAPABILITY_U32S_2, "Length too small.");
9235744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#endif
9245744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#ifdef _LINUX_CAPABILITY_VERSION_3
9255744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampestatic_assert(kMaxCapUserDataLength >= _LINUX_CAPABILITY_U32S_3, "Length too small.");
9265744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#endif
9275744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#ifdef _LINUX_CAPABILITY_VERSION_4
9285744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampestatic_assert(false, "Unsupported capability version, please update.");
9295744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#endif
9305744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
9315744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampestatic size_t GetCapUserDataLength(uint32_t version) {
9325744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#ifdef _LINUX_CAPABILITY_VERSION_1
9335744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (version == _LINUX_CAPABILITY_VERSION_1) {
9345744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return _LINUX_CAPABILITY_U32S_1;
9355744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
9365744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#endif
9375744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#ifdef _LINUX_CAPABILITY_VERSION_2
9385744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (version == _LINUX_CAPABILITY_VERSION_2) {
9395744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return _LINUX_CAPABILITY_U32S_2;
9405744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
9415744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#endif
9425744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#ifdef _LINUX_CAPABILITY_VERSION_3
9435744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (version == _LINUX_CAPABILITY_VERSION_3) {
9445744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return _LINUX_CAPABILITY_U32S_3;
9455744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
9465744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#endif
9475744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    return 0;
9485744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe}
9495744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
9500965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_accept(JNIEnv* env, jobject, jobject javaFd, jobject javaSocketAddress) {
951553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes    sockaddr_storage ss;
952553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes    socklen_t sl = sizeof(ss);
953553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes    memset(&ss, 0, sizeof(ss));
9540ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    sockaddr* peer = (javaSocketAddress != NULL) ? reinterpret_cast<sockaddr*>(&ss) : NULL;
9550ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    socklen_t* peerLength = (javaSocketAddress != NULL) ? &sl : 0;
9561124a814d698ed6fd68ac501f5dddfa103d656fdElliott Hughes    jint clientFd = NET_FAILURE_RETRY(env, int, accept, javaFd, peer, peerLength);
9570ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    if (clientFd == -1 || !fillSocketAddress(env, javaSocketAddress, ss, *peerLength)) {
958553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes        close(clientFd);
959553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes        return NULL;
960553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes    }
961553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes    return (clientFd != -1) ? jniCreateFileDescriptor(env, clientFd) : NULL;
962553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes}
963553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes
9640965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jboolean Linux_access(JNIEnv* env, jobject, jstring javaPath, jint mode) {
965ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    ScopedUtfChars path(env, javaPath);
966ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    if (path.c_str() == NULL) {
967ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes        return JNI_FALSE;
968ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    }
96947cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes    int rc = TEMP_FAILURE_RETRY(access(path.c_str(), mode));
970dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes    if (rc == -1) {
9717e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes        throwErrnoException(env, "access");
972dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes    }
973ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    return (rc == 0);
974ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes}
975ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes
9760965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_bind(JNIEnv* env, jobject, jobject javaFd, jobject javaAddress, jint port) {
9771124a814d698ed6fd68ac501f5dddfa103d656fdElliott Hughes    // We don't need the return value because we'll already have thrown.
978b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti    (void) NET_IPV4_FALLBACK(env, int, bind, javaFd, javaAddress, port, NULL_ADDR_FORBIDDEN);
979da15009528cc8300a6251f1d0931ac8657c9fc31Elliott Hughes}
980da15009528cc8300a6251f1d0931ac8657c9fc31Elliott Hughes
9810965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_bindSocketAddress(
9828f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        JNIEnv* env, jobject, jobject javaFd, jobject javaSocketAddress) {
9838f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    sockaddr_storage ss;
9848f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    socklen_t sa_len;
9858f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    if (!javaSocketAddressToSockaddr(env, javaSocketAddress, ss, sa_len)) {
9868f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        return;  // Exception already thrown.
9878f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    }
9888f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline
9898f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    const sockaddr* sa = reinterpret_cast<const sockaddr*>(&ss);
9908f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    // We don't need the return value because we'll already have thrown.
9918f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    (void) NET_FAILURE_RETRY(env, int, bind, javaFd, sa, sa_len);
9928f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline}
9938f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline
9945744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampestatic jobjectArray Linux_capget(JNIEnv* env, jobject, jobject header) {
9955744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    // Convert Java header struct to kernel datastructure.
9965744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    __user_cap_header_struct cap_header;
9975744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (!ReadStructCapUserHeader(env, header, &cap_header)) {
9985744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        AssertException(env);
9995744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return nullptr;
10005744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
10015744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
10025744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    // Call capget.
10035744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    __user_cap_data_struct cap_data[kMaxCapUserDataLength];
10045744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (capget(&cap_header, &cap_data[0]) == -1) {
10055744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        // Check for EINVAL. In that case, mutate the header.
10065744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        if (errno == EINVAL) {
10075744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe            int saved_errno = errno;
10085744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe            SetStructCapUserHeaderVersion(env, header, &cap_header);
10095744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe            errno = saved_errno;
10105744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        }
10115744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        throwErrnoException(env, "capget");
10125744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return nullptr;
10135744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
10145744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
10155744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    // Create the result array.
10165744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    ScopedLocalRef<jclass> data_class(env, env->FindClass("android/system/StructCapUserData"));
10175744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (data_class.get() == nullptr) {
10185744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return nullptr;
10195744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
10205744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    size_t result_size = GetCapUserDataLength(cap_header.version);
10215744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    ScopedLocalRef<jobjectArray> result(
10225744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe            env, env->NewObjectArray(result_size, data_class.get(), nullptr));
10235744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (result.get() == nullptr) {
10245744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return nullptr;
10255744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
10265744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    // Translate the values we got.
10275744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    for (size_t i = 0; i < result_size; ++i) {
10285744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        ScopedLocalRef<jobject> value(
10295744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe                env, CreateStructCapUserData(env, data_class.get(), &cap_data[i]));
10305744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        if (value.get() == nullptr) {
10315744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe            AssertException(env);
10325744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe            return nullptr;
10335744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        }
10345744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        env->SetObjectArrayElement(result.get(), i, value.get());
10355744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
10365744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    return result.release();
10375744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe}
10385744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
10395744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampestatic void Linux_capset(
10405744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        JNIEnv* env, jobject, jobject header, jobjectArray data) {
10415744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    // Convert Java header struct to kernel datastructure.
10425744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    __user_cap_header_struct cap_header;
10435744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (!ReadStructCapUserHeader(env, header, &cap_header)) {
10445744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        AssertException(env);
10455744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return;
10465744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
10475744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    size_t result_size = GetCapUserDataLength(cap_header.version);
10485744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    // Ensure that the array has the expected length.
10495744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (env->GetArrayLength(data) != static_cast<jint>(result_size)) {
10505744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        jniThrowExceptionFmt(env,
10515744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe                             "java/lang/IllegalArgumentException",
10525744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe                             "Unsupported input length %d (expected %zu)",
10535744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe                             env->GetArrayLength(data),
10545744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe                             result_size);
10555744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return;
10565744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
10575744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
10585744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    __user_cap_data_struct cap_data[kMaxCapUserDataLength];
10595744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    // Translate the values we got.
10605744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    for (size_t i = 0; i < result_size; ++i) {
10615744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        ScopedLocalRef<jobject> value(env, env->GetObjectArrayElement(data, i));
10625744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        if (!ReadStructCapUserData(env, value.get(), &cap_data[i])) {
10635744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe            AssertException(env);
10645744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe            return;
10655744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        }
10665744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
10675744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
10685744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    throwIfMinusOne(env, "capset", capset(&cap_header, &cap_data[0]));
10695744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe}
10705744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
10710965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_chmod(JNIEnv* env, jobject, jstring javaPath, jint mode) {
1072b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes    ScopedUtfChars path(env, javaPath);
1073b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes    if (path.c_str() == NULL) {
1074b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes        return;
1075b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes    }
1076b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes    throwIfMinusOne(env, "chmod", TEMP_FAILURE_RETRY(chmod(path.c_str(), mode)));
1077b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes}
1078b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes
10790965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_chown(JNIEnv* env, jobject, jstring javaPath, jint uid, jint gid) {
108044f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes    ScopedUtfChars path(env, javaPath);
108144f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes    if (path.c_str() == NULL) {
108244f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes        return;
108344f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes    }
108444f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes    throwIfMinusOne(env, "chown", TEMP_FAILURE_RETRY(chown(path.c_str(), uid, gid)));
108544f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes}
108644f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes
10870965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_close(JNIEnv* env, jobject, jobject javaFd) {
1088462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes    // Get the FileDescriptor's 'fd' field and clear it.
1089462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes    // We need to do this before we can throw an IOException (http://b/3222087).
1090462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
1091462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes    jniSetFileDescriptorOfFD(env, javaFd, -1);
1092462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes
1093462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes    // Even if close(2) fails with EINTR, the fd will have been closed.
1094462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes    // Using TEMP_FAILURE_RETRY will either lead to EBADF or closing someone else's fd.
1095462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes    // http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
1096462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes    throwIfMinusOne(env, "close", close(fd));
1097462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes}
1098462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes
10990965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_connect(JNIEnv* env, jobject, jobject javaFd, jobject javaAddress, jint port) {
1100b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti    (void) NET_IPV4_FALLBACK(env, int, connect, javaFd, javaAddress, port, NULL_ADDR_FORBIDDEN);
1101996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes}
1102996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes
11030965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_connectSocketAddress(
11048f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        JNIEnv* env, jobject, jobject javaFd, jobject javaSocketAddress) {
11058f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    sockaddr_storage ss;
11068f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    socklen_t sa_len;
11078f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    if (!javaSocketAddressToSockaddr(env, javaSocketAddress, ss, sa_len)) {
11088f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        return;  // Exception already thrown.
11098f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    }
11108f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline
11118f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    const sockaddr* sa = reinterpret_cast<const sockaddr*>(&ss);
11128f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    // We don't need the return value because we'll already have thrown.
11138f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    (void) NET_FAILURE_RETRY(env, int, connect, javaFd, sa, sa_len);
11148f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline}
11158f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline
11160965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_dup(JNIEnv* env, jobject, jobject javaOldFd) {
1117396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes    int oldFd = jniGetFDFromFileDescriptor(env, javaOldFd);
1118396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes    int newFd = throwIfMinusOne(env, "dup", TEMP_FAILURE_RETRY(dup(oldFd)));
1119396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes    return (newFd != -1) ? jniCreateFileDescriptor(env, newFd) : NULL;
1120396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes}
1121396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes
11220965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_dup2(JNIEnv* env, jobject, jobject javaOldFd, jint newFd) {
1123396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes    int oldFd = jniGetFDFromFileDescriptor(env, javaOldFd);
1124396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes    int fd = throwIfMinusOne(env, "dup2", TEMP_FAILURE_RETRY(dup2(oldFd, newFd)));
1125396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes    return (fd != -1) ? jniCreateFileDescriptor(env, fd) : NULL;
1126396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes}
1127396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes
11280965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobjectArray Linux_environ(JNIEnv* env, jobject) {
1129ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    extern char** environ; // Standard, but not in any header file.
1130ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    return toStringArray(env, environ);
1131ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes}
1132ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes
11330965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_execve(JNIEnv* env, jobject, jstring javaFilename, jobjectArray javaArgv, jobjectArray javaEnvp) {
1134798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich    ScopedUtfChars path(env, javaFilename);
1135798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich    if (path.c_str() == NULL) {
1136798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich        return;
1137798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich    }
1138798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich
1139ad9208affa02f92a6b85354a33123d51d80febe1Elliott Hughes    ExecStrings argv(env, javaArgv);
1140ad9208affa02f92a6b85354a33123d51d80febe1Elliott Hughes    ExecStrings envp(env, javaEnvp);
1141fa542091e45db699a937c5ac0191194405107827Elliott Hughes    TEMP_FAILURE_RETRY(execve(path.c_str(), argv.get(), envp.get()));
1142798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich
1143798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich    throwErrnoException(env, "execve");
1144798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich}
1145798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich
11460965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_execv(JNIEnv* env, jobject, jstring javaFilename, jobjectArray javaArgv) {
1147798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich    ScopedUtfChars path(env, javaFilename);
1148798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich    if (path.c_str() == NULL) {
1149798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich        return;
1150798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich    }
1151798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich
1152ad9208affa02f92a6b85354a33123d51d80febe1Elliott Hughes    ExecStrings argv(env, javaArgv);
1153fa542091e45db699a937c5ac0191194405107827Elliott Hughes    TEMP_FAILURE_RETRY(execv(path.c_str(), argv.get()));
1154798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich
1155798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich    throwErrnoException(env, "execv");
1156798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich}
1157798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich
11580965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_fchmod(JNIEnv* env, jobject, jobject javaFd, jint mode) {
115944f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
116044f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes    throwIfMinusOne(env, "fchmod", TEMP_FAILURE_RETRY(fchmod(fd, mode)));
116144f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes}
116244f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes
11630965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_fchown(JNIEnv* env, jobject, jobject javaFd, jint uid, jint gid) {
116444f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
116544f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes    throwIfMinusOne(env, "fchown", TEMP_FAILURE_RETRY(fchown(fd, uid, gid)));
116644f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes}
116744f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes
11680965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_fcntlFlock(JNIEnv* env, jobject, jobject javaFd, jint cmd, jobject javaFlock) {
1169fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    static jfieldID typeFid = env->GetFieldID(JniConstants::structFlockClass, "l_type", "S");
1170fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    static jfieldID whenceFid = env->GetFieldID(JniConstants::structFlockClass, "l_whence", "S");
1171fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    static jfieldID startFid = env->GetFieldID(JniConstants::structFlockClass, "l_start", "J");
1172fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    static jfieldID lenFid = env->GetFieldID(JniConstants::structFlockClass, "l_len", "J");
1173fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    static jfieldID pidFid = env->GetFieldID(JniConstants::structFlockClass, "l_pid", "I");
1174fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes
1175fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    struct flock64 lock;
1176fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    memset(&lock, 0, sizeof(lock));
1177fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    lock.l_type = env->GetShortField(javaFlock, typeFid);
1178fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    lock.l_whence = env->GetShortField(javaFlock, whenceFid);
1179fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    lock.l_start = env->GetLongField(javaFlock, startFid);
1180fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    lock.l_len = env->GetLongField(javaFlock, lenFid);
1181fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    lock.l_pid = env->GetIntField(javaFlock, pidFid);
1182fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes
11838add3229ceb13f2aa5d15b84cc59f5ecc6b90214Neil Fuller    int rc = IO_FAILURE_RETRY(env, int, fcntl, javaFd, cmd, &lock);
1184fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    if (rc != -1) {
1185fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes        env->SetShortField(javaFlock, typeFid, lock.l_type);
1186fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes        env->SetShortField(javaFlock, whenceFid, lock.l_whence);
1187fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes        env->SetLongField(javaFlock, startFid, lock.l_start);
1188fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes        env->SetLongField(javaFlock, lenFid, lock.l_len);
1189fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes        env->SetIntField(javaFlock, pidFid, lock.l_pid);
1190fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    }
1191fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    return rc;
1192fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes}
1193fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes
11940965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_fcntlInt(JNIEnv* env, jobject, jobject javaFd, jint cmd, jint arg) {
1195c8d9ea662de6f4856b28907b4119087cfc5a44d2Narayan Kamath    int fd = jniGetFDFromFileDescriptor(env, javaFd);
1196c8d9ea662de6f4856b28907b4119087cfc5a44d2Narayan Kamath    return throwIfMinusOne(env, "fcntl", TEMP_FAILURE_RETRY(fcntl(fd, cmd, arg)));
1197c8d9ea662de6f4856b28907b4119087cfc5a44d2Narayan Kamath}
1198c8d9ea662de6f4856b28907b4119087cfc5a44d2Narayan Kamath
11990965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_fcntlVoid(JNIEnv* env, jobject, jobject javaFd, jint cmd) {
1200c8d9ea662de6f4856b28907b4119087cfc5a44d2Narayan Kamath    int fd = jniGetFDFromFileDescriptor(env, javaFd);
1201c8d9ea662de6f4856b28907b4119087cfc5a44d2Narayan Kamath    return throwIfMinusOne(env, "fcntl", TEMP_FAILURE_RETRY(fcntl(fd, cmd)));
1202c8d9ea662de6f4856b28907b4119087cfc5a44d2Narayan Kamath}
1203c8d9ea662de6f4856b28907b4119087cfc5a44d2Narayan Kamath
12040965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_fdatasync(JNIEnv* env, jobject, jobject javaFd) {
120552724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
12067e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes    throwIfMinusOne(env, "fdatasync", TEMP_FAILURE_RETRY(fdatasync(fd)));
120752724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes}
120852724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes
12090965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_fstat(JNIEnv* env, jobject, jobject javaFd) {
121047cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
121113a70e6c04157064fc8a61ecfcb1d863f29c239dYi Kong    struct stat64 sb;
121213a70e6c04157064fc8a61ecfcb1d863f29c239dYi Kong    int rc = TEMP_FAILURE_RETRY(fstat64(fd, &sb));
1213dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes    if (rc == -1) {
12147e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes        throwErrnoException(env, "fstat");
121547cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes        return NULL;
121647cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes    }
121747cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes    return makeStructStat(env, sb);
121847cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes}
121947cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes
12200965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_fstatvfs(JNIEnv* env, jobject, jobject javaFd) {
122159fa7163774d6930a174bc038414a4b780581957Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
1222721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes    struct statvfs sb;
1223721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes    int rc = TEMP_FAILURE_RETRY(fstatvfs(fd, &sb));
122459fa7163774d6930a174bc038414a4b780581957Elliott Hughes    if (rc == -1) {
1225721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes        throwErrnoException(env, "fstatvfs");
122659fa7163774d6930a174bc038414a4b780581957Elliott Hughes        return NULL;
122759fa7163774d6930a174bc038414a4b780581957Elliott Hughes    }
1228721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes    return makeStructStatVfs(env, sb);
122959fa7163774d6930a174bc038414a4b780581957Elliott Hughes}
123059fa7163774d6930a174bc038414a4b780581957Elliott Hughes
12310965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_fsync(JNIEnv* env, jobject, jobject javaFd) {
123252724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
12337e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes    throwIfMinusOne(env, "fsync", TEMP_FAILURE_RETRY(fsync(fd)));
1234f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes}
1235f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes
12360965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_ftruncate(JNIEnv* env, jobject, jobject javaFd, jlong length) {
1237f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
12387e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes    throwIfMinusOne(env, "ftruncate", TEMP_FAILURE_RETRY(ftruncate64(fd, length)));
123952724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes}
124052724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes
12410965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jstring Linux_gai_strerror(JNIEnv* env, jobject, jint error) {
12424f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    return env->NewStringUTF(gai_strerror(error));
12434f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes}
12444f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes
12450965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobjectArray Linux_android_getaddrinfo(JNIEnv* env, jobject, jstring javaNode,
12463e58734d651080009c9190c7062837fca5c7cf4ePaul Jensen        jobject javaHints, jint netId) {
12471c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    ScopedUtfChars node(env, javaNode);
12481c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    if (node.c_str() == NULL) {
12491c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        return NULL;
12501c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    }
12511c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes
12521c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    static jfieldID flagsFid = env->GetFieldID(JniConstants::structAddrinfoClass, "ai_flags", "I");
12531c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    static jfieldID familyFid = env->GetFieldID(JniConstants::structAddrinfoClass, "ai_family", "I");
12541c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    static jfieldID socktypeFid = env->GetFieldID(JniConstants::structAddrinfoClass, "ai_socktype", "I");
12551c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    static jfieldID protocolFid = env->GetFieldID(JniConstants::structAddrinfoClass, "ai_protocol", "I");
12561c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes
12571c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    addrinfo hints;
12581c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    memset(&hints, 0, sizeof(hints));
12591c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    hints.ai_flags = env->GetIntField(javaHints, flagsFid);
12601c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    hints.ai_family = env->GetIntField(javaHints, familyFid);
12611c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    hints.ai_socktype = env->GetIntField(javaHints, socktypeFid);
12621c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    hints.ai_protocol = env->GetIntField(javaHints, protocolFid);
12631c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes
12641c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    addrinfo* addressList = NULL;
126575cf14944d476670f6f915e5efd849e238a16250Elliott Hughes    errno = 0;
12663e58734d651080009c9190c7062837fca5c7cf4ePaul Jensen    int rc = android_getaddrinfofornet(node.c_str(), NULL, &hints, netId, 0, &addressList);
1267b3aacde3d8af759ee4a7b395c636ea360547d92dIan Rogers    std::unique_ptr<addrinfo, addrinfo_deleter> addressListDeleter(addressList);
12681c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    if (rc != 0) {
12693e58734d651080009c9190c7062837fca5c7cf4ePaul Jensen        throwGaiException(env, "android_getaddrinfo", rc);
12701c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        return NULL;
12711c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    }
12721c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes
12731c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    // Count results so we know how to size the output array.
12741c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    int addressCount = 0;
12751c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    for (addrinfo* ai = addressList; ai != NULL; ai = ai->ai_next) {
12761c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) {
12771c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes            ++addressCount;
12781c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        } else {
12793e58734d651080009c9190c7062837fca5c7cf4ePaul Jensen            ALOGE("android_getaddrinfo unexpected ai_family %i", ai->ai_family);
12801c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        }
12811c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    }
12821c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    if (addressCount == 0) {
12831c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        return NULL;
12841c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    }
12851c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes
12861c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    // Prepare output array.
12871c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    jobjectArray result = env->NewObjectArray(addressCount, JniConstants::inetAddressClass, NULL);
12881c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    if (result == NULL) {
12891c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        return NULL;
12901c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    }
12911c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes
12921c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    // Examine returned addresses one by one, save them in the output array.
12931c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    int index = 0;
12941c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    for (addrinfo* ai = addressList; ai != NULL; ai = ai->ai_next) {
12951c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) {
12961c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes            // Unknown address family. Skip this address.
12973e58734d651080009c9190c7062837fca5c7cf4ePaul Jensen            ALOGE("android_getaddrinfo unexpected ai_family %i", ai->ai_family);
12981c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes            continue;
12991c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        }
13001c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes
13011c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        // Convert each IP address into a Java byte array.
1302482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes        sockaddr_storage& address = *reinterpret_cast<sockaddr_storage*>(ai->ai_addr);
130323ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes        ScopedLocalRef<jobject> inetAddress(env, sockaddrToInetAddress(env, address, NULL));
13041c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        if (inetAddress.get() == NULL) {
13051c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes            return NULL;
13061c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        }
13071c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        env->SetObjectArrayElement(result, index, inetAddress.get());
13081c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        ++index;
13091c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    }
13101c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    return result;
13111c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes}
13121c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes
13130965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_getegid(JNIEnv*, jobject) {
1314564312855784c9ae57e2af73affc48b0807b13eeElliott Hughes    return getegid();
1315396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes}
1316396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes
13170965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_geteuid(JNIEnv*, jobject) {
1318564312855784c9ae57e2af73affc48b0807b13eeElliott Hughes    return geteuid();
1319396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes}
1320396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes
13210965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_getgid(JNIEnv*, jobject) {
1322564312855784c9ae57e2af73affc48b0807b13eeElliott Hughes    return getgid();
1323396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes}
1324396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes
132544177e6982a62506127a857070a2452956c3f0f1Enrico Granatastatic jintArray Linux_getgroups(JNIEnv* env, jobject) {
132644177e6982a62506127a857070a2452956c3f0f1Enrico Granata    int ngrps = throwIfMinusOne(env, "getgroups", getgroups(0, nullptr));
132744177e6982a62506127a857070a2452956c3f0f1Enrico Granata    if (ngrps == -1) {
132844177e6982a62506127a857070a2452956c3f0f1Enrico Granata        return NULL;
132944177e6982a62506127a857070a2452956c3f0f1Enrico Granata    }
133044177e6982a62506127a857070a2452956c3f0f1Enrico Granata    std::vector<gid_t> groups(ngrps, 0);
133144177e6982a62506127a857070a2452956c3f0f1Enrico Granata    ngrps = throwIfMinusOne(env, "getgroups", getgroups(ngrps, &groups[0]));
133244177e6982a62506127a857070a2452956c3f0f1Enrico Granata    if (ngrps == -1) {
133344177e6982a62506127a857070a2452956c3f0f1Enrico Granata        return NULL;
133444177e6982a62506127a857070a2452956c3f0f1Enrico Granata    }
133544177e6982a62506127a857070a2452956c3f0f1Enrico Granata    jintArray out = env->NewIntArray(ngrps);
133644177e6982a62506127a857070a2452956c3f0f1Enrico Granata    if ((out != NULL) && (ngrps > 0)) {
133744177e6982a62506127a857070a2452956c3f0f1Enrico Granata      env->SetIntArrayRegion(out, 0, ngrps, reinterpret_cast<int*>(&groups[0]));
133844177e6982a62506127a857070a2452956c3f0f1Enrico Granata    }
133944177e6982a62506127a857070a2452956c3f0f1Enrico Granata
134044177e6982a62506127a857070a2452956c3f0f1Enrico Granata    return out;
134144177e6982a62506127a857070a2452956c3f0f1Enrico Granata}
134244177e6982a62506127a857070a2452956c3f0f1Enrico Granata
13430965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jstring Linux_getenv(JNIEnv* env, jobject, jstring javaName) {
1344ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes    ScopedUtfChars name(env, javaName);
1345ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes    if (name.c_str() == NULL) {
1346ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes        return NULL;
1347ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes    }
1348ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes    return env->NewStringUTF(getenv(name.c_str()));
1349ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes}
1350ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes
13510965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jstring Linux_getnameinfo(JNIEnv* env, jobject, jobject javaAddress, jint flags) {
13524f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    sockaddr_storage ss;
1353482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes    socklen_t sa_len;
1354482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes    if (!inetAddressToSockaddrVerbatim(env, javaAddress, 0, ss, sa_len)) {
13554f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes        return NULL;
13564f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    }
13574f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    char buf[NI_MAXHOST]; // NI_MAXHOST is longer than INET6_ADDRSTRLEN.
135875cf14944d476670f6f915e5efd849e238a16250Elliott Hughes    errno = 0;
1359482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes    int rc = getnameinfo(reinterpret_cast<sockaddr*>(&ss), sa_len, buf, sizeof(buf), NULL, 0, flags);
13604f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    if (rc != 0) {
13614f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes        throwGaiException(env, "getnameinfo", rc);
13624f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes        return NULL;
13634f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    }
13644f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    return env->NewStringUTF(buf);
13654f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes}
13664f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes
13670965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_getpeername(JNIEnv* env, jobject, jobject javaFd) {
1368482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  return doGetSockName(env, javaFd, false);
1369482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes}
1370482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes
13710965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_getpgid(JNIEnv* env, jobject, jint pid) {
13728f0f2ac7fcd8f366a78cc51181d065ab93385e46Elliott Hughes    return throwIfMinusOne(env, "getpgid", TEMP_FAILURE_RETRY(getpgid(pid)));
13738f0f2ac7fcd8f366a78cc51181d065ab93385e46Elliott Hughes}
13748f0f2ac7fcd8f366a78cc51181d065ab93385e46Elliott Hughes
13750965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_getpid(JNIEnv*, jobject) {
1376fa542091e45db699a937c5ac0191194405107827Elliott Hughes    return TEMP_FAILURE_RETRY(getpid());
1377396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes}
1378396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes
13790965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_getppid(JNIEnv*, jobject) {
1380fa542091e45db699a937c5ac0191194405107827Elliott Hughes    return TEMP_FAILURE_RETRY(getppid());
1381396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes}
1382396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes
13830965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_getpwnam(JNIEnv* env, jobject, jstring javaName) {
1384d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    ScopedUtfChars name(env, javaName);
1385d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    if (name.c_str() == NULL) {
1386d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes        return NULL;
1387d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    }
1388d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    return Passwd(env).getpwnam(name.c_str());
1389d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes}
1390d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes
13910965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_getpwuid(JNIEnv* env, jobject, jint uid) {
1392d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    return Passwd(env).getpwuid(uid);
1393d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes}
1394d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes
1395e873cd1285c04da110758df066b4bd40ad6eb93dNarayan Kamathstatic jobject Linux_getrlimit(JNIEnv* env, jobject, jint resource) {
1396e873cd1285c04da110758df066b4bd40ad6eb93dNarayan Kamath    struct rlimit r;
1397e873cd1285c04da110758df066b4bd40ad6eb93dNarayan Kamath    if (throwIfMinusOne(env, "getrlimit", TEMP_FAILURE_RETRY(getrlimit(resource, &r))) == -1) {
1398e873cd1285c04da110758df066b4bd40ad6eb93dNarayan Kamath        return nullptr;
1399e873cd1285c04da110758df066b4bd40ad6eb93dNarayan Kamath    }
1400e873cd1285c04da110758df066b4bd40ad6eb93dNarayan Kamath
1401e873cd1285c04da110758df066b4bd40ad6eb93dNarayan Kamath    ScopedLocalRef<jclass> rlimit_class(env, env->FindClass("android/system/StructRlimit"));
1402e873cd1285c04da110758df066b4bd40ad6eb93dNarayan Kamath    jmethodID ctor = env->GetMethodID(rlimit_class.get(), "<init>", "(JJ)V");
140393a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    if (ctor == NULL) {
140493a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        return NULL;
140593a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    }
1406e785612bdf3b0112b5a1854bdf241f0ef87a3171Narayan Kamath    return env->NewObject(rlimit_class.get(), ctor,
1407e785612bdf3b0112b5a1854bdf241f0ef87a3171Narayan Kamath                          static_cast<jlong>(r.rlim_cur),
1408e785612bdf3b0112b5a1854bdf241f0ef87a3171Narayan Kamath                          static_cast<jlong>(r.rlim_max));
1409e873cd1285c04da110758df066b4bd40ad6eb93dNarayan Kamath}
1410e873cd1285c04da110758df066b4bd40ad6eb93dNarayan Kamath
14110965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_getsockname(JNIEnv* env, jobject, jobject javaFd) {
1412482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  return doGetSockName(env, javaFd, true);
14130a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes}
14140a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes
14150965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_getsockoptByte(JNIEnv* env, jobject, jobject javaFd, jint level, jint option) {
14160a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
14170a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    u_char result = 0;
14180a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    socklen_t size = sizeof(result);
14190a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    throwIfMinusOne(env, "getsockopt", TEMP_FAILURE_RETRY(getsockopt(fd, level, option, &result, &size)));
14200a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    return result;
14210a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes}
14220a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes
14230965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_getsockoptInAddr(JNIEnv* env, jobject, jobject javaFd, jint level, jint option) {
14240a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
14250a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    sockaddr_storage ss;
14260a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    memset(&ss, 0, sizeof(ss));
14270a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    ss.ss_family = AF_INET; // This is only for the IPv4-only IP_MULTICAST_IF.
14280a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    sockaddr_in* sa = reinterpret_cast<sockaddr_in*>(&ss);
14290a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    socklen_t size = sizeof(sa->sin_addr);
14300a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    int rc = TEMP_FAILURE_RETRY(getsockopt(fd, level, option, &sa->sin_addr, &size));
14310a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    if (rc == -1) {
14320a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes        throwErrnoException(env, "getsockopt");
14330a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes        return NULL;
14340a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    }
1435482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes    return sockaddrToInetAddress(env, ss, NULL);
14360a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes}
14370a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes
14380965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_getsockoptInt(JNIEnv* env, jobject, jobject javaFd, jint level, jint option) {
14390a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
14400a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    jint result = 0;
14410a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    socklen_t size = sizeof(result);
14420a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    throwIfMinusOne(env, "getsockopt", TEMP_FAILURE_RETRY(getsockopt(fd, level, option, &result, &size)));
14430a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    return result;
14440a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes}
14450a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes
14460965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_getsockoptLinger(JNIEnv* env, jobject, jobject javaFd, jint level, jint option) {
14470a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
14480a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    struct linger l;
14490a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    socklen_t size = sizeof(l);
14500a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    memset(&l, 0, size);
14510a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    int rc = TEMP_FAILURE_RETRY(getsockopt(fd, level, option, &l, &size));
14520a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    if (rc == -1) {
14530a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes        throwErrnoException(env, "getsockopt");
14540a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes        return NULL;
14550a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    }
14560a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    return makeStructLinger(env, l);
14570a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes}
14580a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes
14590965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_getsockoptTimeval(JNIEnv* env, jobject, jobject javaFd, jint level, jint option) {
14600a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
14610a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    struct timeval tv;
14620a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    socklen_t size = sizeof(tv);
14630a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    memset(&tv, 0, size);
14640a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    int rc = TEMP_FAILURE_RETRY(getsockopt(fd, level, option, &tv, &size));
14650a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    if (rc == -1) {
14660a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes        throwErrnoException(env, "getsockopt");
14670a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes        return NULL;
14680a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    }
14690a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    return makeStructTimeval(env, tv);
14700a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes}
14710a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes
14720965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_getsockoptUcred(JNIEnv* env, jobject, jobject javaFd, jint level, jint option) {
1473482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  int fd = jniGetFDFromFileDescriptor(env, javaFd);
1474482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  struct ucred u;
1475482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  socklen_t size = sizeof(u);
1476482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  memset(&u, 0, size);
1477482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  int rc = TEMP_FAILURE_RETRY(getsockopt(fd, level, option, &u, &size));
1478482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  if (rc == -1) {
1479482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes    throwErrnoException(env, "getsockopt");
1480482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes    return NULL;
1481482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  }
1482482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  return makeStructUcred(env, u);
1483482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes}
1484482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes
14850965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_gettid(JNIEnv* env __unused, jobject) {
1486efe42934a8523f2b051a351e5eceebf6216454aeElliott Hughes#if defined(__BIONIC__)
1487fa542091e45db699a937c5ac0191194405107827Elliott Hughes  return TEMP_FAILURE_RETRY(gettid());
14883deabd220cf7b1ca0824987e90b8ecc07087f05aIan Rogers#else
1489069525a39125c203b658c805685b6045a7d4dfebElliott Hughes  return syscall(__NR_gettid);
14903deabd220cf7b1ca0824987e90b8ecc07087f05aIan Rogers#endif
1491069525a39125c203b658c805685b6045a7d4dfebElliott Hughes}
1492069525a39125c203b658c805685b6045a7d4dfebElliott Hughes
14930965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_getuid(JNIEnv*, jobject) {
1494564312855784c9ae57e2af73affc48b0807b13eeElliott Hughes    return getuid();
1495396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes}
1496396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes
14970965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jbyteArray Linux_getxattr(JNIEnv* env, jobject, jstring javaPath,
149840afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        jstring javaName) {
149990246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    ScopedUtfChars path(env, javaPath);
150090246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    if (path.c_str() == NULL) {
150140afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        return NULL;
150290246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    }
150390246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    ScopedUtfChars name(env, javaName);
150490246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    if (name.c_str() == NULL) {
150540afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        return NULL;
150690246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    }
150740afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong
150840afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong    while (true) {
150940afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        // Get the current size of the named extended attribute.
151040afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        ssize_t valueLength;
151140afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        if ((valueLength = getxattr(path.c_str(), name.c_str(), NULL, 0)) < 0) {
151240afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong            throwErrnoException(env, "getxattr");
151340afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong            return NULL;
151440afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        }
151540afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong
151640afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        // Create the actual byte array.
151740afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        std::vector<char> buf(valueLength);
151840afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        if ((valueLength = getxattr(path.c_str(), name.c_str(), buf.data(), valueLength)) < 0) {
151940afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong            if (errno == ERANGE) {
152040afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong                // The attribute value has changed since last getxattr call and buf no longer fits,
152140afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong                // try again.
152240afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong                continue;
152340afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong            }
152440afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong            throwErrnoException(env, "getxattr");
152540afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong            return NULL;
152640afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        }
152740afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        jbyteArray array = env->NewByteArray(valueLength);
152840afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        if (array == NULL) {
152940afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong            return NULL;
153040afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        }
153140afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        env->SetByteArrayRegion(array, 0, valueLength, reinterpret_cast<const jbyte*>(buf.data()));
153240afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        return array;
153390246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    }
153490246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey}
153590246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey
15360965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobjectArray Linux_getifaddrs(JNIEnv* env, jobject) {
15376d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    static jmethodID ctor = env->GetMethodID(JniConstants::structIfaddrs, "<init>",
15386d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong            "(Ljava/lang/String;ILjava/net/InetAddress;Ljava/net/InetAddress;Ljava/net/InetAddress;[B)V");
153993a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    if (ctor == NULL) {
154093a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        return NULL;
154193a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    }
15426d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong
15436d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    ifaddrs* ifaddr;
15446d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    int rc = TEMP_FAILURE_RETRY(getifaddrs(&ifaddr));
15456d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    if (rc == -1) {
15466d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        throwErrnoException(env, "getifaddrs");
15476d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        return NULL;
15486d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    }
15496d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    std::unique_ptr<ifaddrs, decltype(&freeifaddrs)> ifaddrPtr(ifaddr, freeifaddrs);
15506d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong
15516d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    // Count results so we know how to size the output array.
15526d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    jint ifCount = 0;
15536d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    for (ifaddrs* ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
15546d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        ++ifCount;
15556d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    }
15566d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong
15576d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    // Prepare output array.
15586d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    jobjectArray result = env->NewObjectArray(ifCount, JniConstants::structIfaddrs, NULL);
15596d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    if (result == NULL) {
15606d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        return NULL;
15616d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    }
15626d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong
15636d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    // Traverse the list and populate the output array.
15646d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    int index = 0;
15656d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    for (ifaddrs* ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next, ++index) {
15666d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        TO_JAVA_STRING(name, ifa->ifa_name);
15676d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        jint flags = ifa->ifa_flags;
15686d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        sockaddr_storage* interfaceAddr =
15696d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong            reinterpret_cast<sockaddr_storage*>(ifa->ifa_addr);
15706d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        sockaddr_storage* netmaskAddr =
15716d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong            reinterpret_cast<sockaddr_storage*>(ifa->ifa_netmask);
15726d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        sockaddr_storage* broadAddr =
15736d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong            reinterpret_cast<sockaddr_storage*>(ifa->ifa_broadaddr);
15746d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong
15756d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        jobject addr, netmask, broad;
15766d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        jbyteArray hwaddr = NULL;
15776d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        if (interfaceAddr != NULL) {
15786d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong            switch (interfaceAddr->ss_family) {
15796d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong            case AF_INET:
15806d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong            case AF_INET6:
15816d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                // IPv4 / IPv6.
15826d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                // interfaceAddr and netmaskAddr are never null.
15836d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                if ((addr = sockaddrToInetAddress(env, *interfaceAddr, NULL)) == NULL) {
15846d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                    return NULL;
15856d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                }
15866d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                if ((netmask = sockaddrToInetAddress(env, *netmaskAddr, NULL)) == NULL) {
15876d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                    return NULL;
15886d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                }
15896d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                if (broadAddr != NULL && (ifa->ifa_flags & IFF_BROADCAST)) {
15906d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                    if ((broad = sockaddrToInetAddress(env, *broadAddr, NULL)) == NULL) {
15916d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                        return NULL;
15926d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                    }
15936d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                } else {
15946d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                    broad = NULL;
15956d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                }
15966d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                break;
15976d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong            case AF_PACKET:
15986d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                // Raw Interface.
15996d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                sockaddr_ll* sll = reinterpret_cast<sockaddr_ll*>(ifa->ifa_addr);
16006d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong
16016d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                bool allZero = true;
16026d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                for (int i = 0; i < sll->sll_halen; ++i) {
16036d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                    if (sll->sll_addr[i] != 0) {
16046d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                        allZero = false;
16056d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                        break;
16066d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                    }
16076d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                }
16086d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong
16096d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                if (!allZero) {
16106d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                    hwaddr = env->NewByteArray(sll->sll_halen);
16116d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                    if (hwaddr == NULL) {
16126d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                        return NULL;
16136d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                    }
16146d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                    env->SetByteArrayRegion(hwaddr, 0, sll->sll_halen,
16156d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                                            reinterpret_cast<const jbyte*>(sll->sll_addr));
16166d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                }
16176d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                addr = netmask = broad = NULL;
16186d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                break;
16196d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong            }
16206d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        } else {
16216d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong            // Preserve the entry even if the interface has no interface address.
16226d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong            // http://b/29243557/
16236d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong            addr = netmask = broad = NULL;
16246d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        }
16256d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong
16266d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        jobject o = env->NewObject(JniConstants::structIfaddrs, ctor, name, flags, addr, netmask,
16276d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                                   broad, hwaddr);
162893a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        if (o == NULL) {
162993a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak            return NULL;
163093a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        }
16316d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        env->SetObjectArrayElement(result, index, o);
16326d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    }
16336d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong
16346d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    return result;
16356d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong}
16366d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong
16370965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jstring Linux_if_indextoname(JNIEnv* env, jobject, jint index) {
1638a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    char buf[IF_NAMESIZE];
1639a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    char* name = if_indextoname(index, buf);
1640a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    // if_indextoname(3) returns NULL on failure, which will come out of NewStringUTF unscathed.
1641a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    // There's no useful information in errno, so we don't bother throwing. Callers can null-check.
1642a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    return env->NewStringUTF(name);
1643a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes}
1644a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes
16450965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_if_nametoindex(JNIEnv* env, jobject, jstring name) {
16466d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    ScopedUtfChars cname(env, name);
1647507ae71a0387dbf4ec17e5eef27b9d3d6d691986Yi Kong    if (cname.c_str() == NULL) {
1648507ae71a0387dbf4ec17e5eef27b9d3d6d691986Yi Kong        return 0;
1649507ae71a0387dbf4ec17e5eef27b9d3d6d691986Yi Kong    }
1650507ae71a0387dbf4ec17e5eef27b9d3d6d691986Yi Kong
16516d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    // There's no useful information in errno, so we don't bother throwing. Callers can zero-check.
16526d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    return if_nametoindex(cname.c_str());
16536d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong}
16546d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong
16550965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_inet_pton(JNIEnv* env, jobject, jint family, jstring javaName) {
16561c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    ScopedUtfChars name(env, javaName);
16571c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    if (name.c_str() == NULL) {
16581c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        return NULL;
16591c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    }
16601c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    sockaddr_storage ss;
16611c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    memset(&ss, 0, sizeof(ss));
1662fc041ff241f9a7556e72236f130de0215ecd17dbElliott Hughes    // sockaddr_in and sockaddr_in6 are at the same address, so we can use either here.
1663fc041ff241f9a7556e72236f130de0215ecd17dbElliott Hughes    void* dst = &reinterpret_cast<sockaddr_in*>(&ss)->sin_addr;
1664fc041ff241f9a7556e72236f130de0215ecd17dbElliott Hughes    if (inet_pton(family, name.c_str(), dst) != 1) {
16651c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        return NULL;
16661c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    }
1667fc041ff241f9a7556e72236f130de0215ecd17dbElliott Hughes    ss.ss_family = family;
1668482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes    return sockaddrToInetAddress(env, ss, NULL);
16691c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes}
16701c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes
16710965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_ioctlFlags(JNIEnv* env, jobject, jobject javaFd, jstring javaInterfaceName) {
167245348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong     struct ifreq req;
167345348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong     if (!fillIfreq(env, javaInterfaceName, req)) {
167445348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong        return 0;
167545348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong     }
167645348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong     int fd = jniGetFDFromFileDescriptor(env, javaFd);
167745348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong     throwIfMinusOne(env, "ioctl", TEMP_FAILURE_RETRY(ioctl(fd, SIOCGIFFLAGS, &req)));
167845348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong     return req.ifr_flags;
167945348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong}
168045348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong
16810965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_ioctlInetAddress(JNIEnv* env, jobject, jobject javaFd, jint cmd, jstring javaInterfaceName) {
1682a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    struct ifreq req;
1683a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    if (!fillIfreq(env, javaInterfaceName, req)) {
1684a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes        return NULL;
1685a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    }
1686a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
1687a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    int rc = throwIfMinusOne(env, "ioctl", TEMP_FAILURE_RETRY(ioctl(fd, cmd, &req)));
1688a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    if (rc == -1) {
1689a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes        return NULL;
1690a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    }
1691482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes    return sockaddrToInetAddress(env, reinterpret_cast<sockaddr_storage&>(req.ifr_addr), NULL);
1692a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes}
1693a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes
16940965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_ioctlInt(JNIEnv* env, jobject, jobject javaFd, jint cmd, jobject javaArg) {
16958b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    // This is complicated because ioctls may return their result by updating their argument
16968b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    // or via their return value, so we need to support both.
1697461d0d860814c68154d8dd06d24f94118f33d28aElliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
1698e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer    jint arg = env->GetIntField(javaArg, int32RefValueFid);
16998b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    int rc = throwIfMinusOne(env, "ioctl", TEMP_FAILURE_RETRY(ioctl(fd, cmd, &arg)));
17008b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    if (!env->ExceptionCheck()) {
1701e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer        env->SetIntField(javaArg, int32RefValueFid, arg);
17028b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    }
17038b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    return rc;
1704461d0d860814c68154d8dd06d24f94118f33d28aElliott Hughes}
1705461d0d860814c68154d8dd06d24f94118f33d28aElliott Hughes
17060965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_ioctlMTU(JNIEnv* env, jobject, jobject javaFd, jstring javaInterfaceName) {
170745348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong     struct ifreq req;
170845348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong     if (!fillIfreq(env, javaInterfaceName, req)) {
170945348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong        return 0;
171045348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong     }
171145348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong     int fd = jniGetFDFromFileDescriptor(env, javaFd);
171245348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong     throwIfMinusOne(env, "ioctl", TEMP_FAILURE_RETRY(ioctl(fd, SIOCGIFMTU, &req)));
171345348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong     return req.ifr_mtu;
171445348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong}
171545348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong
17160965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jboolean Linux_isatty(JNIEnv* env, jobject, jobject javaFd) {
17179a3f363523000704205df288f8b6f2f48c0d8563Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
1718bb5816aa1626eb2f6263bd21479600b114c8a1bdJohan Redestig    return TEMP_FAILURE_RETRY(isatty(fd)) == 1;
17199a3f363523000704205df288f8b6f2f48c0d8563Elliott Hughes}
17209a3f363523000704205df288f8b6f2f48c0d8563Elliott Hughes
17210965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_kill(JNIEnv* env, jobject, jint pid, jint sig) {
1722a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes    throwIfMinusOne(env, "kill", TEMP_FAILURE_RETRY(kill(pid, sig)));
1723a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes}
1724a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes
17250965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_lchown(JNIEnv* env, jobject, jstring javaPath, jint uid, jint gid) {
172644f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes    ScopedUtfChars path(env, javaPath);
172744f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes    if (path.c_str() == NULL) {
172844f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes        return;
172944f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes    }
173044f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes    throwIfMinusOne(env, "lchown", TEMP_FAILURE_RETRY(lchown(path.c_str(), uid, gid)));
173144f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes}
173244f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes
17330965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_link(JNIEnv* env, jobject, jstring javaOldPath, jstring javaNewPath) {
173404428d61d7000e17ab21d08a1d672c34eb68f6e2Elliott Hughes    ScopedUtfChars oldPath(env, javaOldPath);
173504428d61d7000e17ab21d08a1d672c34eb68f6e2Elliott Hughes    if (oldPath.c_str() == NULL) {
173604428d61d7000e17ab21d08a1d672c34eb68f6e2Elliott Hughes        return;
173704428d61d7000e17ab21d08a1d672c34eb68f6e2Elliott Hughes    }
173804428d61d7000e17ab21d08a1d672c34eb68f6e2Elliott Hughes    ScopedUtfChars newPath(env, javaNewPath);
173904428d61d7000e17ab21d08a1d672c34eb68f6e2Elliott Hughes    if (newPath.c_str() == NULL) {
174004428d61d7000e17ab21d08a1d672c34eb68f6e2Elliott Hughes        return;
174104428d61d7000e17ab21d08a1d672c34eb68f6e2Elliott Hughes    }
174204428d61d7000e17ab21d08a1d672c34eb68f6e2Elliott Hughes    throwIfMinusOne(env, "link", TEMP_FAILURE_RETRY(link(oldPath.c_str(), newPath.c_str())));
174304428d61d7000e17ab21d08a1d672c34eb68f6e2Elliott Hughes}
174404428d61d7000e17ab21d08a1d672c34eb68f6e2Elliott Hughes
17450965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_listen(JNIEnv* env, jobject, jobject javaFd, jint backlog) {
1746e1502d64e937001636fca3d62b2552ef2a34d05fElliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
1747e1502d64e937001636fca3d62b2552ef2a34d05fElliott Hughes    throwIfMinusOne(env, "listen", TEMP_FAILURE_RETRY(listen(fd, backlog)));
1748e1502d64e937001636fca3d62b2552ef2a34d05fElliott Hughes}
1749e1502d64e937001636fca3d62b2552ef2a34d05fElliott Hughes
17500965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobjectArray Linux_listxattr(JNIEnv* env, jobject, jstring javaPath) {
175155dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong    ScopedUtfChars path(env, javaPath);
175255dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong    if (path.c_str() == NULL) {
175355dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong        return NULL;
175455dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong    }
175555dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong
175655dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong    while (true) {
175755dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong        // Get the current size of the named extended attribute.
175855dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong        ssize_t valueLength;
175955dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong        if ((valueLength = listxattr(path.c_str(), NULL, 0)) < 0) {
176055dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong            throwErrnoException(env, "listxattr");
176155dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong            return NULL;
176255dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong        }
176355dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong
176455dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong        // Create the actual byte array.
176555dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong        std::string buf(valueLength, '\0');
176655dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong        if ((valueLength = listxattr(path.c_str(), &buf[0], valueLength)) < 0) {
176755dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong            if (errno == ERANGE) {
176855dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong                // The attribute value has changed since last listxattr call and buf no longer fits,
176955dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong                // try again.
177055dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong                continue;
177155dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong            }
177255dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong            throwErrnoException(env, "listxattr");
177355dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong            return NULL;
177455dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong        }
177555dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong
177655dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong        // Split the output by '\0'.
177755dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong        buf.resize(valueLength > 0 ? valueLength - 1 : 0); // Remove the trailing NULL character.
177855dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong        std::string delim("\0", 1);
177955dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong        auto xattrs = android::base::Split(buf, delim);
178055dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong
178155dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong        return toStringArray(env, xattrs);
178255dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong    }
178355dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong}
178455dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong
17850965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jlong Linux_lseek(JNIEnv* env, jobject, jobject javaFd, jlong offset, jint whence) {
1786dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
17877e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes    return throwIfMinusOne(env, "lseek", TEMP_FAILURE_RETRY(lseek64(fd, offset, whence)));
1788dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes}
1789dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes
17900965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_lstat(JNIEnv* env, jobject, jstring javaPath) {
179147cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes    return doStat(env, javaPath, true);
179247cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes}
179347cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes
17940965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_mincore(JNIEnv* env, jobject, jlong address, jlong byteCount, jbyteArray javaVector) {
17950f746ff511162add42eeabaf14ba70ace874c6f4Elliott Hughes    ScopedByteArrayRW vector(env, javaVector);
17960f746ff511162add42eeabaf14ba70ace874c6f4Elliott Hughes    if (vector.get() == NULL) {
17970f746ff511162add42eeabaf14ba70ace874c6f4Elliott Hughes        return;
17980f746ff511162add42eeabaf14ba70ace874c6f4Elliott Hughes    }
17990f746ff511162add42eeabaf14ba70ace874c6f4Elliott Hughes    void* ptr = reinterpret_cast<void*>(static_cast<uintptr_t>(address));
18000f746ff511162add42eeabaf14ba70ace874c6f4Elliott Hughes    unsigned char* vec = reinterpret_cast<unsigned char*>(vector.get());
18010f746ff511162add42eeabaf14ba70ace874c6f4Elliott Hughes    throwIfMinusOne(env, "mincore", TEMP_FAILURE_RETRY(mincore(ptr, byteCount, vec)));
18020f746ff511162add42eeabaf14ba70ace874c6f4Elliott Hughes}
18030f746ff511162add42eeabaf14ba70ace874c6f4Elliott Hughes
18040965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_mkdir(JNIEnv* env, jobject, jstring javaPath, jint mode) {
1805c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes    ScopedUtfChars path(env, javaPath);
1806c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes    if (path.c_str() == NULL) {
1807c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes        return;
1808c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes    }
1809c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes    throwIfMinusOne(env, "mkdir", TEMP_FAILURE_RETRY(mkdir(path.c_str(), mode)));
1810c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes}
1811c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes
18120965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_mkfifo(JNIEnv* env, jobject, jstring javaPath, jint mode) {
1813f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    ScopedUtfChars path(env, javaPath);
1814f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    if (path.c_str() == NULL) {
1815f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller        return;
1816f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    }
1817f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    throwIfMinusOne(env, "mkfifo", TEMP_FAILURE_RETRY(mkfifo(path.c_str(), mode)));
1818f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller}
1819f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller
18200965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_mlock(JNIEnv* env, jobject, jlong address, jlong byteCount) {
18217e13c0f05ac9e7c55682d10e953dd4cbd5e6107cElliott Hughes    void* ptr = reinterpret_cast<void*>(static_cast<uintptr_t>(address));
18227e13c0f05ac9e7c55682d10e953dd4cbd5e6107cElliott Hughes    throwIfMinusOne(env, "mlock", TEMP_FAILURE_RETRY(mlock(ptr, byteCount)));
18237e13c0f05ac9e7c55682d10e953dd4cbd5e6107cElliott Hughes}
18247e13c0f05ac9e7c55682d10e953dd4cbd5e6107cElliott Hughes
18250965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jlong Linux_mmap(JNIEnv* env, jobject, jlong address, jlong byteCount, jint prot, jint flags, jobject javaFd, jlong offset) {
18267e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
18277e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes    void* suggestedPtr = reinterpret_cast<void*>(static_cast<uintptr_t>(address));
182813a70e6c04157064fc8a61ecfcb1d863f29c239dYi Kong    void* ptr = mmap64(suggestedPtr, byteCount, prot, flags, fd, offset);
18297e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes    if (ptr == MAP_FAILED) {
18307e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes        throwErrnoException(env, "mmap");
18317e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes    }
18327e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes    return static_cast<jlong>(reinterpret_cast<uintptr_t>(ptr));
18337e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes}
18347e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes
18350965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_msync(JNIEnv* env, jobject, jlong address, jlong byteCount, jint flags) {
18367e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes    void* ptr = reinterpret_cast<void*>(static_cast<uintptr_t>(address));
18377e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes    throwIfMinusOne(env, "msync", TEMP_FAILURE_RETRY(msync(ptr, byteCount, flags)));
18387e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes}
18397e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes
18400965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_munlock(JNIEnv* env, jobject, jlong address, jlong byteCount) {
18417e13c0f05ac9e7c55682d10e953dd4cbd5e6107cElliott Hughes    void* ptr = reinterpret_cast<void*>(static_cast<uintptr_t>(address));
18427e13c0f05ac9e7c55682d10e953dd4cbd5e6107cElliott Hughes    throwIfMinusOne(env, "munlock", TEMP_FAILURE_RETRY(munlock(ptr, byteCount)));
18437e13c0f05ac9e7c55682d10e953dd4cbd5e6107cElliott Hughes}
18447e13c0f05ac9e7c55682d10e953dd4cbd5e6107cElliott Hughes
18450965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_munmap(JNIEnv* env, jobject, jlong address, jlong byteCount) {
18467e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes    void* ptr = reinterpret_cast<void*>(static_cast<uintptr_t>(address));
18477e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes    throwIfMinusOne(env, "munmap", TEMP_FAILURE_RETRY(munmap(ptr, byteCount)));
18487e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes}
18497e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes
18500965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_open(JNIEnv* env, jobject, jstring javaPath, jint flags, jint mode) {
18510ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes    ScopedUtfChars path(env, javaPath);
18520ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes    if (path.c_str() == NULL) {
18530ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes        return NULL;
18540ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes    }
18550ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes    int fd = throwIfMinusOne(env, "open", TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode)));
18560ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes    return fd != -1 ? jniCreateFileDescriptor(env, fd) : NULL;
18570ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes}
18580ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes
18590965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobjectArray Linux_pipe2(JNIEnv* env, jobject, jint flags __unused) {
186041f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes    int fds[2];
186157a65ad7f0be5b9d0364d36208752f66e9f13596Przemyslaw Szczepaniak    int pipe2_result = throwIfMinusOne(env, "pipe2", TEMP_FAILURE_RETRY(pipe2(&fds[0], flags)));
186257a65ad7f0be5b9d0364d36208752f66e9f13596Przemyslaw Szczepaniak    if (pipe2_result == -1) {
186357a65ad7f0be5b9d0364d36208752f66e9f13596Przemyslaw Szczepaniak        return NULL;
186457a65ad7f0be5b9d0364d36208752f66e9f13596Przemyslaw Szczepaniak    }
186541f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes    jobjectArray result = env->NewObjectArray(2, JniConstants::fileDescriptorClass, NULL);
186641f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes    if (result == NULL) {
186741f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes        return NULL;
186841f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes    }
186941f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes    for (int i = 0; i < 2; ++i) {
187041f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes        ScopedLocalRef<jobject> fd(env, jniCreateFileDescriptor(env, fds[i]));
187141f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes        if (fd.get() == NULL) {
187241f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes            return NULL;
187341f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes        }
187441f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes        env->SetObjectArrayElement(result, i, fd.get());
187541f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes        if (env->ExceptionCheck()) {
187641f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes            return NULL;
187741f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes        }
187841f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes    }
187941f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes    return result;
188041f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes}
188141f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes
18820965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_poll(JNIEnv* env, jobject, jobjectArray javaStructs, jint timeoutMs) {
188370c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    static jfieldID fdFid = env->GetFieldID(JniConstants::structPollfdClass, "fd", "Ljava/io/FileDescriptor;");
188470c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    static jfieldID eventsFid = env->GetFieldID(JniConstants::structPollfdClass, "events", "S");
188570c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    static jfieldID reventsFid = env->GetFieldID(JniConstants::structPollfdClass, "revents", "S");
188670c820401677ca251ad09ac64cc23c760764e75dElliott Hughes
18875d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughes    // Turn the Java android.system.StructPollfd[] into a C++ struct pollfd[].
188870c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    size_t arrayLength = env->GetArrayLength(javaStructs);
1889b3aacde3d8af759ee4a7b395c636ea360547d92dIan Rogers    std::unique_ptr<struct pollfd[]> fds(new struct pollfd[arrayLength]);
189070c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    memset(fds.get(), 0, sizeof(struct pollfd) * arrayLength);
189170c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    size_t count = 0; // Some trailing array elements may be irrelevant. (See below.)
189270c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    for (size_t i = 0; i < arrayLength; ++i) {
189370c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        ScopedLocalRef<jobject> javaStruct(env, env->GetObjectArrayElement(javaStructs, i));
189470c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        if (javaStruct.get() == NULL) {
189570c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            break; // We allow trailing nulls in the array for caller convenience.
189670c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        }
189770c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        ScopedLocalRef<jobject> javaFd(env, env->GetObjectField(javaStruct.get(), fdFid));
189870c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        if (javaFd.get() == NULL) {
189970c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            break; // We also allow callers to just clear the fd field (this is what Selector does).
190070c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        }
190170c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        fds[count].fd = jniGetFDFromFileDescriptor(env, javaFd.get());
190270c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        fds[count].events = env->GetShortField(javaStruct.get(), eventsFid);
190370c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        ++count;
190470c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    }
190570c820401677ca251ad09ac64cc23c760764e75dElliott Hughes
1906f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    std::vector<AsynchronousCloseMonitor*> monitors;
1907796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes    for (size_t i = 0; i < count; ++i) {
1908f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller        monitors.push_back(new AsynchronousCloseMonitor(fds[i].fd));
1909796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes    }
1910fa542091e45db699a937c5ac0191194405107827Elliott Hughes
1911fa542091e45db699a937c5ac0191194405107827Elliott Hughes    int rc;
1912fa542091e45db699a937c5ac0191194405107827Elliott Hughes    while (true) {
1913fa542091e45db699a937c5ac0191194405107827Elliott Hughes        timespec before;
1914fa542091e45db699a937c5ac0191194405107827Elliott Hughes        clock_gettime(CLOCK_MONOTONIC, &before);
1915fa542091e45db699a937c5ac0191194405107827Elliott Hughes
1916fa542091e45db699a937c5ac0191194405107827Elliott Hughes        rc = poll(fds.get(), count, timeoutMs);
1917fa542091e45db699a937c5ac0191194405107827Elliott Hughes        if (rc >= 0 || errno != EINTR) {
1918fa542091e45db699a937c5ac0191194405107827Elliott Hughes            break;
1919fa542091e45db699a937c5ac0191194405107827Elliott Hughes        }
1920fa542091e45db699a937c5ac0191194405107827Elliott Hughes
1921fa542091e45db699a937c5ac0191194405107827Elliott Hughes        // We got EINTR. Work out how much of the original timeout is still left.
1922fa542091e45db699a937c5ac0191194405107827Elliott Hughes        if (timeoutMs > 0) {
1923fa542091e45db699a937c5ac0191194405107827Elliott Hughes            timespec now;
1924fa542091e45db699a937c5ac0191194405107827Elliott Hughes            clock_gettime(CLOCK_MONOTONIC, &now);
1925fa542091e45db699a937c5ac0191194405107827Elliott Hughes
1926fa542091e45db699a937c5ac0191194405107827Elliott Hughes            timespec diff;
1927fa542091e45db699a937c5ac0191194405107827Elliott Hughes            diff.tv_sec = now.tv_sec - before.tv_sec;
1928fa542091e45db699a937c5ac0191194405107827Elliott Hughes            diff.tv_nsec = now.tv_nsec - before.tv_nsec;
1929fa542091e45db699a937c5ac0191194405107827Elliott Hughes            if (diff.tv_nsec < 0) {
1930fa542091e45db699a937c5ac0191194405107827Elliott Hughes                --diff.tv_sec;
1931fa542091e45db699a937c5ac0191194405107827Elliott Hughes                diff.tv_nsec += 1000000000;
1932fa542091e45db699a937c5ac0191194405107827Elliott Hughes            }
1933fa542091e45db699a937c5ac0191194405107827Elliott Hughes
1934fa542091e45db699a937c5ac0191194405107827Elliott Hughes            jint diffMs = diff.tv_sec * 1000 + diff.tv_nsec / 1000000;
1935fa542091e45db699a937c5ac0191194405107827Elliott Hughes            if (diffMs >= timeoutMs) {
1936fa542091e45db699a937c5ac0191194405107827Elliott Hughes                rc = 0; // We have less than 1ms left anyway, so just time out.
1937fa542091e45db699a937c5ac0191194405107827Elliott Hughes                break;
1938fa542091e45db699a937c5ac0191194405107827Elliott Hughes            }
1939fa542091e45db699a937c5ac0191194405107827Elliott Hughes
1940fa542091e45db699a937c5ac0191194405107827Elliott Hughes            timeoutMs -= diffMs;
1941fa542091e45db699a937c5ac0191194405107827Elliott Hughes        }
1942fa542091e45db699a937c5ac0191194405107827Elliott Hughes    }
1943fa542091e45db699a937c5ac0191194405107827Elliott Hughes
1944796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes    for (size_t i = 0; i < monitors.size(); ++i) {
1945796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes        delete monitors[i];
1946796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes    }
194770c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    if (rc == -1) {
194870c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        throwErrnoException(env, "poll");
194970c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        return -1;
195070c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    }
195170c820401677ca251ad09ac64cc23c760764e75dElliott Hughes
19525d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughes    // Update the revents fields in the Java android.system.StructPollfd[].
195398b23d4d9894d21be1eacf498f48aeb707ca1e41Elliott Hughes    for (size_t i = 0; i < count; ++i) {
195470c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        ScopedLocalRef<jobject> javaStruct(env, env->GetObjectArrayElement(javaStructs, i));
195598b23d4d9894d21be1eacf498f48aeb707ca1e41Elliott Hughes        if (javaStruct.get() == NULL) {
195698b23d4d9894d21be1eacf498f48aeb707ca1e41Elliott Hughes            return -1;
195798b23d4d9894d21be1eacf498f48aeb707ca1e41Elliott Hughes        }
195870c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        env->SetShortField(javaStruct.get(), reventsFid, fds[i].revents);
195970c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    }
196070c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    return rc;
196170c820401677ca251ad09ac64cc23c760764e75dElliott Hughes}
196270c820401677ca251ad09ac64cc23c760764e75dElliott Hughes
19630965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_posix_fallocate(JNIEnv* env, jobject, jobject javaFd __unused,
19643deabd220cf7b1ca0824987e90b8ecc07087f05aIan Rogers                                  jlong offset __unused, jlong length __unused) {
196511f07d30d2e344b48f132ec6ed105d85423052c2Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
1966fa542091e45db699a937c5ac0191194405107827Elliott Hughes    while ((errno = posix_fallocate64(fd, offset, length)) == EINTR) {
1967fa542091e45db699a937c5ac0191194405107827Elliott Hughes    }
196811f07d30d2e344b48f132ec6ed105d85423052c2Elliott Hughes    if (errno != 0) {
196911f07d30d2e344b48f132ec6ed105d85423052c2Elliott Hughes        throwErrnoException(env, "posix_fallocate");
197011f07d30d2e344b48f132ec6ed105d85423052c2Elliott Hughes    }
197111f07d30d2e344b48f132ec6ed105d85423052c2Elliott Hughes}
197211f07d30d2e344b48f132ec6ed105d85423052c2Elliott Hughes
19730965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_prctl(JNIEnv* env, jobject, jint option __unused, jlong arg2 __unused,
19743deabd220cf7b1ca0824987e90b8ecc07087f05aIan Rogers                        jlong arg3 __unused, jlong arg4 __unused, jlong arg5 __unused) {
1975fa542091e45db699a937c5ac0191194405107827Elliott Hughes    int result = TEMP_FAILURE_RETRY(prctl(static_cast<int>(option),
1976fa542091e45db699a937c5ac0191194405107827Elliott Hughes                                          static_cast<unsigned long>(arg2),
1977fa542091e45db699a937c5ac0191194405107827Elliott Hughes                                          static_cast<unsigned long>(arg3),
1978fa542091e45db699a937c5ac0191194405107827Elliott Hughes                                          static_cast<unsigned long>(arg4),
1979fa542091e45db699a937c5ac0191194405107827Elliott Hughes                                          static_cast<unsigned long>(arg5)));
19805215e4c0db7530519981f1e505e6db82401802f2Nick Kralevich    return throwIfMinusOne(env, "prctl", result);
19815215e4c0db7530519981f1e505e6db82401802f2Nick Kralevich}
19825215e4c0db7530519981f1e505e6db82401802f2Nick Kralevich
19830965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_preadBytes(JNIEnv* env, jobject, jobject javaFd, jobject javaBytes, jint byteOffset, jint byteCount, jlong offset) {
1984e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes    ScopedBytesRW bytes(env, javaBytes);
1985e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes    if (bytes.get() == NULL) {
1986e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes        return -1;
1987e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes    }
1988f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    return IO_FAILURE_RETRY(env, ssize_t, pread64, javaFd, bytes.get() + byteOffset, byteCount, offset);
1989e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes}
1990e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes
19910965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_pwriteBytes(JNIEnv* env, jobject, jobject javaFd, jbyteArray javaBytes, jint byteOffset, jint byteCount, jlong offset) {
1992e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes    ScopedBytesRO bytes(env, javaBytes);
1993e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes    if (bytes.get() == NULL) {
1994e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes        return -1;
1995e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes    }
1996f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    return IO_FAILURE_RETRY(env, ssize_t, pwrite64, javaFd, bytes.get() + byteOffset, byteCount, offset);
1997e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes}
1998e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes
19990965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_readBytes(JNIEnv* env, jobject, jobject javaFd, jobject javaBytes, jint byteOffset, jint byteCount) {
20000568a63ba1086a78ffb4cff68dd2eac4f9908e13Elliott Hughes    ScopedBytesRW bytes(env, javaBytes);
200126c7025a7a919044771fb89031161bd26fe03032Elliott Hughes    if (bytes.get() == NULL) {
200226c7025a7a919044771fb89031161bd26fe03032Elliott Hughes        return -1;
200326c7025a7a919044771fb89031161bd26fe03032Elliott Hughes    }
2004f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    return IO_FAILURE_RETRY(env, ssize_t, read, javaFd, bytes.get() + byteOffset, byteCount);
200526c7025a7a919044771fb89031161bd26fe03032Elliott Hughes}
200626c7025a7a919044771fb89031161bd26fe03032Elliott Hughes
20070965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jstring Linux_readlink(JNIEnv* env, jobject, jstring javaPath) {
20080b6b3e10459fc3a3f4dd280dab8d4a145f7bf2f0Elliott Hughes    ScopedUtfChars path(env, javaPath);
20090b6b3e10459fc3a3f4dd280dab8d4a145f7bf2f0Elliott Hughes    if (path.c_str() == NULL) {
20100b6b3e10459fc3a3f4dd280dab8d4a145f7bf2f0Elliott Hughes        return NULL;
20110b6b3e10459fc3a3f4dd280dab8d4a145f7bf2f0Elliott Hughes    }
20120b6b3e10459fc3a3f4dd280dab8d4a145f7bf2f0Elliott Hughes
20130b6b3e10459fc3a3f4dd280dab8d4a145f7bf2f0Elliott Hughes    std::string result;
20142cb2851f4a528e3e6e3e59cf3e854c2abf9f1811Elliott Hughes    if (!android::base::Readlink(path.c_str(), &result)) {
20150b6b3e10459fc3a3f4dd280dab8d4a145f7bf2f0Elliott Hughes        throwErrnoException(env, "readlink");
20160b6b3e10459fc3a3f4dd280dab8d4a145f7bf2f0Elliott Hughes        return NULL;
20170b6b3e10459fc3a3f4dd280dab8d4a145f7bf2f0Elliott Hughes    }
20180b6b3e10459fc3a3f4dd280dab8d4a145f7bf2f0Elliott Hughes    return env->NewStringUTF(result.c_str());
20190b6b3e10459fc3a3f4dd280dab8d4a145f7bf2f0Elliott Hughes}
20200b6b3e10459fc3a3f4dd280dab8d4a145f7bf2f0Elliott Hughes
20210965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jstring Linux_realpath(JNIEnv* env, jobject, jstring javaPath) {
20225d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath    ScopedUtfChars path(env, javaPath);
20235d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath    if (path.c_str() == NULL) {
20245d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath        return NULL;
20255d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath    }
20265d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath
20275d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath    std::unique_ptr<char, c_deleter> real_path(realpath(path.c_str(), nullptr));
20285d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath    if (real_path.get() == nullptr) {
20295d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath        throwErrnoException(env, "realpath");
20305d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath        return NULL;
20315d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath    }
20325d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath
20335d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath    return env->NewStringUTF(real_path.get());
20345d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath}
20355d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath
20360965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_readv(JNIEnv* env, jobject, jobject javaFd, jobjectArray buffers, jintArray offsets, jintArray byteCounts) {
20378dc754726bb5303c25e2c48decdf76d9323ee231Elliott Hughes    IoVec<ScopedBytesRW> ioVec(env, env->GetArrayLength(buffers));
2038bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    if (!ioVec.init(buffers, offsets, byteCounts)) {
2039bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        return -1;
2040bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    }
2041f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    return IO_FAILURE_RETRY(env, ssize_t, readv, javaFd, ioVec.get(), ioVec.size());
2042bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes}
2043bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes
20440965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_recvfromBytes(JNIEnv* env, jobject, jobject javaFd, jobject javaBytes, jint byteOffset, jint byteCount, jint flags, jobject javaInetSocketAddress) {
204523ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes    ScopedBytesRW bytes(env, javaBytes);
204623ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes    if (bytes.get() == NULL) {
204723ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes        return -1;
204823ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes    }
204923ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes    sockaddr_storage ss;
205023ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes    socklen_t sl = sizeof(ss);
205123ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes    memset(&ss, 0, sizeof(ss));
205223ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes    sockaddr* from = (javaInetSocketAddress != NULL) ? reinterpret_cast<sockaddr*>(&ss) : NULL;
205323ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes    socklen_t* fromLength = (javaInetSocketAddress != NULL) ? &sl : 0;
20541124a814d698ed6fd68ac501f5dddfa103d656fdElliott Hughes    jint recvCount = NET_FAILURE_RETRY(env, ssize_t, recvfrom, javaFd, bytes.get() + byteOffset, byteCount, flags, from, fromLength);
20556dd21e692ae87b75e49b23ffbecc6964604f466aYi Kong    if (recvCount >= 0) {
20566dd21e692ae87b75e49b23ffbecc6964604f466aYi Kong        // The socket may have performed orderly shutdown and recvCount would return 0 (see man 2
20576dd21e692ae87b75e49b23ffbecc6964604f466aYi Kong        // recvfrom), in which case ss.ss_family == AF_UNIX and fillInetSocketAddress would fail.
20586dd21e692ae87b75e49b23ffbecc6964604f466aYi Kong        // Don't fill in the address if recvfrom didn't succeed. http://b/33483694
20596dd21e692ae87b75e49b23ffbecc6964604f466aYi Kong        if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6) {
20606dd21e692ae87b75e49b23ffbecc6964604f466aYi Kong            fillInetSocketAddress(env, javaInetSocketAddress, ss);
20616dd21e692ae87b75e49b23ffbecc6964604f466aYi Kong        }
20620ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    }
206323ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes    return recvCount;
206423ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes}
206523ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes
20660965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_remove(JNIEnv* env, jobject, jstring javaPath) {
2067c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes    ScopedUtfChars path(env, javaPath);
2068c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes    if (path.c_str() == NULL) {
2069c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes        return;
2070c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes    }
2071c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes    throwIfMinusOne(env, "remove", TEMP_FAILURE_RETRY(remove(path.c_str())));
2072c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes}
2073c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes
20740965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_removexattr(JNIEnv* env, jobject, jstring javaPath, jstring javaName) {
207590246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    ScopedUtfChars path(env, javaPath);
207690246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    if (path.c_str() == NULL) {
207790246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey        return;
207890246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    }
207990246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    ScopedUtfChars name(env, javaName);
208090246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    if (name.c_str() == NULL) {
208190246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey        return;
208290246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    }
208390246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey
208490246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    int res = removexattr(path.c_str(), name.c_str());
208590246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    if (res < 0) {
208690246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey        throwErrnoException(env, "removexattr");
208790246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    }
208890246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey}
208990246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey
20900965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_rename(JNIEnv* env, jobject, jstring javaOldPath, jstring javaNewPath) {
2091a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes    ScopedUtfChars oldPath(env, javaOldPath);
2092a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes    if (oldPath.c_str() == NULL) {
2093a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes        return;
2094a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes    }
2095a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes    ScopedUtfChars newPath(env, javaNewPath);
2096a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes    if (newPath.c_str() == NULL) {
2097a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes        return;
2098a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes    }
2099a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes    throwIfMinusOne(env, "rename", TEMP_FAILURE_RETRY(rename(oldPath.c_str(), newPath.c_str())));
2100a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes}
2101a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes
21020965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jlong Linux_sendfile(JNIEnv* env, jobject, jobject javaOutFd, jobject javaInFd, jobject javaOffset, jlong byteCount) {
21038b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    int outFd = jniGetFDFromFileDescriptor(env, javaOutFd);
21048b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    int inFd = jniGetFDFromFileDescriptor(env, javaInFd);
21058b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    off_t offset = 0;
21068b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    off_t* offsetPtr = NULL;
21078b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    if (javaOffset != NULL) {
21088b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes        // TODO: fix bionic so we can have a 64-bit off_t!
2109e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer        offset = env->GetLongField(javaOffset, int64RefValueFid);
21108b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes        offsetPtr = &offset;
21118b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    }
21128b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    jlong result = throwIfMinusOne(env, "sendfile", TEMP_FAILURE_RETRY(sendfile(outFd, inFd, offsetPtr, byteCount)));
211357a65ad7f0be5b9d0364d36208752f66e9f13596Przemyslaw Szczepaniak    if (result == -1) {
211457a65ad7f0be5b9d0364d36208752f66e9f13596Przemyslaw Szczepaniak        return -1;
211557a65ad7f0be5b9d0364d36208752f66e9f13596Przemyslaw Szczepaniak    }
21168b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    if (javaOffset != NULL) {
2117e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer        env->SetLongField(javaOffset, int64RefValueFid, offset);
21188b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    }
21198b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    return result;
21208b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes}
21218b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes
21220965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_sendtoBytes(JNIEnv* env, jobject, jobject javaFd, jobject javaBytes, jint byteOffset, jint byteCount, jint flags, jobject javaInetAddress, jint port) {
212390d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes    ScopedBytesRO bytes(env, javaBytes);
212490d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes    if (bytes.get() == NULL) {
212590d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes        return -1;
212690d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes    }
2127b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti
2128b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti    return NET_IPV4_FALLBACK(env, ssize_t, sendto, javaFd, javaInetAddress, port,
2129b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti                             NULL_ADDR_OK, bytes.get() + byteOffset, byteCount, flags);
213090d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes}
213190d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes
21320965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_sendtoBytesSocketAddress(JNIEnv* env, jobject, jobject javaFd, jobject javaBytes, jint byteOffset, jint byteCount, jint flags, jobject javaSocketAddress) {
2133f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti    if (env->IsInstanceOf(javaSocketAddress, JniConstants::inetSocketAddressClass)) {
2134f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti        // Use the InetAddress version so we get the benefit of NET_IPV4_FALLBACK.
2135f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti        jobject javaInetAddress;
2136f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti        jint port;
2137f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti        javaInetSocketAddressToInetAddressAndPort(env, javaSocketAddress, javaInetAddress, port);
21380965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe        return Linux_sendtoBytes(env, NULL, javaFd, javaBytes, byteOffset, byteCount, flags,
2139f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti                                 javaInetAddress, port);
2140f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti    }
2141f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti
2142a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti    ScopedBytesRO bytes(env, javaBytes);
2143a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti    if (bytes.get() == NULL) {
2144a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti        return -1;
2145a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti    }
2146a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti
2147a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti    sockaddr_storage ss;
2148a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti    socklen_t sa_len;
2149a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti    if (!javaSocketAddressToSockaddr(env, javaSocketAddress, ss, sa_len)) {
2150a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti        return -1;
2151a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti    }
2152a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti
2153a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti    const sockaddr* sa = reinterpret_cast<const sockaddr*>(&ss);
2154a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti    // We don't need the return value because we'll already have thrown.
2155a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti    return NET_FAILURE_RETRY(env, ssize_t, sendto, javaFd, bytes.get() + byteOffset, byteCount, flags, sa, sa_len);
2156a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti}
2157a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti
21580965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setegid(JNIEnv* env, jobject, jint egid) {
2159396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes    throwIfMinusOne(env, "setegid", TEMP_FAILURE_RETRY(setegid(egid)));
2160396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes}
2161396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes
21620965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setenv(JNIEnv* env, jobject, jstring javaName, jstring javaValue, jboolean overwrite) {
2163895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes    ScopedUtfChars name(env, javaName);
2164895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes    if (name.c_str() == NULL) {
2165895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes        return;
2166895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes    }
2167895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes    ScopedUtfChars value(env, javaValue);
2168895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes    if (value.c_str() == NULL) {
2169895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes        return;
2170895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes    }
2171895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes    throwIfMinusOne(env, "setenv", setenv(name.c_str(), value.c_str(), overwrite));
2172895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes}
2173895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes
21740965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_seteuid(JNIEnv* env, jobject, jint euid) {
2175396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes    throwIfMinusOne(env, "seteuid", TEMP_FAILURE_RETRY(seteuid(euid)));
2176396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes}
2177396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes
21780965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setgid(JNIEnv* env, jobject, jint gid) {
2179396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes    throwIfMinusOne(env, "setgid", TEMP_FAILURE_RETRY(setgid(gid)));
2180396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes}
2181396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes
218244177e6982a62506127a857070a2452956c3f0f1Enrico Granatastatic void Linux_setgroups(JNIEnv* env, jobject, jintArray gids) {
218344177e6982a62506127a857070a2452956c3f0f1Enrico Granata    size_t ngrps = gids == NULL ? 0 : env->GetArrayLength(gids);
218444177e6982a62506127a857070a2452956c3f0f1Enrico Granata    std::vector<gid_t> groups(ngrps, 0);
218544177e6982a62506127a857070a2452956c3f0f1Enrico Granata    env->GetIntArrayRegion(gids, 0, ngrps, reinterpret_cast<int*>(&groups[0]));
218644177e6982a62506127a857070a2452956c3f0f1Enrico Granata    throwIfMinusOne(env, "setgroups", setgroups(ngrps, &groups[0]));
218744177e6982a62506127a857070a2452956c3f0f1Enrico Granata}
218844177e6982a62506127a857070a2452956c3f0f1Enrico Granata
21890965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setpgid(JNIEnv* env, jobject, jint pid, int pgid) {
21908f0f2ac7fcd8f366a78cc51181d065ab93385e46Elliott Hughes    throwIfMinusOne(env, "setpgid", TEMP_FAILURE_RETRY(setpgid(pid, pgid)));
21918f0f2ac7fcd8f366a78cc51181d065ab93385e46Elliott Hughes}
21928f0f2ac7fcd8f366a78cc51181d065ab93385e46Elliott Hughes
21930965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setregid(JNIEnv* env, jobject, jint rgid, int egid) {
21948f0f2ac7fcd8f366a78cc51181d065ab93385e46Elliott Hughes    throwIfMinusOne(env, "setregid", TEMP_FAILURE_RETRY(setregid(rgid, egid)));
21958f0f2ac7fcd8f366a78cc51181d065ab93385e46Elliott Hughes}
21968f0f2ac7fcd8f366a78cc51181d065ab93385e46Elliott Hughes
21970965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setreuid(JNIEnv* env, jobject, jint ruid, int euid) {
21988f0f2ac7fcd8f366a78cc51181d065ab93385e46Elliott Hughes    throwIfMinusOne(env, "setreuid", TEMP_FAILURE_RETRY(setreuid(ruid, euid)));
21998f0f2ac7fcd8f366a78cc51181d065ab93385e46Elliott Hughes}
22008f0f2ac7fcd8f366a78cc51181d065ab93385e46Elliott Hughes
22010965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_setsid(JNIEnv* env, jobject) {
22026c9b5377550a9649ed1532d1fcdfeba116c74eadElliott Hughes    return throwIfMinusOne(env, "setsid", TEMP_FAILURE_RETRY(setsid()));
22036c9b5377550a9649ed1532d1fcdfeba116c74eadElliott Hughes}
22046c9b5377550a9649ed1532d1fcdfeba116c74eadElliott Hughes
22050965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setsockoptByte(JNIEnv* env, jobject, jobject javaFd, jint level, jint option, jint value) {
2206c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
2207c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    u_char byte = value;
2208c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    throwIfMinusOne(env, "setsockopt", TEMP_FAILURE_RETRY(setsockopt(fd, level, option, &byte, sizeof(byte))));
2209c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes}
2210c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes
22110965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setsockoptIfreq(JNIEnv* env, jobject, jobject javaFd, jint level, jint option, jstring javaInterfaceName) {
2212a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    struct ifreq req;
2213a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    if (!fillIfreq(env, javaInterfaceName, req)) {
2214b974666d79ebc392b37ec1ae83aae57ae6331c08Elliott Hughes        return;
2215b974666d79ebc392b37ec1ae83aae57ae6331c08Elliott Hughes    }
2216b974666d79ebc392b37ec1ae83aae57ae6331c08Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
2217b974666d79ebc392b37ec1ae83aae57ae6331c08Elliott Hughes    throwIfMinusOne(env, "setsockopt", TEMP_FAILURE_RETRY(setsockopt(fd, level, option, &req, sizeof(req))));
2218b974666d79ebc392b37ec1ae83aae57ae6331c08Elliott Hughes}
2219b974666d79ebc392b37ec1ae83aae57ae6331c08Elliott Hughes
22200965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setsockoptInt(JNIEnv* env, jobject, jobject javaFd, jint level, jint option, jint value) {
2221454a95f6a28855aa3c88d168b15a45bf315efc99Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
2222454a95f6a28855aa3c88d168b15a45bf315efc99Elliott Hughes    throwIfMinusOne(env, "setsockopt", TEMP_FAILURE_RETRY(setsockopt(fd, level, option, &value, sizeof(value))));
2223454a95f6a28855aa3c88d168b15a45bf315efc99Elliott Hughes}
2224454a95f6a28855aa3c88d168b15a45bf315efc99Elliott Hughes
22250965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setsockoptIpMreqn(JNIEnv* env, jobject, jobject javaFd, jint level, jint option, jint value) {
2226b974666d79ebc392b37ec1ae83aae57ae6331c08Elliott Hughes    ip_mreqn req;
2227b974666d79ebc392b37ec1ae83aae57ae6331c08Elliott Hughes    memset(&req, 0, sizeof(req));
2228b974666d79ebc392b37ec1ae83aae57ae6331c08Elliott Hughes    req.imr_ifindex = value;
2229b974666d79ebc392b37ec1ae83aae57ae6331c08Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
2230b974666d79ebc392b37ec1ae83aae57ae6331c08Elliott Hughes    throwIfMinusOne(env, "setsockopt", TEMP_FAILURE_RETRY(setsockopt(fd, level, option, &req, sizeof(req))));
2231b974666d79ebc392b37ec1ae83aae57ae6331c08Elliott Hughes}
2232b974666d79ebc392b37ec1ae83aae57ae6331c08Elliott Hughes
22330965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setsockoptGroupReq(JNIEnv* env, jobject, jobject javaFd, jint level, jint option, jobject javaGroupReq) {
22348ecbb3f6a89983adb1a085469befc70488f4f04fElliott Hughes    struct group_req req;
22358ecbb3f6a89983adb1a085469befc70488f4f04fElliott Hughes    memset(&req, 0, sizeof(req));
2236438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes
2237438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes    static jfieldID grInterfaceFid = env->GetFieldID(JniConstants::structGroupReqClass, "gr_interface", "I");
22388ecbb3f6a89983adb1a085469befc70488f4f04fElliott Hughes    req.gr_interface = env->GetIntField(javaGroupReq, grInterfaceFid);
2239438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes    // Get the IPv4 or IPv6 multicast address to join or leave.
2240438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes    static jfieldID grGroupFid = env->GetFieldID(JniConstants::structGroupReqClass, "gr_group", "Ljava/net/InetAddress;");
2241e9f12043a1e2a29c60779cdb55c58eb156963570Elliott Hughes    ScopedLocalRef<jobject> javaGroup(env, env->GetObjectField(javaGroupReq, grGroupFid));
2242482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes    socklen_t sa_len;
2243482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes    if (!inetAddressToSockaddrVerbatim(env, javaGroup.get(), 0, req.gr_group, sa_len)) {
2244438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes        return;
2245438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes    }
2246438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes
2247438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
22488ecbb3f6a89983adb1a085469befc70488f4f04fElliott Hughes    int rc = TEMP_FAILURE_RETRY(setsockopt(fd, level, option, &req, sizeof(req)));
2249438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes    if (rc == -1 && errno == EINVAL) {
2250438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes        // Maybe we're a 32-bit binary talking to a 64-bit kernel?
2251438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes        // glibc doesn't automatically handle this.
2252df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller        // http://sourceware.org/bugzilla/show_bug.cgi?id=12080
22539634b569a92841f32268907c88c408f22cb00486Elliott Hughes        struct group_req64 {
2254438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes            uint32_t gr_interface;
2255438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes            uint32_t my_padding;
2256438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes            sockaddr_storage gr_group;
2257438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes        };
22588ecbb3f6a89983adb1a085469befc70488f4f04fElliott Hughes        group_req64 req64;
22598ecbb3f6a89983adb1a085469befc70488f4f04fElliott Hughes        req64.gr_interface = req.gr_interface;
22608ecbb3f6a89983adb1a085469befc70488f4f04fElliott Hughes        memcpy(&req64.gr_group, &req.gr_group, sizeof(req.gr_group));
22618ecbb3f6a89983adb1a085469befc70488f4f04fElliott Hughes        rc = TEMP_FAILURE_RETRY(setsockopt(fd, level, option, &req64, sizeof(req64)));
2262438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes    }
2263438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes    throwIfMinusOne(env, "setsockopt", rc);
2264438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes}
2265df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller
22660965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setsockoptLinger(JNIEnv* env, jobject, jobject javaFd, jint level, jint option, jobject javaLinger) {
2267c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    static jfieldID lOnoffFid = env->GetFieldID(JniConstants::structLingerClass, "l_onoff", "I");
2268c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    static jfieldID lLingerFid = env->GetFieldID(JniConstants::structLingerClass, "l_linger", "I");
2269c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
2270c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    struct linger value;
2271c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    value.l_onoff = env->GetIntField(javaLinger, lOnoffFid);
2272c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    value.l_linger = env->GetIntField(javaLinger, lLingerFid);
2273c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    throwIfMinusOne(env, "setsockopt", TEMP_FAILURE_RETRY(setsockopt(fd, level, option, &value, sizeof(value))));
2274c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes}
2275c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes
22760965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setsockoptTimeval(JNIEnv* env, jobject, jobject javaFd, jint level, jint option, jobject javaTimeval) {
2277c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    static jfieldID tvSecFid = env->GetFieldID(JniConstants::structTimevalClass, "tv_sec", "J");
2278c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    static jfieldID tvUsecFid = env->GetFieldID(JniConstants::structTimevalClass, "tv_usec", "J");
2279c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
2280c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    struct timeval value;
228139fd5e164f93ab821841aa4d1fac09055c102b8bElliott Hughes    value.tv_sec = env->GetLongField(javaTimeval, tvSecFid);
228239fd5e164f93ab821841aa4d1fac09055c102b8bElliott Hughes    value.tv_usec = env->GetLongField(javaTimeval, tvUsecFid);
2283c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    throwIfMinusOne(env, "setsockopt", TEMP_FAILURE_RETRY(setsockopt(fd, level, option, &value, sizeof(value))));
2284c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes}
2285c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes
22860965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setuid(JNIEnv* env, jobject, jint uid) {
2287396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes    throwIfMinusOne(env, "setuid", TEMP_FAILURE_RETRY(setuid(uid)));
2288396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes}
2289396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes
22900965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setxattr(JNIEnv* env, jobject, jstring javaPath, jstring javaName,
229190246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey        jbyteArray javaValue, jint flags) {
229290246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    ScopedUtfChars path(env, javaPath);
229390246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    if (path.c_str() == NULL) {
229490246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey        return;
229590246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    }
229690246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    ScopedUtfChars name(env, javaName);
229790246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    if (name.c_str() == NULL) {
229890246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey        return;
229990246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    }
230090246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    ScopedBytesRO value(env, javaValue);
230190246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    if (value.get() == NULL) {
230290246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey        return;
230390246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    }
230490246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    size_t valueLength = env->GetArrayLength(javaValue);
230590246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    int res = setxattr(path.c_str(), name.c_str(), value.get(), valueLength, flags);
230690246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    if (res < 0) {
230790246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey        throwErrnoException(env, "setxattr");
230890246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    }
230990246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey}
231090246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey
23110965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_shutdown(JNIEnv* env, jobject, jobject javaFd, jint how) {
231259e4744d27231f260271dbbca406e0cc39768116Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
231359e4744d27231f260271dbbca406e0cc39768116Elliott Hughes    throwIfMinusOne(env, "shutdown", TEMP_FAILURE_RETRY(shutdown(fd, how)));
231459e4744d27231f260271dbbca406e0cc39768116Elliott Hughes}
231559e4744d27231f260271dbbca406e0cc39768116Elliott Hughes
23160965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_socket(JNIEnv* env, jobject, jint domain, jint type, jint protocol) {
231700bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    if (domain == AF_PACKET) {
231800bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        protocol = htons(protocol);  // Packet sockets specify the protocol in host byte order.
231900bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    }
2320454a95f6a28855aa3c88d168b15a45bf315efc99Elliott Hughes    int fd = throwIfMinusOne(env, "socket", TEMP_FAILURE_RETRY(socket(domain, type, protocol)));
2321454a95f6a28855aa3c88d168b15a45bf315efc99Elliott Hughes    return fd != -1 ? jniCreateFileDescriptor(env, fd) : NULL;
2322454a95f6a28855aa3c88d168b15a45bf315efc99Elliott Hughes}
2323454a95f6a28855aa3c88d168b15a45bf315efc99Elliott Hughes
23240965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_socketpair(JNIEnv* env, jobject, jint domain, jint type, jint protocol, jobject javaFd1, jobject javaFd2) {
23253218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes    int fds[2];
23263218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes    int rc = throwIfMinusOne(env, "socketpair", TEMP_FAILURE_RETRY(socketpair(domain, type, protocol, fds)));
23273218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes    if (rc != -1) {
23283218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes        jniSetFileDescriptorOfFD(env, javaFd1, fds[0]);
23293218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes        jniSetFileDescriptorOfFD(env, javaFd2, fds[1]);
23303218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes    }
23313218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes}
23323218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes
23330965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_stat(JNIEnv* env, jobject, jstring javaPath) {
233447cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes    return doStat(env, javaPath, false);
233547cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes}
233647cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes
23370965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_statvfs(JNIEnv* env, jobject, jstring javaPath) {
233859fa7163774d6930a174bc038414a4b780581957Elliott Hughes    ScopedUtfChars path(env, javaPath);
233959fa7163774d6930a174bc038414a4b780581957Elliott Hughes    if (path.c_str() == NULL) {
234059fa7163774d6930a174bc038414a4b780581957Elliott Hughes        return NULL;
234159fa7163774d6930a174bc038414a4b780581957Elliott Hughes    }
2342721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes    struct statvfs sb;
2343721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes    int rc = TEMP_FAILURE_RETRY(statvfs(path.c_str(), &sb));
234459fa7163774d6930a174bc038414a4b780581957Elliott Hughes    if (rc == -1) {
2345721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes        throwErrnoException(env, "statvfs");
234659fa7163774d6930a174bc038414a4b780581957Elliott Hughes        return NULL;
234759fa7163774d6930a174bc038414a4b780581957Elliott Hughes    }
2348721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes    return makeStructStatVfs(env, sb);
234959fa7163774d6930a174bc038414a4b780581957Elliott Hughes}
235059fa7163774d6930a174bc038414a4b780581957Elliott Hughes
23510965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jstring Linux_strerror(JNIEnv* env, jobject, jint errnum) {
235252724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes    char buffer[BUFSIZ];
2353ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    const char* message = jniStrError(errnum, buffer, sizeof(buffer));
2354ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    return env->NewStringUTF(message);
2355ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes}
2356ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes
23570965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jstring Linux_strsignal(JNIEnv* env, jobject, jint signal) {
2358763f8ed6195707d0c30bfae1ca8a3bb886b746ccElliott Hughes    return env->NewStringUTF(strsignal(signal));
2359763f8ed6195707d0c30bfae1ca8a3bb886b746ccElliott Hughes}
2360763f8ed6195707d0c30bfae1ca8a3bb886b746ccElliott Hughes
23610965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_symlink(JNIEnv* env, jobject, jstring javaOldPath, jstring javaNewPath) {
2362a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes    ScopedUtfChars oldPath(env, javaOldPath);
2363a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes    if (oldPath.c_str() == NULL) {
2364a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes        return;
2365a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes    }
2366a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes    ScopedUtfChars newPath(env, javaNewPath);
2367a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes    if (newPath.c_str() == NULL) {
2368a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes        return;
2369a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes    }
2370a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes    throwIfMinusOne(env, "symlink", TEMP_FAILURE_RETRY(symlink(oldPath.c_str(), newPath.c_str())));
2371a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes}
2372a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes
23730965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jlong Linux_sysconf(JNIEnv* env, jobject, jint name) {
23746fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughes    // Since -1 is a valid result from sysconf(3), detecting failure is a little more awkward.
23756fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughes    errno = 0;
23766fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughes    long result = sysconf(name);
23776fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughes    if (result == -1L && errno == EINVAL) {
23787e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes        throwErrnoException(env, "sysconf");
23796fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughes    }
23806fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughes    return result;
23816fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughes}
23826fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughes
23830965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_tcdrain(JNIEnv* env, jobject, jobject javaFd) {
2384bb5816aa1626eb2f6263bd21479600b114c8a1bdJohan Redestig    int fd = jniGetFDFromFileDescriptor(env, javaFd);
2385bb5816aa1626eb2f6263bd21479600b114c8a1bdJohan Redestig    throwIfMinusOne(env, "tcdrain", TEMP_FAILURE_RETRY(tcdrain(fd)));
2386bb5816aa1626eb2f6263bd21479600b114c8a1bdJohan Redestig}
2387bb5816aa1626eb2f6263bd21479600b114c8a1bdJohan Redestig
23880965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_tcsendbreak(JNIEnv* env, jobject, jobject javaFd, jint duration) {
2389039f7599559fd7e48c354b99dcb94ff391f53349Elliott Hughes  int fd = jniGetFDFromFileDescriptor(env, javaFd);
2390039f7599559fd7e48c354b99dcb94ff391f53349Elliott Hughes  throwIfMinusOne(env, "tcsendbreak", TEMP_FAILURE_RETRY(tcsendbreak(fd, duration)));
2391039f7599559fd7e48c354b99dcb94ff391f53349Elliott Hughes}
2392039f7599559fd7e48c354b99dcb94ff391f53349Elliott Hughes
23930965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_umaskImpl(JNIEnv*, jobject, jint mask) {
239444f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes    return umask(mask);
239544f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes}
239644f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes
23970965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_uname(JNIEnv* env, jobject) {
23987341b9ed7157a1e37a3e69a0974676da358b735aElliott Hughes    struct utsname buf;
23999b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes    if (TEMP_FAILURE_RETRY(uname(&buf)) == -1) {
24009b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes        return NULL; // Can't happen.
24017341b9ed7157a1e37a3e69a0974676da358b735aElliott Hughes    }
24027341b9ed7157a1e37a3e69a0974676da358b735aElliott Hughes    return makeStructUtsname(env, buf);
24037341b9ed7157a1e37a3e69a0974676da358b735aElliott Hughes}
24047341b9ed7157a1e37a3e69a0974676da358b735aElliott Hughes
24050965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_unlink(JNIEnv* env, jobject, jstring javaPathname) {
24065e8f82f2592498e75ac4685ccd0d31d601d37bdcNeil Fuller    ScopedUtfChars pathname(env, javaPathname);
24075e8f82f2592498e75ac4685ccd0d31d601d37bdcNeil Fuller    if (pathname.c_str() == NULL) {
24085e8f82f2592498e75ac4685ccd0d31d601d37bdcNeil Fuller        return;
24095e8f82f2592498e75ac4685ccd0d31d601d37bdcNeil Fuller    }
24105e8f82f2592498e75ac4685ccd0d31d601d37bdcNeil Fuller    throwIfMinusOne(env, "unlink", unlink(pathname.c_str()));
24115e8f82f2592498e75ac4685ccd0d31d601d37bdcNeil Fuller}
24125e8f82f2592498e75ac4685ccd0d31d601d37bdcNeil Fuller
24130965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_unsetenv(JNIEnv* env, jobject, jstring javaName) {
2414895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes    ScopedUtfChars name(env, javaName);
2415895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes    if (name.c_str() == NULL) {
2416895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes        return;
2417895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes    }
2418895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes    throwIfMinusOne(env, "unsetenv", unsetenv(name.c_str()));
2419895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes}
2420895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes
24210965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_waitpid(JNIEnv* env, jobject, jint pid, jobject javaStatus, jint options) {
24229e67ca71d3d4a489a157abadc5ba519ced7a0b50Elliott Hughes    int status;
24239e67ca71d3d4a489a157abadc5ba519ced7a0b50Elliott Hughes    int rc = throwIfMinusOne(env, "waitpid", TEMP_FAILURE_RETRY(waitpid(pid, &status, options)));
24249e67ca71d3d4a489a157abadc5ba519ced7a0b50Elliott Hughes    if (rc != -1) {
2425e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer        env->SetIntField(javaStatus, int32RefValueFid, status);
24269e67ca71d3d4a489a157abadc5ba519ced7a0b50Elliott Hughes    }
24279e67ca71d3d4a489a157abadc5ba519ced7a0b50Elliott Hughes    return rc;
24289e67ca71d3d4a489a157abadc5ba519ced7a0b50Elliott Hughes}
24299e67ca71d3d4a489a157abadc5ba519ced7a0b50Elliott Hughes
24300965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_writeBytes(JNIEnv* env, jobject, jobject javaFd, jbyteArray javaBytes, jint byteOffset, jint byteCount) {
24310568a63ba1086a78ffb4cff68dd2eac4f9908e13Elliott Hughes    ScopedBytesRO bytes(env, javaBytes);
243278c7cc547101002b9f9043cf3845970719d1bda8Elliott Hughes    if (bytes.get() == NULL) {
243378c7cc547101002b9f9043cf3845970719d1bda8Elliott Hughes        return -1;
243478c7cc547101002b9f9043cf3845970719d1bda8Elliott Hughes    }
2435f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    return IO_FAILURE_RETRY(env, ssize_t, write, javaFd, bytes.get() + byteOffset, byteCount);
243678c7cc547101002b9f9043cf3845970719d1bda8Elliott Hughes}
243778c7cc547101002b9f9043cf3845970719d1bda8Elliott Hughes
24380965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_writev(JNIEnv* env, jobject, jobject javaFd, jobjectArray buffers, jintArray offsets, jintArray byteCounts) {
24398dc754726bb5303c25e2c48decdf76d9323ee231Elliott Hughes    IoVec<ScopedBytesRO> ioVec(env, env->GetArrayLength(buffers));
2440bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    if (!ioVec.init(buffers, offsets, byteCounts)) {
2441bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        return -1;
2442bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    }
2443f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    return IO_FAILURE_RETRY(env, ssize_t, writev, javaFd, ioVec.get(), ioVec.size());
2444bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes}
2445bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes
24468f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline#define NATIVE_METHOD_OVERLOAD(className, functionName, signature, variant) \
24478f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    { #functionName, signature, reinterpret_cast<void*>(className ## _ ## functionName ## variant) }
24488f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline
2449ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughesstatic JNINativeMethod gMethods[] = {
24500965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, accept, "(Ljava/io/FileDescriptor;Ljava/net/SocketAddress;)Ljava/io/FileDescriptor;"),
24510965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, access, "(Ljava/lang/String;I)Z"),
24520965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, android_getaddrinfo, "(Ljava/lang/String;Landroid/system/StructAddrinfo;I)[Ljava/net/InetAddress;"),
24530965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, bind, "(Ljava/io/FileDescriptor;Ljava/net/InetAddress;I)V"),
24540965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD_OVERLOAD(Linux, bind, "(Ljava/io/FileDescriptor;Ljava/net/SocketAddress;)V", SocketAddress),
24555744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    NATIVE_METHOD(Linux, capget,
24565744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe                  "(Landroid/system/StructCapUserHeader;)[Landroid/system/StructCapUserData;"),
24575744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    NATIVE_METHOD(Linux, capset,
24585744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe                  "(Landroid/system/StructCapUserHeader;[Landroid/system/StructCapUserData;)V"),
24590965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, chmod, "(Ljava/lang/String;I)V"),
24600965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, chown, "(Ljava/lang/String;II)V"),
24610965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, close, "(Ljava/io/FileDescriptor;)V"),
24620965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, connect, "(Ljava/io/FileDescriptor;Ljava/net/InetAddress;I)V"),
24630965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD_OVERLOAD(Linux, connect, "(Ljava/io/FileDescriptor;Ljava/net/SocketAddress;)V", SocketAddress),
24640965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, dup, "(Ljava/io/FileDescriptor;)Ljava/io/FileDescriptor;"),
24650965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, dup2, "(Ljava/io/FileDescriptor;I)Ljava/io/FileDescriptor;"),
24660965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, environ, "()[Ljava/lang/String;"),
24670965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, execv, "(Ljava/lang/String;[Ljava/lang/String;)V"),
24680965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, execve, "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V"),
24690965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, fchmod, "(Ljava/io/FileDescriptor;I)V"),
24700965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, fchown, "(Ljava/io/FileDescriptor;II)V"),
24710965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, fcntlFlock, "(Ljava/io/FileDescriptor;ILandroid/system/StructFlock;)I"),
24720965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, fcntlInt, "(Ljava/io/FileDescriptor;II)I"),
24730965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, fcntlVoid, "(Ljava/io/FileDescriptor;I)I"),
24740965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, fdatasync, "(Ljava/io/FileDescriptor;)V"),
24750965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, fstat, "(Ljava/io/FileDescriptor;)Landroid/system/StructStat;"),
24760965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, fstatvfs, "(Ljava/io/FileDescriptor;)Landroid/system/StructStatVfs;"),
24770965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, fsync, "(Ljava/io/FileDescriptor;)V"),
24780965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, ftruncate, "(Ljava/io/FileDescriptor;J)V"),
24790965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, gai_strerror, "(I)Ljava/lang/String;"),
24800965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getegid, "()I"),
24810965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, geteuid, "()I"),
24820965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getgid, "()I"),
248344177e6982a62506127a857070a2452956c3f0f1Enrico Granata    NATIVE_METHOD(Linux, getgroups, "()[I"),
24840965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getenv, "(Ljava/lang/String;)Ljava/lang/String;"),
24850965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getnameinfo, "(Ljava/net/InetAddress;I)Ljava/lang/String;"),
24860965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getpeername, "(Ljava/io/FileDescriptor;)Ljava/net/SocketAddress;"),
24870965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getpgid, "(I)I"),
24880965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getpid, "()I"),
24890965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getppid, "()I"),
24900965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getpwnam, "(Ljava/lang/String;)Landroid/system/StructPasswd;"),
24910965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getpwuid, "(I)Landroid/system/StructPasswd;"),
2492e873cd1285c04da110758df066b4bd40ad6eb93dNarayan Kamath    NATIVE_METHOD(Linux, getrlimit, "(I)Landroid/system/StructRlimit;"),
24930965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getsockname, "(Ljava/io/FileDescriptor;)Ljava/net/SocketAddress;"),
24940965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getsockoptByte, "(Ljava/io/FileDescriptor;II)I"),
24950965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getsockoptInAddr, "(Ljava/io/FileDescriptor;II)Ljava/net/InetAddress;"),
24960965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getsockoptInt, "(Ljava/io/FileDescriptor;II)I"),
24970965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getsockoptLinger, "(Ljava/io/FileDescriptor;II)Landroid/system/StructLinger;"),
24980965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getsockoptTimeval, "(Ljava/io/FileDescriptor;II)Landroid/system/StructTimeval;"),
24990965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getsockoptUcred, "(Ljava/io/FileDescriptor;II)Landroid/system/StructUcred;"),
25000965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, gettid, "()I"),
25010965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getuid, "()I"),
25020965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getxattr, "(Ljava/lang/String;Ljava/lang/String;)[B"),
25030965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getifaddrs, "()[Landroid/system/StructIfaddrs;"),
25040965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, if_indextoname, "(I)Ljava/lang/String;"),
25050965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, if_nametoindex, "(Ljava/lang/String;)I"),
25060965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, inet_pton, "(ILjava/lang/String;)Ljava/net/InetAddress;"),
25070965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, ioctlFlags, "(Ljava/io/FileDescriptor;Ljava/lang/String;)I"),
25080965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, ioctlInetAddress, "(Ljava/io/FileDescriptor;ILjava/lang/String;)Ljava/net/InetAddress;"),
2509e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer    NATIVE_METHOD(Linux, ioctlInt, "(Ljava/io/FileDescriptor;ILandroid/system/Int32Ref;)I"),
25100965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, ioctlMTU, "(Ljava/io/FileDescriptor;Ljava/lang/String;)I"),
25110965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, isatty, "(Ljava/io/FileDescriptor;)Z"),
25120965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, kill, "(II)V"),
25130965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, lchown, "(Ljava/lang/String;II)V"),
25140965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, link, "(Ljava/lang/String;Ljava/lang/String;)V"),
25150965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, listen, "(Ljava/io/FileDescriptor;I)V"),
25160965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, listxattr, "(Ljava/lang/String;)[Ljava/lang/String;"),
25170965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, lseek, "(Ljava/io/FileDescriptor;JI)J"),
25180965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, lstat, "(Ljava/lang/String;)Landroid/system/StructStat;"),
25190965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, mincore, "(JJ[B)V"),
25200965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, mkdir, "(Ljava/lang/String;I)V"),
25210965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, mkfifo, "(Ljava/lang/String;I)V"),
25220965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, mlock, "(JJ)V"),
25230965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, mmap, "(JJIILjava/io/FileDescriptor;J)J"),
25240965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, msync, "(JJI)V"),
25250965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, munlock, "(JJ)V"),
25260965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, munmap, "(JJ)V"),
25270965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, open, "(Ljava/lang/String;II)Ljava/io/FileDescriptor;"),
25280965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, pipe2, "(I)[Ljava/io/FileDescriptor;"),
25290965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, poll, "([Landroid/system/StructPollfd;I)I"),
25300965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, posix_fallocate, "(Ljava/io/FileDescriptor;JJ)V"),
25310965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, prctl, "(IJJJJ)I"),
25320965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, preadBytes, "(Ljava/io/FileDescriptor;Ljava/lang/Object;IIJ)I"),
25330965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, pwriteBytes, "(Ljava/io/FileDescriptor;Ljava/lang/Object;IIJ)I"),
25340965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, readBytes, "(Ljava/io/FileDescriptor;Ljava/lang/Object;II)I"),
25350965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, readlink, "(Ljava/lang/String;)Ljava/lang/String;"),
25360965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, realpath, "(Ljava/lang/String;)Ljava/lang/String;"),
25370965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, readv, "(Ljava/io/FileDescriptor;[Ljava/lang/Object;[I[I)I"),
25380965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, recvfromBytes, "(Ljava/io/FileDescriptor;Ljava/lang/Object;IIILjava/net/InetSocketAddress;)I"),
25390965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, remove, "(Ljava/lang/String;)V"),
25400965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, removexattr, "(Ljava/lang/String;Ljava/lang/String;)V"),
25410965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, rename, "(Ljava/lang/String;Ljava/lang/String;)V"),
2542e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer    NATIVE_METHOD(Linux, sendfile, "(Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;Landroid/system/Int64Ref;J)J"),
25430965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, sendtoBytes, "(Ljava/io/FileDescriptor;Ljava/lang/Object;IIILjava/net/InetAddress;I)I"),
25440965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD_OVERLOAD(Linux, sendtoBytes, "(Ljava/io/FileDescriptor;Ljava/lang/Object;IIILjava/net/SocketAddress;)I", SocketAddress),
25450965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setegid, "(I)V"),
25460965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setenv, "(Ljava/lang/String;Ljava/lang/String;Z)V"),
25470965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, seteuid, "(I)V"),
25480965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setgid, "(I)V"),
254944177e6982a62506127a857070a2452956c3f0f1Enrico Granata    NATIVE_METHOD(Linux, setgroups, "([I)V"),
25500965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setpgid, "(II)V"),
25510965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setregid, "(II)V"),
25520965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setreuid, "(II)V"),
25530965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setsid, "()I"),
25540965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setsockoptByte, "(Ljava/io/FileDescriptor;III)V"),
25550965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setsockoptIfreq, "(Ljava/io/FileDescriptor;IILjava/lang/String;)V"),
25560965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setsockoptInt, "(Ljava/io/FileDescriptor;III)V"),
25570965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setsockoptIpMreqn, "(Ljava/io/FileDescriptor;III)V"),
25580965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setsockoptGroupReq, "(Ljava/io/FileDescriptor;IILandroid/system/StructGroupReq;)V"),
25590965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setsockoptLinger, "(Ljava/io/FileDescriptor;IILandroid/system/StructLinger;)V"),
25600965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setsockoptTimeval, "(Ljava/io/FileDescriptor;IILandroid/system/StructTimeval;)V"),
25610965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setuid, "(I)V"),
25620965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setxattr, "(Ljava/lang/String;Ljava/lang/String;[BI)V"),
25630965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, shutdown, "(Ljava/io/FileDescriptor;I)V"),
25640965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, socket, "(III)Ljava/io/FileDescriptor;"),
25650965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, socketpair, "(IIILjava/io/FileDescriptor;Ljava/io/FileDescriptor;)V"),
25660965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, stat, "(Ljava/lang/String;)Landroid/system/StructStat;"),
25670965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, statvfs, "(Ljava/lang/String;)Landroid/system/StructStatVfs;"),
25680965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, strerror, "(I)Ljava/lang/String;"),
25690965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, strsignal, "(I)Ljava/lang/String;"),
25700965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, symlink, "(Ljava/lang/String;Ljava/lang/String;)V"),
25710965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, sysconf, "(I)J"),
25720965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, tcdrain, "(Ljava/io/FileDescriptor;)V"),
25730965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, tcsendbreak, "(Ljava/io/FileDescriptor;I)V"),
25740965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, umaskImpl, "(I)I"),
25750965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, uname, "()Landroid/system/StructUtsname;"),
25760965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, unlink, "(Ljava/lang/String;)V"),
25770965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, unsetenv, "(Ljava/lang/String;)V"),
2578e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer    NATIVE_METHOD(Linux, waitpid, "(ILandroid/system/Int32Ref;I)I"),
25790965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, writeBytes, "(Ljava/io/FileDescriptor;Ljava/lang/Object;II)I"),
25800965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, writev, "(Ljava/io/FileDescriptor;[Ljava/lang/Object;[I[I)I"),
2581ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes};
25820965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampevoid register_libcore_io_Linux(JNIEnv* env) {
25832c549f1ba3fb683ab1c4ede75bdcb312e8769672Andreas Gampe    // Note: it is safe to only cache the fields as boot classpath classes are never
25842c549f1ba3fb683ab1c4ede75bdcb312e8769672Andreas Gampe    //       unloaded.
2585e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer    ScopedLocalRef<jclass> int32RefClass(env, env->FindClass("android/system/Int32Ref"));
2586e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer    CHECK(int32RefClass != nullptr);
2587e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer    int32RefValueFid = env->GetFieldID(int32RefClass.get(), "value", "I");
2588e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer    CHECK(int32RefValueFid != nullptr);
2589e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer
2590e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer    ScopedLocalRef<jclass> int64RefClass(env, env->FindClass("android/system/Int64Ref"));
2591e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer    CHECK(int64RefClass != nullptr);
2592e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer    int64RefValueFid = env->GetFieldID(int64RefClass.get(), "value", "J");
2593e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer    CHECK(int64RefValueFid != nullptr);
25942c549f1ba3fb683ab1c4ede75bdcb312e8769672Andreas Gampe
25950965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    jniRegisterNativeMethods(env, "libcore/io/Linux", gMethods, NELEM(gMethods));
2596ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes}
2597