Merge pull request #10364 from obsidiansystems/split-out-unix
Start factoring out Unix-assuming code
This commit is contained in:
43 files changed
+402
-302
No files matched your search
@@ -5,6 +5,11 @@ ERROR_SWITCH_ENUM = -Werror=switch-enum
|
||||
$(foreach i, config.h $(wildcard src/lib*/*.hh), \
|
||||
$(eval $(call install-file-in, $(i), $(includedir)/nix, 0644)))
|
||||
|
||||
ifdef HOST_UNIX
|
||||
$(foreach i, $(wildcard src/lib*/unix/*.hh), \
|
||||
$(eval $(call install-file-in, $(i), $(includedir)/nix, 0644)))
|
||||
endif
|
||||
|
||||
$(GCH): src/libutil/util.hh config.h
|
||||
|
||||
GCH_CXXFLAGS = $(INCLUDE_libutil)
|
||||
+1
-1
@@ -6,7 +6,7 @@ libcmd_DIR := $(d)
|
||||
|
||||
libcmd_SOURCES := $(wildcard $(d)/*.cc)
|
||||
|
||||
libcmd_CXXFLAGS += $(INCLUDE_libutil) $(INCLUDE_libstore) $(INCLUDE_libfetchers) $(INCLUDE_libexpr) -I src/libmain
|
||||
libcmd_CXXFLAGS += $(INCLUDE_libutil) $(INCLUDE_libstore) $(INCLUDE_libfetchers) $(INCLUDE_libexpr) $(INCLUDE_libmain)
|
||||
|
||||
libcmd_LDFLAGS = $(EDITLINE_LIBS) $(LOWDOWN_LIBS) $(THREAD_LDFLAGS)
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ libexpr_SOURCES := \
|
||||
|
||||
INCLUDE_libexpr := -I $(d)
|
||||
|
||||
libexpr_CXXFLAGS += $(INCLUDE_libutil) $(INCLUDE_libstore) $(INCLUDE_libfetchers) -I src/libmain $(INCLUDE_libexpr)
|
||||
libexpr_CXXFLAGS += $(INCLUDE_libutil) $(INCLUDE_libstore) $(INCLUDE_libfetchers) $(INCLUDE_libmain) $(INCLUDE_libexpr)
|
||||
|
||||
libexpr_LIBS = libutil libstore libfetchers
|
||||
|
||||
|
||||
@@ -5,10 +5,16 @@ libfetchers_NAME = libnixfetchers
|
||||
libfetchers_DIR := $(d)
|
||||
|
||||
libfetchers_SOURCES := $(wildcard $(d)/*.cc)
|
||||
ifdef HOST_UNIX
|
||||
libfetchers_SOURCES += $(wildcard $(d)/unix/*.cc)
|
||||
endif
|
||||
|
||||
# Not just for this library itself, but also for downstream libraries using this library
|
||||
|
||||
INCLUDE_libfetchers := -I $(d)
|
||||
ifdef HOST_UNIX
|
||||
INCLUDE_libfetchers += -I $(d)/unix
|
||||
endif
|
||||
|
||||
libfetchers_CXXFLAGS += $(INCLUDE_libutil) $(INCLUDE_libstore) $(INCLUDE_libfetchers)
|
||||
|
||||
|
||||
File renamed without changes.
File renamed without changes.
@@ -5,8 +5,13 @@ libmain_NAME = libnixmain
|
||||
libmain_DIR := $(d)
|
||||
|
||||
libmain_SOURCES := $(wildcard $(d)/*.cc)
|
||||
ifdef HOST_UNIX
|
||||
libmain_SOURCES += $(wildcard $(d)/unix/*.cc)
|
||||
endif
|
||||
|
||||
libmain_CXXFLAGS += $(INCLUDE_libutil) $(INCLUDE_libstore)
|
||||
INCLUDE_libmain := -I $(d)
|
||||
|
||||
libmain_CXXFLAGS += $(INCLUDE_libutil) $(INCLUDE_libstore) $(INCLUDE_libmain)
|
||||
|
||||
libmain_LDFLAGS += $(OPENSSL_LIBS)
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include "cgroup.hh"
|
||||
#include "personality.hh"
|
||||
#include "current-process.hh"
|
||||
#include "namespaces.hh"
|
||||
#include "child.hh"
|
||||
#include "unix-domain-socket.hh"
|
||||
#include "posix-fs-canonicalise.hh"
|
||||
@@ -40,18 +39,19 @@
|
||||
|
||||
/* Includes required for chroot support. */
|
||||
#if __linux__
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sched.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/syscall.h>
|
||||
#if HAVE_SECCOMP
|
||||
#include <seccomp.h>
|
||||
#endif
|
||||
#define pivot_root(new_root, put_old) (syscall(SYS_pivot_root, new_root, put_old))
|
||||
# include <sys/ioctl.h>
|
||||
# include <net/if.h>
|
||||
# include <netinet/ip.h>
|
||||
# include <sys/mman.h>
|
||||
# include <sched.h>
|
||||
# include <sys/param.h>
|
||||
# include <sys/mount.h>
|
||||
# include <sys/syscall.h>
|
||||
# include "namespaces.hh"
|
||||
# if HAVE_SECCOMP
|
||||
# include <seccomp.h>
|
||||
# endif
|
||||
# define pivot_root(new_root, put_old) (syscall(SYS_pivot_root, new_root, put_old))
|
||||
#endif
|
||||
|
||||
#if __APPLE__
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "filetransfer.hh"
|
||||
#include "namespaces.hh"
|
||||
#include "globals.hh"
|
||||
#include "store-api.hh"
|
||||
#include "s3.hh"
|
||||
@@ -12,6 +11,10 @@
|
||||
#include <aws/core/client/ClientConfiguration.h>
|
||||
#endif
|
||||
|
||||
#if __linux__
|
||||
# include "namespaces.hh"
|
||||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
@@ -568,7 +571,9 @@ struct curlFileTransfer : public FileTransfer
|
||||
stopWorkerThread();
|
||||
});
|
||||
|
||||
#if __linux__
|
||||
unshareFilesystem();
|
||||
#endif
|
||||
|
||||
std::map<CURL *, std::shared_ptr<TransferItem>> items;
|
||||
|
||||
|
||||
@@ -5,6 +5,9 @@ libstore_NAME = libnixstore
|
||||
libstore_DIR := $(d)
|
||||
|
||||
libstore_SOURCES := $(wildcard $(d)/*.cc $(d)/builtins/*.cc $(d)/build/*.cc)
|
||||
ifdef HOST_UNIX
|
||||
libstore_SOURCES += $(wildcard $(d)/unix/*.cc)
|
||||
endif
|
||||
|
||||
libstore_LIBS = libutil
|
||||
|
||||
@@ -30,6 +33,9 @@ endif
|
||||
# Not just for this library itself, but also for downstream libraries using this library
|
||||
|
||||
INCLUDE_libstore := -I $(d) -I $(d)/build
|
||||
ifdef HOST_UNIX
|
||||
INCLUDE_libstore += -I $(d)/unix
|
||||
endif
|
||||
|
||||
libstore_CXXFLAGS += \
|
||||
$(INCLUDE_libutil) $(INCLUDE_libstore) $(INCLUDE_libstore) \
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include <cstring>
|
||||
|
||||
#include "current-process.hh"
|
||||
#include "namespaces.hh"
|
||||
#include "util.hh"
|
||||
#include "finally.hh"
|
||||
#include "file-system.hh"
|
||||
@@ -17,6 +16,7 @@
|
||||
# include <mutex>
|
||||
# include <sys/resource.h>
|
||||
# include "cgroup.hh"
|
||||
# include "namespaces.hh"
|
||||
#endif
|
||||
|
||||
#include <sys/mount.h>
|
||||
@@ -84,7 +84,9 @@ void restoreProcessContext(bool restoreMounts)
|
||||
{
|
||||
restoreSignals();
|
||||
if (restoreMounts) {
|
||||
#if __linux__
|
||||
restoreMountNamespace();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (savedStackSize) {
|
||||
|
||||
@@ -32,18 +32,4 @@ std::map<std::string, std::string> getEnv()
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
+25
-161
@@ -8,74 +8,14 @@
|
||||
|
||||
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 writeLine(int fd, std::string s)
|
||||
void writeLine(Descriptor fd, std::string s)
|
||||
{
|
||||
s += '\n';
|
||||
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
|
||||
// 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}
|
||||
{
|
||||
that.fd = -1;
|
||||
that.fd = INVALID_DESCRIPTOR;
|
||||
}
|
||||
|
||||
|
||||
@@ -136,7 +44,7 @@ AutoCloseFD & AutoCloseFD::operator =(AutoCloseFD && that)
|
||||
{
|
||||
close();
|
||||
fd = that.fd;
|
||||
that.fd = -1;
|
||||
that.fd = INVALID_DESCRIPTOR;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -151,7 +59,7 @@ AutoCloseFD::~AutoCloseFD()
|
||||
}
|
||||
|
||||
|
||||
int AutoCloseFD::get() const
|
||||
Descriptor AutoCloseFD::get() const
|
||||
{
|
||||
return fd;
|
||||
}
|
||||
@@ -159,56 +67,46 @@ int AutoCloseFD::get() const
|
||||
|
||||
void AutoCloseFD::close()
|
||||
{
|
||||
if (fd != -1) {
|
||||
if (::close(fd) == -1)
|
||||
if (fd != INVALID_DESCRIPTOR) {
|
||||
if(::close(fd) == -1)
|
||||
/* This should never happen. */
|
||||
throw SysError("closing file descriptor %1%", fd);
|
||||
fd = -1;
|
||||
fd = INVALID_DESCRIPTOR;
|
||||
}
|
||||
}
|
||||
|
||||
void AutoCloseFD::fsync()
|
||||
{
|
||||
if (fd != -1) {
|
||||
int result;
|
||||
if (fd != INVALID_DESCRIPTOR) {
|
||||
int result;
|
||||
result =
|
||||
#if __APPLE__
|
||||
result = ::fcntl(fd, F_FULLFSYNC);
|
||||
::fcntl(fd, F_FULLFSYNC)
|
||||
#else
|
||||
result = ::fsync(fd);
|
||||
::fsync(fd)
|
||||
#endif
|
||||
if (result == -1)
|
||||
throw SysError("fsync file descriptor %1%", fd);
|
||||
}
|
||||
;
|
||||
if (result == -1)
|
||||
throw SysError("fsync file descriptor %1%", fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AutoCloseFD::operator bool() const
|
||||
{
|
||||
return fd != -1;
|
||||
return fd != INVALID_DESCRIPTOR;
|
||||
}
|
||||
|
||||
|
||||
int AutoCloseFD::release()
|
||||
Descriptor AutoCloseFD::release()
|
||||
{
|
||||
int oldFD = fd;
|
||||
fd = -1;
|
||||
Descriptor oldFD = fd;
|
||||
fd = INVALID_DESCRIPTOR;
|
||||
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()
|
||||
@@ -217,38 +115,4 @@ void Pipe::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 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.
|
||||
*/
|
||||
std::string readFile(int fd);
|
||||
std::string readFile(Descriptor fd);
|
||||
|
||||
/**
|
||||
* Wrappers arount read()/write() that read/write exactly the
|
||||
* 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.
|
||||
*/
|
||||
std::string readLine(int fd);
|
||||
std::string readLine(Descriptor fd);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
class AutoCloseFD
|
||||
{
|
||||
int fd;
|
||||
Descriptor fd;
|
||||
public:
|
||||
AutoCloseFD();
|
||||
AutoCloseFD(int fd);
|
||||
AutoCloseFD(Descriptor fd);
|
||||
AutoCloseFD(const AutoCloseFD & fd) = delete;
|
||||
AutoCloseFD(AutoCloseFD&& fd);
|
||||
~AutoCloseFD();
|
||||
AutoCloseFD& operator =(const AutoCloseFD & fd) = delete;
|
||||
AutoCloseFD& operator =(AutoCloseFD&& fd);
|
||||
int get() const;
|
||||
Descriptor get() const;
|
||||
explicit operator bool() const;
|
||||
int release();
|
||||
Descriptor release();
|
||||
void close();
|
||||
void fsync();
|
||||
};
|
||||
@@ -72,12 +104,12 @@ public:
|
||||
* Close all file descriptors except those listed in the given set.
|
||||
* 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.
|
||||
*/
|
||||
void closeOnExec(int fd);
|
||||
void closeOnExec(Descriptor fd);
|
||||
|
||||
MakeError(EndOfFile, Error);
|
||||
|
||||
|
||||
@@ -5,18 +5,14 @@
|
||||
#include "processes.hh"
|
||||
#include "signals.hh"
|
||||
|
||||
#if __linux__
|
||||
# include <mutex>
|
||||
# include <sys/resource.h>
|
||||
# include "cgroup.hh"
|
||||
#endif
|
||||
#include <mutex>
|
||||
#include <sys/resource.h>
|
||||
#include "cgroup.hh"
|
||||
|
||||
#include <sys/mount.h>
|
||||
|
||||
namespace nix {
|
||||
|
||||
#if __linux__
|
||||
|
||||
bool userNamespacesSupported()
|
||||
{
|
||||
static auto res = [&]() -> bool
|
||||
@@ -101,19 +97,14 @@ bool mountAndPidNamespacesSupported()
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if __linux__
|
||||
static AutoCloseFD fdSavedMountNamespace;
|
||||
static AutoCloseFD fdSavedRoot;
|
||||
#endif
|
||||
|
||||
void saveMountNamespace()
|
||||
{
|
||||
#if __linux__
|
||||
static std::once_flag done;
|
||||
std::call_once(done, []() {
|
||||
fdSavedMountNamespace = open("/proc/self/ns/mnt", O_RDONLY);
|
||||
@@ -122,12 +113,10 @@ void saveMountNamespace()
|
||||
|
||||
fdSavedRoot = open("/proc/self/root", O_RDONLY);
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
void restoreMountNamespace()
|
||||
{
|
||||
#if __linux__
|
||||
try {
|
||||
auto savedCwd = absPath(".");
|
||||
|
||||
@@ -146,15 +135,12 @@ void restoreMountNamespace()
|
||||
} catch (Error & e) {
|
||||
debug(e.msg());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void unshareFilesystem()
|
||||
{
|
||||
#ifdef __linux__
|
||||
if (unshare(CLONE_FS) != 0 && errno != EPERM)
|
||||
throw SysError("unsharing filesystem state in download thread");
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,12 +26,8 @@ void restoreMountNamespace();
|
||||
*/
|
||||
void unshareFilesystem();
|
||||
|
||||
#if __linux__
|
||||
|
||||
bool userNamespacesSupported();
|
||||
|
||||
bool mountAndPidNamespacesSupported();
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -5,10 +5,22 @@ libutil_NAME = libnixutil
|
||||
libutil_DIR := $(d)
|
||||
|
||||
libutil_SOURCES := $(wildcard $(d)/*.cc $(d)/signature/*.cc)
|
||||
ifdef HOST_UNIX
|
||||
libutil_SOURCES += $(wildcard $(d)/unix/*.cc)
|
||||
endif
|
||||
ifdef HOST_LINUX
|
||||
libutil_SOURCES += $(wildcard $(d)/linux/*.cc)
|
||||
endif
|
||||
|
||||
# Not just for this library itself, but also for downstream libraries using this library
|
||||
|
||||
INCLUDE_libutil := -I $(d)
|
||||
ifdef HOST_UNIX
|
||||
INCLUDE_libutil += -I $(d)/unix
|
||||
endif
|
||||
ifdef HOST_LINUX
|
||||
INCLUDE_libutil += -I $(d)/linux
|
||||
endif
|
||||
libutil_CXXFLAGS += $(INCLUDE_libutil)
|
||||
|
||||
libutil_LDFLAGS += $(THREAD_LDFLAGS) $(LIBCURL_LIBS) $(SODIUM_LIBS) $(OPENSSL_LIBS) $(LIBBROTLI_LIBS) $(LIBARCHIVE_LIBS) $(BOOST_LDFLAGS) -lboost_context
|
||||
|
||||
@@ -37,8 +37,9 @@ void Logger::warn(const std::string & msg)
|
||||
|
||||
void Logger::writeToStdout(std::string_view s)
|
||||
{
|
||||
writeFull(STDOUT_FILENO, s);
|
||||
writeFull(STDOUT_FILENO, "\n");
|
||||
Descriptor standard_out = getStandardOut();
|
||||
writeFull(standard_out, s);
|
||||
writeFull(standard_out, "\n");
|
||||
}
|
||||
|
||||
class SimpleLogger : public Logger
|
||||
|
||||
@@ -119,18 +119,18 @@ protected:
|
||||
*/
|
||||
struct FdSink : BufferedSink
|
||||
{
|
||||
int fd;
|
||||
Descriptor fd;
|
||||
size_t written = 0;
|
||||
|
||||
FdSink() : fd(-1) { }
|
||||
FdSink(int fd) : fd(fd) { }
|
||||
FdSink() : fd(INVALID_DESCRIPTOR) { }
|
||||
FdSink(Descriptor fd) : fd(fd) { }
|
||||
FdSink(FdSink&&) = default;
|
||||
|
||||
FdSink & operator=(FdSink && s)
|
||||
{
|
||||
flush();
|
||||
fd = s.fd;
|
||||
s.fd = -1;
|
||||
s.fd = INVALID_DESCRIPTOR;
|
||||
written = s.written;
|
||||
return *this;
|
||||
}
|
||||
@@ -151,18 +151,18 @@ private:
|
||||
*/
|
||||
struct FdSource : BufferedSource
|
||||
{
|
||||
int fd;
|
||||
Descriptor fd;
|
||||
size_t read = 0;
|
||||
BackedStringView endOfFileError{"unexpected end-of-file"};
|
||||
|
||||
FdSource() : fd(-1) { }
|
||||
FdSource(int fd) : fd(fd) { }
|
||||
FdSource() : fd(INVALID_DESCRIPTOR) { }
|
||||
FdSource(Descriptor fd) : fd(fd) { }
|
||||
FdSource(FdSource &&) = default;
|
||||
|
||||
FdSource & operator=(FdSource && s)
|
||||
{
|
||||
fd = s.fd;
|
||||
s.fd = -1;
|
||||
s.fd = INVALID_DESCRIPTOR;
|
||||
read = s.read;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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 "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;
|
||||
}
|
||||
|
||||
|
||||
Path getCacheDir()
|
||||
{
|
||||
auto cacheDir = getEnv("XDG_CACHE_HOME");
|
||||
@@ -113,9 +58,4 @@ std::string expandTilde(std::string_view path)
|
||||
return std::string(path);
|
||||
}
|
||||
|
||||
|
||||
bool isRootUser() {
|
||||
return getuid() == 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <array>
|
||||
#include <cctype>
|
||||
#include <iostream>
|
||||
#include <grp.h>
|
||||
#include <regex>
|
||||
|
||||
#include <sodium.h>
|
||||
|
||||
+12
-2
@@ -12,9 +12,19 @@ nix_SOURCES := \
|
||||
$(wildcard src/nix-daemon/*.cc) \
|
||||
$(wildcard src/nix-env/*.cc) \
|
||||
$(wildcard src/nix-instantiate/*.cc) \
|
||||
$(wildcard src/nix-store/*.cc) \
|
||||
$(wildcard src/nix-store/*.cc)
|
||||
|
||||
nix_CXXFLAGS += $(INCLUDE_libutil) $(INCLUDE_libstore) $(INCLUDE_libfetchers) $(INCLUDE_libexpr) -I src/libmain -I src/libcmd -I doc/manual
|
||||
ifdef HOST_UNIX
|
||||
nix_SOURCES += \
|
||||
$(wildcard $(d)/unix/*.cc)
|
||||
endif
|
||||
|
||||
INCLUDE_nix := -I $(d)
|
||||
ifdef HOST_UNIX
|
||||
INCLUDE_nix += -I $(d)/unix
|
||||
endif
|
||||
|
||||
nix_CXXFLAGS += $(INCLUDE_libutil) $(INCLUDE_libstore) $(INCLUDE_libfetchers) $(INCLUDE_libexpr) $(INCLUDE_libmain) -I src/libcmd -I doc/manual $(INCLUDE_nix)
|
||||
|
||||
nix_LIBS = libexpr libmain libfetchers libstore libutil libcmd
|
||||
|
||||
|
||||
+4
-1
@@ -2,7 +2,6 @@
|
||||
|
||||
#include "args/root.hh"
|
||||
#include "current-process.hh"
|
||||
#include "namespaces.hh"
|
||||
#include "command.hh"
|
||||
#include "common-args.hh"
|
||||
#include "eval.hh"
|
||||
@@ -27,6 +26,10 @@
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#if __linux__
|
||||
# include "namespaces.hh"
|
||||
#endif
|
||||
|
||||
extern std::string chrootHelperName;
|
||||
|
||||
void chrootHelper(int argc, char * * argv);
|
||||
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -6,7 +6,7 @@ resolve-system-dependencies_DIR := $(d)
|
||||
|
||||
resolve-system-dependencies_INSTALL_DIR := $(libexecdir)/nix
|
||||
|
||||
resolve-system-dependencies_CXXFLAGS += $(INCLUDE_libutil) $(INCLUDE_libstore) -I src/libmain
|
||||
resolve-system-dependencies_CXXFLAGS += $(INCLUDE_libutil) $(INCLUDE_libstore) $(INCLUDE_libmain)
|
||||
|
||||
resolve-system-dependencies_LIBS := libstore libmain libutil
|
||||
|
||||
|
||||
Reference in new issue
Block a user