aboutsummaryrefslogtreecommitdiff
path: root/src/libutil
diff options
context:
space:
mode:
Diffstat (limited to 'src/libutil')
-rw-r--r--src/libutil/compression.cc6
-rw-r--r--src/libutil/compression.hh2
-rw-r--r--src/libutil/config.cc4
-rw-r--r--src/libutil/hash.cc4
-rw-r--r--src/libutil/hash.hh2
-rw-r--r--src/libutil/serialise.cc6
-rw-r--r--src/libutil/serialise.hh8
-rw-r--r--src/libutil/tests/config.cc48
-rw-r--r--src/libutil/util.cc47
-rw-r--r--src/libutil/util.hh20
10 files changed, 129 insertions, 18 deletions
diff --git a/src/libutil/compression.cc b/src/libutil/compression.cc
index 89180e7a7..ba0847cde 100644
--- a/src/libutil/compression.cc
+++ b/src/libutil/compression.cc
@@ -23,7 +23,7 @@ struct ChunkedCompressionSink : CompressionSink
{
uint8_t outbuf[32 * 1024];
- void write(std::string_view data) override
+ void writeUnbuffered(std::string_view data) override
{
const size_t CHUNK_SIZE = sizeof(outbuf) << 2;
while (!data.empty()) {
@@ -103,7 +103,7 @@ struct ArchiveCompressionSink : CompressionSink
throw Error(reason, archive_error_string(this->archive));
}
- void write(std::string_view data) override
+ void writeUnbuffered(std::string_view data) override
{
ssize_t result = archive_write_data(archive, data.data(), data.length());
if (result <= 0) check(result);
@@ -136,7 +136,7 @@ struct NoneSink : CompressionSink
warn("requested compression level '%d' not supported by compression method 'none'", level);
}
void finish() override { flush(); }
- void write(std::string_view data) override { nextSink(data); }
+ void writeUnbuffered(std::string_view data) override { nextSink(data); }
};
struct BrotliDecompressionSink : ChunkedCompressionSink
diff --git a/src/libutil/compression.hh b/src/libutil/compression.hh
index 3892831c2..4e53a7b3c 100644
--- a/src/libutil/compression.hh
+++ b/src/libutil/compression.hh
@@ -12,7 +12,7 @@ namespace nix {
struct CompressionSink : BufferedSink, FinishSink
{
using BufferedSink::operator ();
- using BufferedSink::write;
+ using BufferedSink::writeUnbuffered;
using FinishSink::finish;
};
diff --git a/src/libutil/config.cc b/src/libutil/config.cc
index 5ff8d91ba..a42f3a849 100644
--- a/src/libutil/config.cc
+++ b/src/libutil/config.cc
@@ -191,6 +191,10 @@ std::map<std::string, nlohmann::json> AbstractSetting::toJSONObject()
std::map<std::string, nlohmann::json> obj;
obj.emplace("description", description);
obj.emplace("aliases", aliases);
+ if (experimentalFeature)
+ obj.emplace("experimentalFeature", *experimentalFeature);
+ else
+ obj.emplace("experimentalFeature", nullptr);
return obj;
}
diff --git a/src/libutil/hash.cc b/src/libutil/hash.cc
index 5735e4715..2c36d9d94 100644
--- a/src/libutil/hash.cc
+++ b/src/libutil/hash.cc
@@ -1,6 +1,7 @@
#include <iostream>
#include <cstring>
+#include <openssl/crypto.h>
#include <openssl/md5.h>
#include <openssl/sha.h>
@@ -16,7 +17,6 @@
namespace nix {
-
static size_t regularHashSize(HashType type) {
switch (type) {
case htMD5: return md5HashSize;
@@ -343,7 +343,7 @@ HashSink::~HashSink()
delete ctx;
}
-void HashSink::write(std::string_view data)
+void HashSink::writeUnbuffered(std::string_view data)
{
bytes += data.size();
update(ht, *ctx, data);
diff --git a/src/libutil/hash.hh b/src/libutil/hash.hh
index be1fdba2a..ae3ee40f4 100644
--- a/src/libutil/hash.hh
+++ b/src/libutil/hash.hh
@@ -197,7 +197,7 @@ public:
HashSink(HashType ht);
HashSink(const HashSink & h);
~HashSink();
- void write(std::string_view data) override;
+ void writeUnbuffered(std::string_view data) override;
HashResult finish() override;
HashResult currentHash();
};
diff --git a/src/libutil/serialise.cc b/src/libutil/serialise.cc
index 6e53239f5..3d5121a19 100644
--- a/src/libutil/serialise.cc
+++ b/src/libutil/serialise.cc
@@ -20,7 +20,7 @@ void BufferedSink::operator () (std::string_view data)
buffer size. */
if (bufPos + data.size() >= bufSize) {
flush();
- write(data);
+ writeUnbuffered(data);
break;
}
/* Otherwise, copy the bytes to the buffer. Flush the buffer
@@ -38,7 +38,7 @@ void BufferedSink::flush()
if (bufPos == 0) return;
size_t n = bufPos;
bufPos = 0; // don't trigger the assert() in ~BufferedSink()
- write({buffer.get(), n});
+ writeUnbuffered({buffer.get(), n});
}
@@ -48,7 +48,7 @@ FdSink::~FdSink()
}
-void FdSink::write(std::string_view data)
+void FdSink::writeUnbuffered(std::string_view data)
{
written += data.size();
try {
diff --git a/src/libutil/serialise.hh b/src/libutil/serialise.hh
index ba6dbf619..333c254ea 100644
--- a/src/libutil/serialise.hh
+++ b/src/libutil/serialise.hh
@@ -53,7 +53,9 @@ struct BufferedSink : virtual Sink
void flush();
- virtual void write(std::string_view data) = 0;
+protected:
+
+ virtual void writeUnbuffered(std::string_view data) = 0;
};
@@ -133,7 +135,7 @@ struct FdSink : BufferedSink
~FdSink();
- void write(std::string_view data) override;
+ void writeUnbuffered(std::string_view data) override;
bool good() override;
@@ -520,7 +522,7 @@ struct FramedSink : nix::BufferedSink
}
}
- void write(std::string_view data) override
+ void writeUnbuffered(std::string_view data) override
{
/* Don't send more data if the remote has
encountered an error. */
diff --git a/src/libutil/tests/config.cc b/src/libutil/tests/config.cc
index 8be6730dd..f250e934e 100644
--- a/src/libutil/tests/config.cc
+++ b/src/libutil/tests/config.cc
@@ -156,12 +156,54 @@ namespace nix {
}
TEST(Config, toJSONOnNonEmptyConfig) {
+ using nlohmann::literals::operator "" _json;
Config config;
- std::map<std::string, Config::SettingInfo> settings;
- Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};
+ Setting<std::string> setting{
+ &config,
+ "",
+ "name-of-the-setting",
+ "description",
+ };
+ setting.assign("value");
+
+ ASSERT_EQ(config.toJSON(),
+ R"#({
+ "name-of-the-setting": {
+ "aliases": [],
+ "defaultValue": "",
+ "description": "description\n",
+ "documentDefault": true,
+ "value": "value",
+ "experimentalFeature": null
+ }
+ })#"_json);
+ }
+
+ TEST(Config, toJSONOnNonEmptyConfigWithExperimentalSetting) {
+ using nlohmann::literals::operator "" _json;
+ Config config;
+ Setting<std::string> setting{
+ &config,
+ "",
+ "name-of-the-setting",
+ "description",
+ {},
+ true,
+ Xp::Flakes,
+ };
setting.assign("value");
- ASSERT_EQ(config.toJSON().dump(), R"#({"name-of-the-setting":{"aliases":[],"defaultValue":"","description":"description\n","documentDefault":true,"value":"value"}})#");
+ ASSERT_EQ(config.toJSON(),
+ R"#({
+ "name-of-the-setting": {
+ "aliases": [],
+ "defaultValue": "",
+ "description": "description\n",
+ "documentDefault": true,
+ "value": "value",
+ "experimentalFeature": "flakes"
+ }
+ })#"_json);
}
TEST(Config, setSettingAlias) {
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 843a10eab..21d1c8dcd 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -47,6 +47,9 @@ extern char * * environ __attribute__((weak));
namespace nix {
+void initLibUtil() {
+}
+
std::optional<std::string> getEnv(const std::string & key)
{
char * value = getenv(key.c_str());
@@ -1744,14 +1747,40 @@ void triggerInterrupt()
}
static sigset_t savedSignalMask;
+static bool savedSignalMaskIsSet = false;
-void startSignalHandlerThread()
+void setChildSignalMask(sigset_t * sigs)
{
- updateWindowSize();
+ assert(sigs); // C style function, but think of sigs as a reference
+
+#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE
+ sigemptyset(&savedSignalMask);
+ // There's no "assign" or "copy" function, so we rely on (math) idempotence
+ // of the or operator: a or a = a.
+ sigorset(&savedSignalMask, sigs, sigs);
+#else
+ // Without sigorset, our best bet is to assume that sigset_t is a type that
+ // can be assigned directly, such as is the case for a sigset_t defined as
+ // an integer type.
+ savedSignalMask = *sigs;
+#endif
+
+ savedSignalMaskIsSet = true;
+}
+void saveSignalMask() {
if (sigprocmask(SIG_BLOCK, nullptr, &savedSignalMask))
throw SysError("querying signal mask");
+ savedSignalMaskIsSet = true;
+}
+
+void startSignalHandlerThread()
+{
+ updateWindowSize();
+
+ saveSignalMask();
+
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGINT);
@@ -1767,6 +1796,20 @@ void startSignalHandlerThread()
static void restoreSignals()
{
+ // If startSignalHandlerThread wasn't called, that means we're not running
+ // in a proper libmain process, but a process that presumably manages its
+ // own signal handlers. Such a process should call either
+ // - initNix(), to be a proper libmain process
+ // - startSignalHandlerThread(), to resemble libmain regarding signal
+ // handling only
+ // - saveSignalMask(), for processes that define their own signal handling
+ // thread
+ // TODO: Warn about this? Have a default signal mask? The latter depends on
+ // whether we should generally inherit signal masks from the caller.
+ // I don't know what the larger unix ecosystem expects from us here.
+ if (!savedSignalMaskIsSet)
+ return;
+
if (sigprocmask(SIG_SETMASK, &savedSignalMask, nullptr))
throw SysError("restoring signals");
}
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index 85ab77b1b..040fed68f 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -32,6 +32,7 @@ namespace nix {
struct Sink;
struct Source;
+void initLibUtil();
/**
* The system for which Nix is compiled.
@@ -445,6 +446,8 @@ void setStackSize(size_t stackSize);
/**
* Restore the original inherited Unix process context (such as signal
* masks, stack size).
+
+ * See startSignalHandlerThread(), saveSignalMask().
*/
void restoreProcessContext(bool restoreMounts = true);
@@ -814,9 +817,26 @@ class Callback;
/**
* Start a thread that handles various signals. Also block those signals
* on the current thread (and thus any threads created by it).
+ * Saves the signal mask before changing the mask to block those signals.
+ * See saveSignalMask().
*/
void startSignalHandlerThread();
+/**
+ * Saves the signal mask, which is the signal mask that nix will restore
+ * before creating child processes.
+ * See setChildSignalMask() to set an arbitrary signal mask instead of the
+ * current mask.
+ */
+void saveSignalMask();
+
+/**
+ * Sets the signal mask. Like saveSignalMask() but for a signal set that doesn't
+ * necessarily match the current thread's mask.
+ * See saveSignalMask() to set the saved mask to the current mask.
+ */
+void setChildSignalMask(sigset_t *sigs);
+
struct InterruptCallback
{
virtual ~InterruptCallback() { };