mirror of
https://github.com/privatevoid-net/nix-super.git
synced 2024-11-25 23:36:16 +02:00
Start factoring out Unix assumptions
This splits files and adds new identifiers in preperation for supporting windows, but no Windows-specific code is actually added yet. Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
This commit is contained in:
parent
852391765d
commit
02fa20622f
34 changed files with 352 additions and 296 deletions
|
@ -17,7 +17,6 @@
|
||||||
#include "cgroup.hh"
|
#include "cgroup.hh"
|
||||||
#include "personality.hh"
|
#include "personality.hh"
|
||||||
#include "current-process.hh"
|
#include "current-process.hh"
|
||||||
#include "namespaces.hh"
|
|
||||||
#include "child.hh"
|
#include "child.hh"
|
||||||
#include "unix-domain-socket.hh"
|
#include "unix-domain-socket.hh"
|
||||||
#include "posix-fs-canonicalise.hh"
|
#include "posix-fs-canonicalise.hh"
|
||||||
|
@ -48,6 +47,7 @@
|
||||||
# include <sys/param.h>
|
# include <sys/param.h>
|
||||||
# include <sys/mount.h>
|
# include <sys/mount.h>
|
||||||
# include <sys/syscall.h>
|
# include <sys/syscall.h>
|
||||||
|
# include "namespaces.hh"
|
||||||
# if HAVE_SECCOMP
|
# if HAVE_SECCOMP
|
||||||
# include <seccomp.h>
|
# include <seccomp.h>
|
||||||
# endif
|
# endif
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#include "filetransfer.hh"
|
#include "filetransfer.hh"
|
||||||
#include "namespaces.hh"
|
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
#include "s3.hh"
|
#include "s3.hh"
|
||||||
|
@ -12,6 +11,10 @@
|
||||||
#include <aws/core/client/ClientConfiguration.h>
|
#include <aws/core/client/ClientConfiguration.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if __linux__
|
||||||
|
# include "namespaces.hh"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
@ -568,7 +571,9 @@ struct curlFileTransfer : public FileTransfer
|
||||||
stopWorkerThread();
|
stopWorkerThread();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#if __linux__
|
||||||
unshareFilesystem();
|
unshareFilesystem();
|
||||||
|
#endif
|
||||||
|
|
||||||
std::map<CURL *, std::shared_ptr<TransferItem>> items;
|
std::map<CURL *, std::shared_ptr<TransferItem>> items;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include "current-process.hh"
|
#include "current-process.hh"
|
||||||
#include "namespaces.hh"
|
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
#include "finally.hh"
|
#include "finally.hh"
|
||||||
#include "file-system.hh"
|
#include "file-system.hh"
|
||||||
|
@ -17,6 +16,7 @@
|
||||||
# include <mutex>
|
# include <mutex>
|
||||||
# include <sys/resource.h>
|
# include <sys/resource.h>
|
||||||
# include "cgroup.hh"
|
# include "cgroup.hh"
|
||||||
|
# include "namespaces.hh"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
|
@ -84,7 +84,9 @@ void restoreProcessContext(bool restoreMounts)
|
||||||
{
|
{
|
||||||
restoreSignals();
|
restoreSignals();
|
||||||
if (restoreMounts) {
|
if (restoreMounts) {
|
||||||
|
#if __linux__
|
||||||
restoreMountNamespace();
|
restoreMountNamespace();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (savedStackSize) {
|
if (savedStackSize) {
|
||||||
|
|
|
@ -32,18 +32,4 @@ std::map<std::string, std::string> getEnv()
|
||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void clearEnv()
|
|
||||||
{
|
|
||||||
for (auto & name : getEnv())
|
|
||||||
unsetenv(name.first.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void replaceEnv(const std::map<std::string, std::string> & newEnv)
|
|
||||||
{
|
|
||||||
clearEnv();
|
|
||||||
for (auto & newEnvVar : newEnv)
|
|
||||||
setenv(newEnvVar.first.c_str(), newEnvVar.second.c_str(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,74 +8,14 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
std::string readFile(int fd)
|
void writeLine(Descriptor fd, std::string s)
|
||||||
{
|
|
||||||
struct stat st;
|
|
||||||
if (fstat(fd, &st) == -1)
|
|
||||||
throw SysError("statting file");
|
|
||||||
|
|
||||||
return drainFD(fd, true, st.st_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void readFull(int fd, char * buf, size_t count)
|
|
||||||
{
|
|
||||||
while (count) {
|
|
||||||
checkInterrupt();
|
|
||||||
ssize_t res = read(fd, buf, count);
|
|
||||||
if (res == -1) {
|
|
||||||
if (errno == EINTR) continue;
|
|
||||||
throw SysError("reading from file");
|
|
||||||
}
|
|
||||||
if (res == 0) throw EndOfFile("unexpected end-of-file");
|
|
||||||
count -= res;
|
|
||||||
buf += res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void writeFull(int fd, std::string_view s, bool allowInterrupts)
|
|
||||||
{
|
|
||||||
while (!s.empty()) {
|
|
||||||
if (allowInterrupts) checkInterrupt();
|
|
||||||
ssize_t res = write(fd, s.data(), s.size());
|
|
||||||
if (res == -1 && errno != EINTR)
|
|
||||||
throw SysError("writing to file");
|
|
||||||
if (res > 0)
|
|
||||||
s.remove_prefix(res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::string readLine(int fd)
|
|
||||||
{
|
|
||||||
std::string s;
|
|
||||||
while (1) {
|
|
||||||
checkInterrupt();
|
|
||||||
char ch;
|
|
||||||
// FIXME: inefficient
|
|
||||||
ssize_t rd = read(fd, &ch, 1);
|
|
||||||
if (rd == -1) {
|
|
||||||
if (errno != EINTR)
|
|
||||||
throw SysError("reading a line");
|
|
||||||
} else if (rd == 0)
|
|
||||||
throw EndOfFile("unexpected EOF reading a line");
|
|
||||||
else {
|
|
||||||
if (ch == '\n') return s;
|
|
||||||
s += ch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void writeLine(int fd, std::string s)
|
|
||||||
{
|
{
|
||||||
s += '\n';
|
s += '\n';
|
||||||
writeFull(fd, s);
|
writeFull(fd, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string drainFD(int fd, bool block, const size_t reserveSize)
|
std::string drainFD(Descriptor fd, bool block, const size_t reserveSize)
|
||||||
{
|
{
|
||||||
// the parser needs two extra bytes to append terminating characters, other users will
|
// the parser needs two extra bytes to append terminating characters, other users will
|
||||||
// not care very much about the extra memory.
|
// not care very much about the extra memory.
|
||||||
|
@ -85,50 +25,18 @@ std::string drainFD(int fd, bool block, const size_t reserveSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void drainFD(int fd, Sink & sink, bool block)
|
|
||||||
{
|
|
||||||
// silence GCC maybe-uninitialized warning in finally
|
|
||||||
int saved = 0;
|
|
||||||
|
|
||||||
if (!block) {
|
|
||||||
saved = fcntl(fd, F_GETFL);
|
|
||||||
if (fcntl(fd, F_SETFL, saved | O_NONBLOCK) == -1)
|
|
||||||
throw SysError("making file descriptor non-blocking");
|
|
||||||
}
|
|
||||||
|
|
||||||
Finally finally([&] {
|
|
||||||
if (!block) {
|
|
||||||
if (fcntl(fd, F_SETFL, saved) == -1)
|
|
||||||
throw SysError("making file descriptor blocking");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
std::vector<unsigned char> buf(64 * 1024);
|
|
||||||
while (1) {
|
|
||||||
checkInterrupt();
|
|
||||||
ssize_t rd = read(fd, buf.data(), buf.size());
|
|
||||||
if (rd == -1) {
|
|
||||||
if (!block && (errno == EAGAIN || errno == EWOULDBLOCK))
|
|
||||||
break;
|
|
||||||
if (errno != EINTR)
|
|
||||||
throw SysError("reading from file");
|
|
||||||
}
|
|
||||||
else if (rd == 0) break;
|
|
||||||
else sink({reinterpret_cast<char *>(buf.data()), size_t(rd)});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
AutoCloseFD::AutoCloseFD() : fd{-1} {}
|
|
||||||
|
AutoCloseFD::AutoCloseFD() : fd{INVALID_DESCRIPTOR} {}
|
||||||
|
|
||||||
|
|
||||||
AutoCloseFD::AutoCloseFD(int fd) : fd{fd} {}
|
AutoCloseFD::AutoCloseFD(Descriptor fd) : fd{fd} {}
|
||||||
|
|
||||||
|
|
||||||
AutoCloseFD::AutoCloseFD(AutoCloseFD && that) : fd{that.fd}
|
AutoCloseFD::AutoCloseFD(AutoCloseFD && that) : fd{that.fd}
|
||||||
{
|
{
|
||||||
that.fd = -1;
|
that.fd = INVALID_DESCRIPTOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -136,7 +44,7 @@ AutoCloseFD & AutoCloseFD::operator =(AutoCloseFD && that)
|
||||||
{
|
{
|
||||||
close();
|
close();
|
||||||
fd = that.fd;
|
fd = that.fd;
|
||||||
that.fd = -1;
|
that.fd = INVALID_DESCRIPTOR;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +59,7 @@ AutoCloseFD::~AutoCloseFD()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int AutoCloseFD::get() const
|
Descriptor AutoCloseFD::get() const
|
||||||
{
|
{
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
@ -159,23 +67,25 @@ int AutoCloseFD::get() const
|
||||||
|
|
||||||
void AutoCloseFD::close()
|
void AutoCloseFD::close()
|
||||||
{
|
{
|
||||||
if (fd != -1) {
|
if (fd != INVALID_DESCRIPTOR) {
|
||||||
if(::close(fd) == -1)
|
if(::close(fd) == -1)
|
||||||
/* This should never happen. */
|
/* This should never happen. */
|
||||||
throw SysError("closing file descriptor %1%", fd);
|
throw SysError("closing file descriptor %1%", fd);
|
||||||
fd = -1;
|
fd = INVALID_DESCRIPTOR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutoCloseFD::fsync()
|
void AutoCloseFD::fsync()
|
||||||
{
|
{
|
||||||
if (fd != -1) {
|
if (fd != INVALID_DESCRIPTOR) {
|
||||||
int result;
|
int result;
|
||||||
|
result =
|
||||||
#if __APPLE__
|
#if __APPLE__
|
||||||
result = ::fcntl(fd, F_FULLFSYNC);
|
::fcntl(fd, F_FULLFSYNC)
|
||||||
#else
|
#else
|
||||||
result = ::fsync(fd);
|
::fsync(fd)
|
||||||
#endif
|
#endif
|
||||||
|
;
|
||||||
if (result == -1)
|
if (result == -1)
|
||||||
throw SysError("fsync file descriptor %1%", fd);
|
throw SysError("fsync file descriptor %1%", fd);
|
||||||
}
|
}
|
||||||
|
@ -184,31 +94,19 @@ void AutoCloseFD::fsync()
|
||||||
|
|
||||||
AutoCloseFD::operator bool() const
|
AutoCloseFD::operator bool() const
|
||||||
{
|
{
|
||||||
return fd != -1;
|
return fd != INVALID_DESCRIPTOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int AutoCloseFD::release()
|
Descriptor AutoCloseFD::release()
|
||||||
{
|
{
|
||||||
int oldFD = fd;
|
Descriptor oldFD = fd;
|
||||||
fd = -1;
|
fd = INVALID_DESCRIPTOR;
|
||||||
return oldFD;
|
return oldFD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Pipe::create()
|
//////////////////////////////////////////////////////////////////////
|
||||||
{
|
|
||||||
int fds[2];
|
|
||||||
#if HAVE_PIPE2
|
|
||||||
if (pipe2(fds, O_CLOEXEC) != 0) throw SysError("creating pipe");
|
|
||||||
#else
|
|
||||||
if (pipe(fds) != 0) throw SysError("creating pipe");
|
|
||||||
closeOnExec(fds[0]);
|
|
||||||
closeOnExec(fds[1]);
|
|
||||||
#endif
|
|
||||||
readSide = fds[0];
|
|
||||||
writeSide = fds[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Pipe::close()
|
void Pipe::close()
|
||||||
|
@ -217,38 +115,4 @@ void Pipe::close()
|
||||||
writeSide.close();
|
writeSide.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void closeMostFDs(const std::set<int> & exceptions)
|
|
||||||
{
|
|
||||||
#if __linux__
|
|
||||||
try {
|
|
||||||
for (auto & s : readDirectory("/proc/self/fd")) {
|
|
||||||
auto fd = std::stoi(s.name);
|
|
||||||
if (!exceptions.count(fd)) {
|
|
||||||
debug("closing leaked FD %d", fd);
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
} catch (SystemError &) {
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int maxFD = 0;
|
|
||||||
maxFD = sysconf(_SC_OPEN_MAX);
|
|
||||||
for (int fd = 0; fd < maxFD; ++fd)
|
|
||||||
if (!exceptions.count(fd))
|
|
||||||
close(fd); /* ignore result */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void closeOnExec(int fd)
|
|
||||||
{
|
|
||||||
int prev;
|
|
||||||
if ((prev = fcntl(fd, F_GETFD, 0)) == -1 ||
|
|
||||||
fcntl(fd, F_SETFD, prev | FD_CLOEXEC) == -1)
|
|
||||||
throw SysError("setting close-on-exec flag");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,53 +9,85 @@ namespace nix {
|
||||||
struct Sink;
|
struct Sink;
|
||||||
struct Source;
|
struct Source;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Operating System capability
|
||||||
|
*/
|
||||||
|
typedef int Descriptor;
|
||||||
|
|
||||||
|
const Descriptor INVALID_DESCRIPTOR = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a native `Descriptor` to a POSIX file descriptor
|
||||||
|
*
|
||||||
|
* This is a no-op except on Windows.
|
||||||
|
*/
|
||||||
|
static inline Descriptor toDescriptor(int fd)
|
||||||
|
{
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a POSIX file descriptor to a native `Descriptor`
|
||||||
|
*
|
||||||
|
* This is a no-op except on Windows.
|
||||||
|
*/
|
||||||
|
static inline int fromDescriptor(Descriptor fd, int flags)
|
||||||
|
{
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read the contents of a resource into a string.
|
* Read the contents of a resource into a string.
|
||||||
*/
|
*/
|
||||||
std::string readFile(int fd);
|
std::string readFile(Descriptor fd);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrappers arount read()/write() that read/write exactly the
|
* Wrappers arount read()/write() that read/write exactly the
|
||||||
* requested number of bytes.
|
* requested number of bytes.
|
||||||
*/
|
*/
|
||||||
void readFull(int fd, char * buf, size_t count);
|
void readFull(Descriptor fd, char * buf, size_t count);
|
||||||
|
|
||||||
void writeFull(int fd, std::string_view s, bool allowInterrupts = true);
|
void writeFull(Descriptor fd, std::string_view s, bool allowInterrupts = true);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read a line from a file descriptor.
|
* Read a line from a file descriptor.
|
||||||
*/
|
*/
|
||||||
std::string readLine(int fd);
|
std::string readLine(Descriptor fd);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write a line to a file descriptor.
|
* Write a line to a file descriptor.
|
||||||
*/
|
*/
|
||||||
void writeLine(int fd, std::string s);
|
void writeLine(Descriptor fd, std::string s);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read a file descriptor until EOF occurs.
|
* Read a file descriptor until EOF occurs.
|
||||||
*/
|
*/
|
||||||
std::string drainFD(int fd, bool block = true, const size_t reserveSize=0);
|
std::string drainFD(Descriptor fd, bool block = true, const size_t reserveSize=0);
|
||||||
|
|
||||||
void drainFD(int fd, Sink & sink, bool block = true);
|
void drainFD(Descriptor fd, Sink & sink, bool block = true);
|
||||||
|
|
||||||
|
[[gnu::always_inline]]
|
||||||
|
inline Descriptor getStandardOut() {
|
||||||
|
return STDOUT_FILENO;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Automatic cleanup of resources.
|
* Automatic cleanup of resources.
|
||||||
*/
|
*/
|
||||||
class AutoCloseFD
|
class AutoCloseFD
|
||||||
{
|
{
|
||||||
int fd;
|
Descriptor fd;
|
||||||
public:
|
public:
|
||||||
AutoCloseFD();
|
AutoCloseFD();
|
||||||
AutoCloseFD(int fd);
|
AutoCloseFD(Descriptor fd);
|
||||||
AutoCloseFD(const AutoCloseFD & fd) = delete;
|
AutoCloseFD(const AutoCloseFD & fd) = delete;
|
||||||
AutoCloseFD(AutoCloseFD&& fd);
|
AutoCloseFD(AutoCloseFD&& fd);
|
||||||
~AutoCloseFD();
|
~AutoCloseFD();
|
||||||
AutoCloseFD& operator =(const AutoCloseFD & fd) = delete;
|
AutoCloseFD& operator =(const AutoCloseFD & fd) = delete;
|
||||||
AutoCloseFD& operator =(AutoCloseFD&& fd);
|
AutoCloseFD& operator =(AutoCloseFD&& fd);
|
||||||
int get() const;
|
Descriptor get() const;
|
||||||
explicit operator bool() const;
|
explicit operator bool() const;
|
||||||
int release();
|
Descriptor release();
|
||||||
void close();
|
void close();
|
||||||
void fsync();
|
void fsync();
|
||||||
};
|
};
|
||||||
|
@ -72,12 +104,12 @@ public:
|
||||||
* Close all file descriptors except those listed in the given set.
|
* Close all file descriptors except those listed in the given set.
|
||||||
* Good practice in child processes.
|
* Good practice in child processes.
|
||||||
*/
|
*/
|
||||||
void closeMostFDs(const std::set<int> & exceptions);
|
void closeMostFDs(const std::set<Descriptor> & exceptions);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the close-on-exec flag for the given file descriptor.
|
* Set the close-on-exec flag for the given file descriptor.
|
||||||
*/
|
*/
|
||||||
void closeOnExec(int fd);
|
void closeOnExec(Descriptor fd);
|
||||||
|
|
||||||
MakeError(EndOfFile, Error);
|
MakeError(EndOfFile, Error);
|
||||||
|
|
||||||
|
|
|
@ -5,18 +5,14 @@
|
||||||
#include "processes.hh"
|
#include "processes.hh"
|
||||||
#include "signals.hh"
|
#include "signals.hh"
|
||||||
|
|
||||||
#if __linux__
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include "cgroup.hh"
|
#include "cgroup.hh"
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
#if __linux__
|
|
||||||
|
|
||||||
bool userNamespacesSupported()
|
bool userNamespacesSupported()
|
||||||
{
|
{
|
||||||
static auto res = [&]() -> bool
|
static auto res = [&]() -> bool
|
||||||
|
@ -101,19 +97,14 @@ bool mountAndPidNamespacesSupported()
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#if __linux__
|
|
||||||
static AutoCloseFD fdSavedMountNamespace;
|
static AutoCloseFD fdSavedMountNamespace;
|
||||||
static AutoCloseFD fdSavedRoot;
|
static AutoCloseFD fdSavedRoot;
|
||||||
#endif
|
|
||||||
|
|
||||||
void saveMountNamespace()
|
void saveMountNamespace()
|
||||||
{
|
{
|
||||||
#if __linux__
|
|
||||||
static std::once_flag done;
|
static std::once_flag done;
|
||||||
std::call_once(done, []() {
|
std::call_once(done, []() {
|
||||||
fdSavedMountNamespace = open("/proc/self/ns/mnt", O_RDONLY);
|
fdSavedMountNamespace = open("/proc/self/ns/mnt", O_RDONLY);
|
||||||
|
@ -122,12 +113,10 @@ void saveMountNamespace()
|
||||||
|
|
||||||
fdSavedRoot = open("/proc/self/root", O_RDONLY);
|
fdSavedRoot = open("/proc/self/root", O_RDONLY);
|
||||||
});
|
});
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void restoreMountNamespace()
|
void restoreMountNamespace()
|
||||||
{
|
{
|
||||||
#if __linux__
|
|
||||||
try {
|
try {
|
||||||
auto savedCwd = absPath(".");
|
auto savedCwd = absPath(".");
|
||||||
|
|
||||||
|
@ -146,15 +135,12 @@ void restoreMountNamespace()
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
debug(e.msg());
|
debug(e.msg());
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void unshareFilesystem()
|
void unshareFilesystem()
|
||||||
{
|
{
|
||||||
#ifdef __linux__
|
|
||||||
if (unshare(CLONE_FS) != 0 && errno != EPERM)
|
if (unshare(CLONE_FS) != 0 && errno != EPERM)
|
||||||
throw SysError("unsharing filesystem state in download thread");
|
throw SysError("unsharing filesystem state in download thread");
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -26,12 +26,8 @@ void restoreMountNamespace();
|
||||||
*/
|
*/
|
||||||
void unshareFilesystem();
|
void unshareFilesystem();
|
||||||
|
|
||||||
#if __linux__
|
|
||||||
|
|
||||||
bool userNamespacesSupported();
|
bool userNamespacesSupported();
|
||||||
|
|
||||||
bool mountAndPidNamespacesSupported();
|
bool mountAndPidNamespacesSupported();
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -37,8 +37,9 @@ void Logger::warn(const std::string & msg)
|
||||||
|
|
||||||
void Logger::writeToStdout(std::string_view s)
|
void Logger::writeToStdout(std::string_view s)
|
||||||
{
|
{
|
||||||
writeFull(STDOUT_FILENO, s);
|
Descriptor standard_out = getStandardOut();
|
||||||
writeFull(STDOUT_FILENO, "\n");
|
writeFull(standard_out, s);
|
||||||
|
writeFull(standard_out, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
class SimpleLogger : public Logger
|
class SimpleLogger : public Logger
|
||||||
|
|
|
@ -119,18 +119,18 @@ protected:
|
||||||
*/
|
*/
|
||||||
struct FdSink : BufferedSink
|
struct FdSink : BufferedSink
|
||||||
{
|
{
|
||||||
int fd;
|
Descriptor fd;
|
||||||
size_t written = 0;
|
size_t written = 0;
|
||||||
|
|
||||||
FdSink() : fd(-1) { }
|
FdSink() : fd(INVALID_DESCRIPTOR) { }
|
||||||
FdSink(int fd) : fd(fd) { }
|
FdSink(Descriptor fd) : fd(fd) { }
|
||||||
FdSink(FdSink&&) = default;
|
FdSink(FdSink&&) = default;
|
||||||
|
|
||||||
FdSink & operator=(FdSink && s)
|
FdSink & operator=(FdSink && s)
|
||||||
{
|
{
|
||||||
flush();
|
flush();
|
||||||
fd = s.fd;
|
fd = s.fd;
|
||||||
s.fd = -1;
|
s.fd = INVALID_DESCRIPTOR;
|
||||||
written = s.written;
|
written = s.written;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -151,18 +151,18 @@ private:
|
||||||
*/
|
*/
|
||||||
struct FdSource : BufferedSource
|
struct FdSource : BufferedSource
|
||||||
{
|
{
|
||||||
int fd;
|
Descriptor fd;
|
||||||
size_t read = 0;
|
size_t read = 0;
|
||||||
BackedStringView endOfFileError{"unexpected end-of-file"};
|
BackedStringView endOfFileError{"unexpected end-of-file"};
|
||||||
|
|
||||||
FdSource() : fd(-1) { }
|
FdSource() : fd(INVALID_DESCRIPTOR) { }
|
||||||
FdSource(int fd) : fd(fd) { }
|
FdSource(Descriptor fd) : fd(fd) { }
|
||||||
FdSource(FdSource &&) = default;
|
FdSource(FdSource &&) = default;
|
||||||
|
|
||||||
FdSource & operator=(FdSource && s)
|
FdSource & operator=(FdSource && s)
|
||||||
{
|
{
|
||||||
fd = s.fd;
|
fd = s.fd;
|
||||||
s.fd = -1;
|
s.fd = INVALID_DESCRIPTOR;
|
||||||
read = s.read;
|
read = s.read;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
21
src/libutil/unix/environment-variables.cc
Normal file
21
src/libutil/unix/environment-variables.cc
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#include "util.hh"
|
||||||
|
#include "environment-variables.hh"
|
||||||
|
|
||||||
|
extern char * * environ __attribute__((weak));
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
void clearEnv()
|
||||||
|
{
|
||||||
|
for (auto & name : getEnv())
|
||||||
|
unsetenv(name.first.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void replaceEnv(const std::map<std::string, std::string> & newEnv)
|
||||||
|
{
|
||||||
|
clearEnv();
|
||||||
|
for (auto & newEnvVar : newEnv)
|
||||||
|
setenv(newEnvVar.first.c_str(), newEnvVar.second.c_str(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
155
src/libutil/unix/file-descriptor.cc
Normal file
155
src/libutil/unix/file-descriptor.cc
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
#include "file-system.hh"
|
||||||
|
#include "signals.hh"
|
||||||
|
#include "finally.hh"
|
||||||
|
#include "serialise.hh"
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
std::string readFile(int fd)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
if (fstat(fd, &st) == -1)
|
||||||
|
throw SysError("statting file");
|
||||||
|
|
||||||
|
return drainFD(fd, true, st.st_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void readFull(int fd, char * buf, size_t count)
|
||||||
|
{
|
||||||
|
while (count) {
|
||||||
|
checkInterrupt();
|
||||||
|
ssize_t res = read(fd, buf, count);
|
||||||
|
if (res == -1) {
|
||||||
|
if (errno == EINTR) continue;
|
||||||
|
throw SysError("reading from file");
|
||||||
|
}
|
||||||
|
if (res == 0) throw EndOfFile("unexpected end-of-file");
|
||||||
|
count -= res;
|
||||||
|
buf += res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void writeFull(int fd, std::string_view s, bool allowInterrupts)
|
||||||
|
{
|
||||||
|
while (!s.empty()) {
|
||||||
|
if (allowInterrupts) checkInterrupt();
|
||||||
|
ssize_t res = write(fd, s.data(), s.size());
|
||||||
|
if (res == -1 && errno != EINTR)
|
||||||
|
throw SysError("writing to file");
|
||||||
|
if (res > 0)
|
||||||
|
s.remove_prefix(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string readLine(int fd)
|
||||||
|
{
|
||||||
|
std::string s;
|
||||||
|
while (1) {
|
||||||
|
checkInterrupt();
|
||||||
|
char ch;
|
||||||
|
// FIXME: inefficient
|
||||||
|
ssize_t rd = read(fd, &ch, 1);
|
||||||
|
if (rd == -1) {
|
||||||
|
if (errno != EINTR)
|
||||||
|
throw SysError("reading a line");
|
||||||
|
} else if (rd == 0)
|
||||||
|
throw EndOfFile("unexpected EOF reading a line");
|
||||||
|
else {
|
||||||
|
if (ch == '\n') return s;
|
||||||
|
s += ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void drainFD(int fd, Sink & sink, bool block)
|
||||||
|
{
|
||||||
|
// silence GCC maybe-uninitialized warning in finally
|
||||||
|
int saved = 0;
|
||||||
|
|
||||||
|
if (!block) {
|
||||||
|
saved = fcntl(fd, F_GETFL);
|
||||||
|
if (fcntl(fd, F_SETFL, saved | O_NONBLOCK) == -1)
|
||||||
|
throw SysError("making file descriptor non-blocking");
|
||||||
|
}
|
||||||
|
|
||||||
|
Finally finally([&]() {
|
||||||
|
if (!block) {
|
||||||
|
if (fcntl(fd, F_SETFL, saved) == -1)
|
||||||
|
throw SysError("making file descriptor blocking");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
std::vector<unsigned char> buf(64 * 1024);
|
||||||
|
while (1) {
|
||||||
|
checkInterrupt();
|
||||||
|
ssize_t rd = read(fd, buf.data(), buf.size());
|
||||||
|
if (rd == -1) {
|
||||||
|
if (!block && (errno == EAGAIN || errno == EWOULDBLOCK))
|
||||||
|
break;
|
||||||
|
if (errno != EINTR)
|
||||||
|
throw SysError("reading from file");
|
||||||
|
}
|
||||||
|
else if (rd == 0) break;
|
||||||
|
else sink({reinterpret_cast<char *>(buf.data()), (size_t) rd});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void Pipe::create()
|
||||||
|
{
|
||||||
|
int fds[2];
|
||||||
|
#if HAVE_PIPE2
|
||||||
|
if (pipe2(fds, O_CLOEXEC) != 0) throw SysError("creating pipe");
|
||||||
|
#else
|
||||||
|
if (pipe(fds) != 0) throw SysError("creating pipe");
|
||||||
|
closeOnExec(fds[0]);
|
||||||
|
closeOnExec(fds[1]);
|
||||||
|
#endif
|
||||||
|
readSide = fds[0];
|
||||||
|
writeSide = fds[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void closeMostFDs(const std::set<int> & exceptions)
|
||||||
|
{
|
||||||
|
#if __linux__
|
||||||
|
try {
|
||||||
|
for (auto & s : readDirectory("/proc/self/fd")) {
|
||||||
|
auto fd = std::stoi(s.name);
|
||||||
|
if (!exceptions.count(fd)) {
|
||||||
|
debug("closing leaked FD %d", fd);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} catch (SysError &) {
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int maxFD = 0;
|
||||||
|
maxFD = sysconf(_SC_OPEN_MAX);
|
||||||
|
for (int fd = 0; fd < maxFD; ++fd)
|
||||||
|
if (!exceptions.count(fd))
|
||||||
|
close(fd); /* ignore result */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void closeOnExec(int fd)
|
||||||
|
{
|
||||||
|
int prev;
|
||||||
|
if ((prev = fcntl(fd, F_GETFD, 0)) == -1 ||
|
||||||
|
fcntl(fd, F_SETFD, prev | FD_CLOEXEC) == -1)
|
||||||
|
throw SysError("setting close-on-exec flag");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
66
src/libutil/unix/users.cc
Normal file
66
src/libutil/unix/users.cc
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
#include "util.hh"
|
||||||
|
#include "users.hh"
|
||||||
|
#include "environment-variables.hh"
|
||||||
|
#include "file-system.hh"
|
||||||
|
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
std::string getUserName()
|
||||||
|
{
|
||||||
|
auto pw = getpwuid(geteuid());
|
||||||
|
std::string name = pw ? pw->pw_name : getEnv("USER").value_or("");
|
||||||
|
if (name.empty())
|
||||||
|
throw Error("cannot figure out user name");
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
Path getHomeOf(uid_t userId)
|
||||||
|
{
|
||||||
|
std::vector<char> buf(16384);
|
||||||
|
struct passwd pwbuf;
|
||||||
|
struct passwd * pw;
|
||||||
|
if (getpwuid_r(userId, &pwbuf, buf.data(), buf.size(), &pw) != 0
|
||||||
|
|| !pw || !pw->pw_dir || !pw->pw_dir[0])
|
||||||
|
throw Error("cannot determine user's home directory");
|
||||||
|
return pw->pw_dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
Path getHome()
|
||||||
|
{
|
||||||
|
static Path homeDir = []()
|
||||||
|
{
|
||||||
|
std::optional<std::string> unownedUserHomeDir = {};
|
||||||
|
auto homeDir = getEnv("HOME");
|
||||||
|
if (homeDir) {
|
||||||
|
// Only use $HOME if doesn't exist or is owned by the current user.
|
||||||
|
struct stat st;
|
||||||
|
int result = stat(homeDir->c_str(), &st);
|
||||||
|
if (result != 0) {
|
||||||
|
if (errno != ENOENT) {
|
||||||
|
warn("couldn't stat $HOME ('%s') for reason other than not existing ('%d'), falling back to the one defined in the 'passwd' file", *homeDir, errno);
|
||||||
|
homeDir.reset();
|
||||||
|
}
|
||||||
|
} else if (st.st_uid != geteuid()) {
|
||||||
|
unownedUserHomeDir.swap(homeDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!homeDir) {
|
||||||
|
homeDir = getHomeOf(geteuid());
|
||||||
|
if (unownedUserHomeDir.has_value() && unownedUserHomeDir != homeDir) {
|
||||||
|
warn("$HOME ('%s') is not owned by you, falling back to the one defined in the 'passwd' file ('%s')", *unownedUserHomeDir, *homeDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *homeDir;
|
||||||
|
}();
|
||||||
|
return homeDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isRootUser() {
|
||||||
|
return getuid() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,63 +3,8 @@
|
||||||
#include "environment-variables.hh"
|
#include "environment-variables.hh"
|
||||||
#include "file-system.hh"
|
#include "file-system.hh"
|
||||||
|
|
||||||
#include <pwd.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
std::string getUserName()
|
|
||||||
{
|
|
||||||
auto pw = getpwuid(geteuid());
|
|
||||||
std::string name = pw ? pw->pw_name : getEnv("USER").value_or("");
|
|
||||||
if (name.empty())
|
|
||||||
throw Error("cannot figure out user name");
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
Path getHomeOf(uid_t userId)
|
|
||||||
{
|
|
||||||
std::vector<char> buf(16384);
|
|
||||||
struct passwd pwbuf;
|
|
||||||
struct passwd * pw;
|
|
||||||
if (getpwuid_r(userId, &pwbuf, buf.data(), buf.size(), &pw) != 0
|
|
||||||
|| !pw || !pw->pw_dir || !pw->pw_dir[0])
|
|
||||||
throw Error("cannot determine user's home directory");
|
|
||||||
return pw->pw_dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
Path getHome()
|
|
||||||
{
|
|
||||||
static Path homeDir = []()
|
|
||||||
{
|
|
||||||
std::optional<std::string> unownedUserHomeDir = {};
|
|
||||||
auto homeDir = getEnv("HOME");
|
|
||||||
if (homeDir) {
|
|
||||||
// Only use $HOME if doesn't exist or is owned by the current user.
|
|
||||||
struct stat st;
|
|
||||||
int result = stat(homeDir->c_str(), &st);
|
|
||||||
if (result != 0) {
|
|
||||||
if (errno != ENOENT) {
|
|
||||||
warn("couldn't stat $HOME ('%s') for reason other than not existing ('%d'), falling back to the one defined in the 'passwd' file", *homeDir, errno);
|
|
||||||
homeDir.reset();
|
|
||||||
}
|
|
||||||
} else if (st.st_uid != geteuid()) {
|
|
||||||
unownedUserHomeDir.swap(homeDir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!homeDir) {
|
|
||||||
homeDir = getHomeOf(geteuid());
|
|
||||||
if (unownedUserHomeDir.has_value() && unownedUserHomeDir != homeDir) {
|
|
||||||
warn("$HOME ('%s') is not owned by you, falling back to the one defined in the 'passwd' file ('%s')", *unownedUserHomeDir, *homeDir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return *homeDir;
|
|
||||||
}();
|
|
||||||
return homeDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Path getCacheDir()
|
Path getCacheDir()
|
||||||
{
|
{
|
||||||
auto cacheDir = getEnv("XDG_CACHE_HOME");
|
auto cacheDir = getEnv("XDG_CACHE_HOME");
|
||||||
|
@ -113,9 +58,4 @@ std::string expandTilde(std::string_view path)
|
||||||
return std::string(path);
|
return std::string(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool isRootUser() {
|
|
||||||
return getuid() == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <grp.h>
|
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
|
||||||
#include <sodium.h>
|
#include <sodium.h>
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#include "args/root.hh"
|
#include "args/root.hh"
|
||||||
#include "current-process.hh"
|
#include "current-process.hh"
|
||||||
#include "namespaces.hh"
|
|
||||||
#include "command.hh"
|
#include "command.hh"
|
||||||
#include "common-args.hh"
|
#include "common-args.hh"
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
|
@ -27,6 +26,10 @@
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
#if __linux__
|
||||||
|
# include "namespaces.hh"
|
||||||
|
#endif
|
||||||
|
|
||||||
extern std::string chrootHelperName;
|
extern std::string chrootHelperName;
|
||||||
|
|
||||||
void chrootHelper(int argc, char * * argv);
|
void chrootHelper(int argc, char * * argv);
|
||||||
|
|
Loading…
Reference in a new issue