Add POSIX fexecve.
I'm skeptical about the usefulness of this, but it's in POSIX, it's in glibc (but not iOS), and it is used in some internal source (test runners and container code). Bug: N/A Test: ran tests Change-Id: I92c5398f2a679b21a33fba92bc8e67e3ae2eb76f
This commit is contained in:
parent
ab9dc08bdd
commit
4d215aad85
|
@ -39,6 +39,8 @@
|
|||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "private/FdPath.h"
|
||||
|
||||
extern "C" char** environ;
|
||||
|
||||
enum ExecVariant { kIsExecL, kIsExecLE, kIsExecLP };
|
||||
|
@ -170,3 +172,10 @@ int execvpe(const char* name, char* const* argv, char* const* envp) {
|
|||
if (saw_EACCES) errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fexecve(int fd, char* const* argv, char* const* envp) {
|
||||
// execveat with AT_EMPTY_PATH (>= 3.19) seems to offer no advantages.
|
||||
execve(FdPath(fd).c_str(), argv, envp);
|
||||
if (errno == ENOENT) errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -33,13 +33,14 @@
|
|||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "private/FdPath.h"
|
||||
|
||||
extern "C" int ___fchmod(int, mode_t);
|
||||
|
||||
int fchmod(int fd, mode_t mode) {
|
||||
int saved_errno = errno;
|
||||
int result = ___fchmod(fd, mode);
|
||||
|
||||
if ((result == 0) || (errno != EBADF)) {
|
||||
if (result == 0 || errno != EBADF) {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -52,16 +53,14 @@ int fchmod(int fd, mode_t mode) {
|
|||
// on an O_PATH file descriptor, and "man open" documents fchmod
|
||||
// on O_PATH file descriptors as returning EBADF.
|
||||
int fd_flag = fcntl(fd, F_GETFL);
|
||||
if ((fd_flag == -1) || ((fd_flag & O_PATH) == 0)) {
|
||||
if (fd_flag == -1 || (fd_flag & O_PATH) == 0) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
char buf[40];
|
||||
snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
|
||||
errno = saved_errno;
|
||||
result = chmod(buf, mode);
|
||||
if ((result == -1) && (errno == ELOOP)) {
|
||||
result = chmod(FdPath(fd).c_str(), mode);
|
||||
if (result == -1 && errno == ELOOP) {
|
||||
// Linux does not support changing the mode of a symlink.
|
||||
// For fchmodat(AT_SYMLINK_NOFOLLOW), POSIX requires a return
|
||||
// value of ENOTSUP. Assume that's true here too.
|
||||
|
|
|
@ -33,13 +33,15 @@
|
|||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "private/FdPath.h"
|
||||
|
||||
extern "C" ssize_t ___fgetxattr(int, const char*, void*, size_t);
|
||||
|
||||
ssize_t fgetxattr(int fd, const char *name, void *value, size_t size) {
|
||||
int saved_errno = errno;
|
||||
ssize_t result = ___fgetxattr(fd, name, value, size);
|
||||
|
||||
if ((result != -1) || (errno != EBADF)) {
|
||||
if (result != -1 || errno != EBADF) {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -47,13 +49,11 @@ ssize_t fgetxattr(int fd, const char *name, void *value, size_t size) {
|
|||
// may not directly support fgetxattr() on such a file descriptor.
|
||||
// Use /proc/self/fd instead to emulate this support.
|
||||
int fd_flag = fcntl(fd, F_GETFL);
|
||||
if ((fd_flag == -1) || ((fd_flag & O_PATH) == 0)) {
|
||||
if (fd_flag == -1 || (fd_flag & O_PATH) == 0) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
char buf[40];
|
||||
snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
|
||||
errno = saved_errno;
|
||||
return getxattr(buf, name, value, size);
|
||||
return getxattr(FdPath(fd).c_str(), name, value, size);
|
||||
}
|
||||
|
|
|
@ -33,13 +33,14 @@
|
|||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "private/FdPath.h"
|
||||
|
||||
extern "C" ssize_t ___flistxattr(int, char*, size_t);
|
||||
|
||||
ssize_t flistxattr(int fd, char *list, size_t size) {
|
||||
int saved_errno = errno;
|
||||
ssize_t result = ___flistxattr(fd, list, size);
|
||||
|
||||
if ((result != -1) || (errno != EBADF)) {
|
||||
if (result != -1 || errno != EBADF) {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -47,13 +48,11 @@ ssize_t flistxattr(int fd, char *list, size_t size) {
|
|||
// may not directly support fgetxattr() on such a file descriptor.
|
||||
// Use /proc/self/fd instead to emulate this support.
|
||||
int fd_flag = fcntl(fd, F_GETFL);
|
||||
if ((fd_flag == -1) || ((fd_flag & O_PATH) == 0)) {
|
||||
if (fd_flag == -1 || (fd_flag & O_PATH) == 0) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
char buf[40];
|
||||
snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
|
||||
errno = saved_errno;
|
||||
return listxattr(buf, list, size);
|
||||
return listxattr(FdPath(fd).c_str(), list, size);
|
||||
}
|
||||
|
|
|
@ -33,13 +33,14 @@
|
|||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "private/FdPath.h"
|
||||
|
||||
extern "C" int ___fsetxattr(int, const char*, const void*, size_t, int);
|
||||
|
||||
int fsetxattr(int fd, const char* name, const void* value, size_t size, int flags) {
|
||||
int saved_errno = errno;
|
||||
int result = ___fsetxattr(fd, name, value, size, flags);
|
||||
|
||||
if ((result == 0) || (errno != EBADF)) {
|
||||
if (result == 0 || errno != EBADF) {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -47,13 +48,11 @@ int fsetxattr(int fd, const char* name, const void* value, size_t size, int flag
|
|||
// may not directly support fsetxattr() on such a file descriptor.
|
||||
// Use /proc/self/fd instead to emulate this support.
|
||||
int fd_flag = fcntl(fd, F_GETFL);
|
||||
if ((fd_flag == -1) || ((fd_flag & O_PATH) == 0)) {
|
||||
if (fd_flag == -1 || (fd_flag & O_PATH) == 0) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
char buf[40];
|
||||
snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
|
||||
errno = saved_errno;
|
||||
return setxattr(buf, name, value, size, flags);
|
||||
return setxattr(FdPath(fd).c_str(), name, value, size, flags);
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include <utmp.h>
|
||||
|
||||
#include "bionic/pthread_internal.h"
|
||||
#include "private/FdPath.h"
|
||||
|
||||
int getpt() {
|
||||
return posix_openpt(O_RDWR|O_NOCTTY);
|
||||
|
@ -94,10 +95,7 @@ int ttyname_r(int fd, char* buf, size_t len) {
|
|||
return errno;
|
||||
}
|
||||
|
||||
char path[64];
|
||||
snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
|
||||
|
||||
ssize_t count = readlink(path, buf, len);
|
||||
ssize_t count = readlink(FdPath(fd).c_str(), buf, len);
|
||||
if (count == -1) {
|
||||
return errno;
|
||||
}
|
||||
|
|
|
@ -98,6 +98,7 @@ int execl(const char* __path, const char* __arg0, ...) __attribute__((__sentinel
|
|||
int execlp(const char* __file, const char* __arg0, ...) __attribute__((__sentinel__));
|
||||
int execle(const char* __path, const char* __arg0, ... /*, char* const* __envp */)
|
||||
__attribute__((__sentinel__(1)));
|
||||
int fexecve(int __fd, char* const* __argv, char* const* __envp) __INTRODUCED_IN_FUTURE;
|
||||
|
||||
int nice(int __incr);
|
||||
|
||||
|
|
|
@ -1325,6 +1325,7 @@ LIBC_P { # introduced=P
|
|||
endhostent;
|
||||
endnetent;
|
||||
endprotoent;
|
||||
fexecve;
|
||||
getentropy;
|
||||
getnetent;
|
||||
getprotoent;
|
||||
|
|
|
@ -1245,6 +1245,7 @@ LIBC_P { # introduced=P
|
|||
endhostent;
|
||||
endnetent;
|
||||
endprotoent;
|
||||
fexecve;
|
||||
getentropy;
|
||||
getnetent;
|
||||
getprotoent;
|
||||
|
|
|
@ -1350,6 +1350,7 @@ LIBC_P { # introduced=P
|
|||
endhostent;
|
||||
endnetent;
|
||||
endprotoent;
|
||||
fexecve;
|
||||
getentropy;
|
||||
getnetent;
|
||||
getprotoent;
|
||||
|
|
|
@ -1309,6 +1309,7 @@ LIBC_P { # introduced=P
|
|||
endhostent;
|
||||
endnetent;
|
||||
endprotoent;
|
||||
fexecve;
|
||||
getentropy;
|
||||
getnetent;
|
||||
getprotoent;
|
||||
|
|
|
@ -1245,6 +1245,7 @@ LIBC_P { # introduced=P
|
|||
endhostent;
|
||||
endnetent;
|
||||
endprotoent;
|
||||
fexecve;
|
||||
getentropy;
|
||||
getnetent;
|
||||
getprotoent;
|
||||
|
|
|
@ -1307,6 +1307,7 @@ LIBC_P { # introduced=P
|
|||
endhostent;
|
||||
endnetent;
|
||||
endprotoent;
|
||||
fexecve;
|
||||
getentropy;
|
||||
getnetent;
|
||||
getprotoent;
|
||||
|
|
|
@ -1245,6 +1245,7 @@ LIBC_P { # introduced=P
|
|||
endhostent;
|
||||
endnetent;
|
||||
endprotoent;
|
||||
fexecve;
|
||||
getentropy;
|
||||
getnetent;
|
||||
getprotoent;
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
class FdPath {
|
||||
public:
|
||||
explicit FdPath(int fd) {
|
||||
snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
|
||||
}
|
||||
|
||||
const char* c_str() {
|
||||
return buf;
|
||||
}
|
||||
|
||||
private:
|
||||
char buf[40];
|
||||
};
|
|
@ -1376,6 +1376,41 @@ TEST(UNISTD_TEST, exec_argv0_null) {
|
|||
"<unknown>: usage: run-as");
|
||||
}
|
||||
|
||||
TEST(UNISTD_TEST, fexecve_failure) {
|
||||
ExecTestHelper eth;
|
||||
errno = 0;
|
||||
int fd = open("/", O_RDONLY);
|
||||
ASSERT_NE(-1, fd);
|
||||
ASSERT_EQ(-1, fexecve(fd, eth.GetArgs(), eth.GetEnv()));
|
||||
ASSERT_EQ(EACCES, errno);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
TEST(UNISTD_TEST, fexecve_bad_fd) {
|
||||
ExecTestHelper eth;
|
||||
errno = 0;
|
||||
ASSERT_EQ(-1, fexecve(-1, eth.GetArgs(), eth.GetEnv()));
|
||||
ASSERT_EQ(EBADF, errno);
|
||||
}
|
||||
|
||||
TEST(UNISTD_TEST, fexecve_args) {
|
||||
// Test basic argument passing.
|
||||
int echo_fd = open(BIN_DIR "echo", O_RDONLY | O_CLOEXEC);
|
||||
ASSERT_NE(-1, echo_fd);
|
||||
ExecTestHelper eth;
|
||||
eth.SetArgs({"echo", "hello", "world", nullptr});
|
||||
eth.Run([&]() { fexecve(echo_fd, eth.GetArgs(), eth.GetEnv()); }, 0, "hello world\n");
|
||||
close(echo_fd);
|
||||
|
||||
// Test environment variable setting too.
|
||||
int printenv_fd = open(BIN_DIR "printenv", O_RDONLY | O_CLOEXEC);
|
||||
ASSERT_NE(-1, printenv_fd);
|
||||
eth.SetArgs({"printenv", nullptr});
|
||||
eth.SetEnv({"A=B", nullptr});
|
||||
eth.Run([&]() { fexecve(printenv_fd, eth.GetArgs(), eth.GetEnv()); }, 0, "A=B\n");
|
||||
close(printenv_fd);
|
||||
}
|
||||
|
||||
TEST(UNISTD_TEST, getlogin_r) {
|
||||
char buf[LOGIN_NAME_MAX] = {};
|
||||
EXPECT_EQ(ERANGE, getlogin_r(buf, 0));
|
||||
|
|
Loading…
Reference in New Issue