2006-09-05 00:06:23 +03:00
|
|
|
|
#include "globals.hh"
|
2016-02-09 22:07:48 +02:00
|
|
|
|
#include "shared.hh"
|
2006-11-30 19:43:04 +02:00
|
|
|
|
#include "store-api.hh"
|
2022-03-01 20:31:36 +02:00
|
|
|
|
#include "gc-store.hh"
|
2006-09-05 00:06:23 +03:00
|
|
|
|
#include "util.hh"
|
2020-06-05 19:20:11 +03:00
|
|
|
|
#include "loggers.hh"
|
2022-09-13 16:29:13 +03:00
|
|
|
|
#include "progress-bar.hh"
|
2006-09-05 00:06:23 +03:00
|
|
|
|
|
2016-02-22 15:49:15 +02:00
|
|
|
|
#include <algorithm>
|
2003-07-24 11:53:43 +03:00
|
|
|
|
#include <cctype>
|
2007-05-01 18:16:17 +03:00
|
|
|
|
#include <exception>
|
2016-02-22 15:49:15 +02:00
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <mutex>
|
2003-07-04 18:42:03 +03:00
|
|
|
|
|
2014-12-14 02:51:14 +02:00
|
|
|
|
#include <cstdlib>
|
2012-12-11 12:49:42 +02:00
|
|
|
|
#include <sys/time.h>
|
2004-03-27 19:58:04 +02:00
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#include <unistd.h>
|
2013-07-31 00:25:37 +03:00
|
|
|
|
#include <signal.h>
|
2021-10-15 10:33:49 +03:00
|
|
|
|
#ifdef __linux__
|
2021-10-15 00:43:07 +03:00
|
|
|
|
#include <features.h>
|
2021-10-15 10:33:49 +03:00
|
|
|
|
#endif
|
2021-10-15 00:43:07 +03:00
|
|
|
|
#ifdef __GLIBC__
|
2021-10-13 20:10:35 +03:00
|
|
|
|
#include <gnu/lib-names.h>
|
|
|
|
|
#include <nss.h>
|
|
|
|
|
#include <dlfcn.h>
|
2021-10-15 00:43:07 +03:00
|
|
|
|
#endif
|
2004-03-27 19:58:04 +02:00
|
|
|
|
|
2016-02-22 15:49:15 +02:00
|
|
|
|
#include <openssl/crypto.h>
|
2014-12-05 22:05:24 +02:00
|
|
|
|
|
2021-01-06 17:43:09 +02:00
|
|
|
|
#include <sodium.h>
|
|
|
|
|
|
2003-07-04 18:42:03 +03:00
|
|
|
|
|
2006-09-05 00:06:23 +03:00
|
|
|
|
namespace nix {
|
2003-07-04 18:42:03 +03:00
|
|
|
|
|
2022-10-28 13:19:37 +03:00
|
|
|
|
char * * savedArgv;
|
2003-07-04 18:42:03 +03:00
|
|
|
|
|
2013-12-20 14:19:10 +02:00
|
|
|
|
static bool gcWarning = true;
|
|
|
|
|
|
2005-02-01 14:36:25 +02:00
|
|
|
|
void printGCWarning()
|
|
|
|
|
{
|
2013-12-20 14:19:10 +02:00
|
|
|
|
if (!gcWarning) return;
|
2006-08-29 18:40:49 +03:00
|
|
|
|
static bool haveWarned = false;
|
2012-07-31 00:13:25 +03:00
|
|
|
|
warnOnce(haveWarned,
|
2017-07-30 14:27:57 +03:00
|
|
|
|
"you did not specify '--add-root'; "
|
2006-08-29 18:40:49 +03:00
|
|
|
|
"the result might be removed by the garbage collector");
|
2005-02-01 14:36:25 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2021-04-05 16:48:18 +03:00
|
|
|
|
void printMissing(ref<Store> store, const std::vector<DerivedPath> & paths, Verbosity lvl)
|
2008-08-04 16:44:46 +03:00
|
|
|
|
{
|
2020-07-30 14:10:49 +03:00
|
|
|
|
uint64_t downloadSize, narSize;
|
2019-12-05 20:11:09 +02:00
|
|
|
|
StorePathSet willBuild, willSubstitute, unknown;
|
Eliminate the "store" global variable
Also, move a few free-standing functions into StoreAPI and Derivation.
Also, introduce a non-nullable smart pointer, ref<T>, which is just a
wrapper around std::shared_ptr ensuring that the pointer is never
null. (For reference-counted values, this is better than passing a
"T&", because the latter doesn't maintain the refcount. Usually, the
caller will have a shared_ptr keeping the value alive, but that's not
always the case, e.g., when passing a reference to a std::thread via
std::bind.)
2016-02-04 15:28:26 +02:00
|
|
|
|
store->queryMissing(paths, willBuild, willSubstitute, unknown, downloadSize, narSize);
|
2017-08-31 18:57:04 +03:00
|
|
|
|
printMissing(store, willBuild, willSubstitute, unknown, downloadSize, narSize, lvl);
|
2012-11-20 01:27:25 +02:00
|
|
|
|
}
|
|
|
|
|
|
2008-08-04 16:44:46 +03:00
|
|
|
|
|
2019-12-05 20:11:09 +02:00
|
|
|
|
void printMissing(ref<Store> store, const StorePathSet & willBuild,
|
|
|
|
|
const StorePathSet & willSubstitute, const StorePathSet & unknown,
|
2020-07-30 14:10:49 +03:00
|
|
|
|
uint64_t downloadSize, uint64_t narSize, Verbosity lvl)
|
2012-11-20 01:27:25 +02:00
|
|
|
|
{
|
2008-08-04 16:44:46 +03:00
|
|
|
|
if (!willBuild.empty()) {
|
2020-06-17 08:41:25 +03:00
|
|
|
|
if (willBuild.size() == 1)
|
2020-06-18 20:54:16 +03:00
|
|
|
|
printMsg(lvl, "this derivation will be built:");
|
2020-06-17 08:41:25 +03:00
|
|
|
|
else
|
2020-06-18 20:54:16 +03:00
|
|
|
|
printMsg(lvl, "these %d derivations will be built:", willBuild.size());
|
2019-12-05 20:11:09 +02:00
|
|
|
|
auto sorted = store->topoSortPaths(willBuild);
|
2014-09-26 15:09:20 +03:00
|
|
|
|
reverse(sorted.begin(), sorted.end());
|
|
|
|
|
for (auto & i : sorted)
|
2020-06-18 20:54:16 +03:00
|
|
|
|
printMsg(lvl, " %s", store->printStorePath(i));
|
2008-08-04 16:44:46 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!willSubstitute.empty()) {
|
2020-06-17 08:41:25 +03:00
|
|
|
|
const float downloadSizeMiB = downloadSize / (1024.f * 1024.f);
|
|
|
|
|
const float narSizeMiB = narSize / (1024.f * 1024.f);
|
|
|
|
|
if (willSubstitute.size() == 1) {
|
2020-06-18 20:54:16 +03:00
|
|
|
|
printMsg(lvl, "this path will be fetched (%.2f MiB download, %.2f MiB unpacked):",
|
2020-06-17 08:41:25 +03:00
|
|
|
|
downloadSizeMiB,
|
2020-06-18 20:54:16 +03:00
|
|
|
|
narSizeMiB);
|
2020-06-17 08:41:25 +03:00
|
|
|
|
} else {
|
2020-06-18 20:54:16 +03:00
|
|
|
|
printMsg(lvl, "these %d paths will be fetched (%.2f MiB download, %.2f MiB unpacked):",
|
2020-06-17 08:41:25 +03:00
|
|
|
|
willSubstitute.size(),
|
|
|
|
|
downloadSizeMiB,
|
2020-06-18 20:54:16 +03:00
|
|
|
|
narSizeMiB);
|
2020-06-17 08:41:25 +03:00
|
|
|
|
}
|
Print the store paths to be fetched sorted by StorePath name() and not baseName
Presently when nix says something like:
```
these 486 paths will be fetched (511.54 MiB download, 6458.64 MiB unpacked):
...path1
...path2
...path3
...
...
...path486
```
It sorts path1, path2, path3, ..., path486 in lexicographic order of the
store path.
After this commit, nix will show path1, path2, path3, ..., path486 sorted by
StorePath name() (basically everything after the hash) rather than the store path.
This makes it easier to review what exactly is being downloaded at a glance,
especially when many paths need to be fetched.
2023-02-23 08:03:30 +02:00
|
|
|
|
std::vector<const StorePath *> willSubstituteSorted = {};
|
|
|
|
|
std::for_each(willSubstitute.begin(), willSubstitute.end(),
|
|
|
|
|
[&](const StorePath &p) { willSubstituteSorted.push_back(&p); });
|
|
|
|
|
std::sort(willSubstituteSorted.begin(), willSubstituteSorted.end(),
|
|
|
|
|
[](const StorePath *lhs, const StorePath *rhs) {
|
|
|
|
|
if (lhs->name() == rhs->name())
|
|
|
|
|
return lhs->to_string() < rhs->to_string();
|
|
|
|
|
else
|
|
|
|
|
return lhs->name() < rhs->name();
|
|
|
|
|
});
|
|
|
|
|
for (auto p : willSubstituteSorted)
|
|
|
|
|
printMsg(lvl, " %s", store->printStorePath(*p));
|
2008-08-04 16:44:46 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!unknown.empty()) {
|
2020-06-18 20:54:16 +03:00
|
|
|
|
printMsg(lvl, "don't know how to build these paths%s:",
|
|
|
|
|
(settings.readOnlyMode ? " (may be caused by read-only store access)" : ""));
|
2014-09-26 15:09:20 +03:00
|
|
|
|
for (auto & i : unknown)
|
2020-06-18 20:54:16 +03:00
|
|
|
|
printMsg(lvl, " %s", store->printStorePath(i));
|
2008-08-04 16:44:46 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2022-02-25 17:00:00 +02:00
|
|
|
|
std::string getArg(const std::string & opt,
|
2012-07-31 02:55:41 +03:00
|
|
|
|
Strings::iterator & i, const Strings::iterator & end)
|
|
|
|
|
{
|
|
|
|
|
++i;
|
2020-04-22 02:07:07 +03:00
|
|
|
|
if (i == end) throw UsageError("'%1%' requires an argument", opt);
|
2012-07-31 02:55:41 +03:00
|
|
|
|
return *i;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-08 21:11:43 +03:00
|
|
|
|
static std::once_flag dns_resolve_flag;
|
|
|
|
|
|
|
|
|
|
static void preloadNSS() {
|
|
|
|
|
/* builtin:fetchurl can trigger a DNS lookup, which with glibc can trigger a dynamic library load of
|
|
|
|
|
one of the glibc NSS libraries in a sandboxed child, which will fail unless the library's already
|
|
|
|
|
been loaded in the parent. So we force a lookup of an invalid domain to force the NSS machinery to
|
|
|
|
|
load its lookup libraries in the parent before any child gets a chance to. */
|
|
|
|
|
std::call_once(dns_resolve_flag, []() {
|
2021-10-15 00:43:07 +03:00
|
|
|
|
#ifdef __GLIBC__
|
2021-10-16 04:39:14 +03:00
|
|
|
|
/* On linux, glibc will run every lookup through the nss layer.
|
|
|
|
|
* That means every lookup goes, by default, through nscd, which acts as a local
|
|
|
|
|
* cache.
|
|
|
|
|
* Because we run builds in a sandbox, we also remove access to nscd otherwise
|
|
|
|
|
* lookups would leak into the sandbox.
|
|
|
|
|
*
|
|
|
|
|
* But now we have a new problem, we need to make sure the nss_dns backend that
|
|
|
|
|
* does the dns lookups when nscd is not available is loaded or available.
|
|
|
|
|
*
|
|
|
|
|
* We can't make it available without leaking nix's environment, so instead we'll
|
|
|
|
|
* load the backend, and configure nss so it does not try to run dns lookups
|
|
|
|
|
* through nscd.
|
|
|
|
|
*
|
|
|
|
|
* This is technically only used for builtins:fetch* functions so we only care
|
|
|
|
|
* about dns.
|
|
|
|
|
*
|
|
|
|
|
* All other platforms are unaffected.
|
|
|
|
|
*/
|
2021-12-13 20:37:30 +02:00
|
|
|
|
if (!dlopen(LIBNSS_DNS_SO, RTLD_NOW))
|
|
|
|
|
warn("unable to load nss_dns backend");
|
|
|
|
|
// FIXME: get hosts entry from nsswitch.conf.
|
|
|
|
|
__nss_configure_lookup("hosts", "files dns");
|
2021-10-15 00:43:07 +03:00
|
|
|
|
#endif
|
2021-09-08 21:11:43 +03:00
|
|
|
|
});
|
|
|
|
|
}
|
2013-07-31 00:25:37 +03:00
|
|
|
|
|
2017-01-25 14:37:02 +02:00
|
|
|
|
static void sigHandler(int signo) { }
|
|
|
|
|
|
|
|
|
|
|
2014-08-13 04:50:44 +03:00
|
|
|
|
void initNix()
|
2003-07-04 18:42:03 +03:00
|
|
|
|
{
|
2014-08-13 04:50:44 +03:00
|
|
|
|
/* Turn on buffering for cerr. */
|
|
|
|
|
#if HAVE_PUBSETBUF
|
|
|
|
|
static char buf[1024];
|
|
|
|
|
std::cerr.rdbuf()->pubsetbuf(buf, sizeof(buf));
|
|
|
|
|
#endif
|
|
|
|
|
|
2023-02-01 14:34:32 +02:00
|
|
|
|
initLibUtil();
|
2015-07-20 02:39:48 +03:00
|
|
|
|
|
2021-01-06 17:43:09 +02:00
|
|
|
|
if (sodium_init() == -1)
|
|
|
|
|
throw Error("could not initialise libsodium");
|
|
|
|
|
|
2017-01-17 19:21:02 +02:00
|
|
|
|
startSignalHandlerThread();
|
2004-01-15 22:23:55 +02:00
|
|
|
|
|
2017-02-01 14:00:21 +02:00
|
|
|
|
/* Reset SIGCHLD to its default. */
|
2017-01-17 19:21:02 +02:00
|
|
|
|
struct sigaction act;
|
|
|
|
|
sigemptyset(&act.sa_mask);
|
2010-01-12 14:22:38 +02:00
|
|
|
|
act.sa_flags = 0;
|
2022-09-04 00:06:33 +03:00
|
|
|
|
|
|
|
|
|
act.sa_handler = SIG_DFL;
|
2010-01-12 14:22:38 +02:00
|
|
|
|
if (sigaction(SIGCHLD, &act, 0))
|
|
|
|
|
throw SysError("resetting SIGCHLD");
|
|
|
|
|
|
2017-01-25 14:37:02 +02:00
|
|
|
|
/* Install a dummy SIGUSR1 handler for use with pthread_kill(). */
|
|
|
|
|
act.sa_handler = sigHandler;
|
|
|
|
|
if (sigaction(SIGUSR1, &act, 0)) throw SysError("handling SIGUSR1");
|
|
|
|
|
|
2019-06-06 03:18:47 +03:00
|
|
|
|
#if __APPLE__
|
|
|
|
|
/* HACK: on darwin, we need can’t use sigprocmask with SIGWINCH.
|
|
|
|
|
* Instead, add a dummy sigaction handler, and signalHandlerThread
|
|
|
|
|
* can handle the rest. */
|
2022-09-03 08:27:16 +03:00
|
|
|
|
act.sa_handler = sigHandler;
|
|
|
|
|
if (sigaction(SIGWINCH, &act, 0)) throw SysError("handling SIGWINCH");
|
|
|
|
|
|
2022-09-04 00:06:33 +03:00
|
|
|
|
/* Disable SA_RESTART for interrupts, so that system calls on this thread
|
|
|
|
|
* error with EINTR like they do on Linux.
|
|
|
|
|
* Most signals on BSD systems default to SA_RESTART on, but Nix
|
|
|
|
|
* expects EINTR from syscalls to properly exit. */
|
2022-09-03 08:27:16 +03:00
|
|
|
|
act.sa_handler = SIG_DFL;
|
|
|
|
|
if (sigaction(SIGINT, &act, 0)) throw SysError("handling SIGINT");
|
|
|
|
|
if (sigaction(SIGTERM, &act, 0)) throw SysError("handling SIGTERM");
|
|
|
|
|
if (sigaction(SIGHUP, &act, 0)) throw SysError("handling SIGHUP");
|
|
|
|
|
if (sigaction(SIGPIPE, &act, 0)) throw SysError("handling SIGPIPE");
|
2022-09-04 00:06:33 +03:00
|
|
|
|
if (sigaction(SIGQUIT, &act, 0)) throw SysError("handling SIGQUIT");
|
|
|
|
|
if (sigaction(SIGTRAP, &act, 0)) throw SysError("handling SIGTRAP");
|
2019-06-06 03:18:47 +03:00
|
|
|
|
#endif
|
2019-06-05 07:40:45 +03:00
|
|
|
|
|
2013-07-31 00:25:37 +03:00
|
|
|
|
/* Register a SIGSEGV handler to detect stack overflows. */
|
|
|
|
|
detectStackOverflow();
|
|
|
|
|
|
2004-09-09 17:16:02 +03:00
|
|
|
|
/* There is no privacy in the Nix system ;-) At least not for
|
|
|
|
|
now. In particular, store objects should be readable by
|
2012-10-04 00:30:45 +03:00
|
|
|
|
everybody. */
|
2004-09-09 17:16:02 +03:00
|
|
|
|
umask(0022);
|
|
|
|
|
|
2012-12-11 12:49:42 +02:00
|
|
|
|
/* Initialise the PRNG. */
|
|
|
|
|
struct timeval tv;
|
|
|
|
|
gettimeofday(&tv, 0);
|
|
|
|
|
srandom(tv.tv_usec);
|
2017-06-12 18:43:19 +03:00
|
|
|
|
|
|
|
|
|
/* On macOS, don't use the per-session TMPDIR (as set e.g. by
|
|
|
|
|
sshd). This breaks build users because they don't have access
|
|
|
|
|
to the TMPDIR, in particular in ‘nix-store --serve’. */
|
|
|
|
|
#if __APPLE__
|
2020-04-12 10:57:22 +03:00
|
|
|
|
if (hasPrefix(getEnv("TMPDIR").value_or("/tmp"), "/var/folders/"))
|
2017-06-12 18:43:19 +03:00
|
|
|
|
unsetenv("TMPDIR");
|
|
|
|
|
#endif
|
2021-09-08 21:11:43 +03:00
|
|
|
|
|
|
|
|
|
preloadNSS();
|
2022-12-19 15:06:07 +02:00
|
|
|
|
initLibStore();
|
2014-08-13 04:50:44 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-10-24 13:45:11 +03:00
|
|
|
|
LegacyArgs::LegacyArgs(const std::string & programName,
|
|
|
|
|
std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
|
|
|
|
|
: MixCommonArgs(programName), parseArg(parseArg)
|
2014-08-13 04:50:44 +03:00
|
|
|
|
{
|
2020-05-04 23:40:19 +03:00
|
|
|
|
addFlag({
|
|
|
|
|
.longName = "no-build-output",
|
|
|
|
|
.shortName = 'Q',
|
2021-01-13 15:18:04 +02:00
|
|
|
|
.description = "Do not show build output.",
|
2020-06-05 19:20:11 +03:00
|
|
|
|
.handler = {[&]() {setLogFormat(LogFormat::raw); }},
|
2020-05-04 23:40:19 +03:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
addFlag({
|
|
|
|
|
.longName = "keep-failed",
|
|
|
|
|
.shortName ='K',
|
2021-01-13 15:18:04 +02:00
|
|
|
|
.description = "Keep temporary directories of failed builds.",
|
2020-05-04 23:40:19 +03:00
|
|
|
|
.handler = {&(bool&) settings.keepFailed, true},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
addFlag({
|
|
|
|
|
.longName = "keep-going",
|
|
|
|
|
.shortName ='k',
|
2021-01-13 15:18:04 +02:00
|
|
|
|
.description = "Keep going after a build fails.",
|
2020-05-04 23:40:19 +03:00
|
|
|
|
.handler = {&(bool&) settings.keepGoing, true},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
addFlag({
|
|
|
|
|
.longName = "fallback",
|
2021-01-13 15:18:04 +02:00
|
|
|
|
.description = "Build from source if substitution fails.",
|
2020-05-04 23:40:19 +03:00
|
|
|
|
.handler = {&(bool&) settings.tryFallback, true},
|
|
|
|
|
});
|
2017-10-24 13:45:11 +03:00
|
|
|
|
|
|
|
|
|
auto intSettingAlias = [&](char shortName, const std::string & longName,
|
2021-01-08 12:40:36 +02:00
|
|
|
|
const std::string & description, const std::string & dest)
|
|
|
|
|
{
|
|
|
|
|
addFlag({
|
|
|
|
|
.longName = longName,
|
|
|
|
|
.shortName = shortName,
|
|
|
|
|
.description = description,
|
|
|
|
|
.labels = {"n"},
|
|
|
|
|
.handler = {[=](std::string s) {
|
2021-01-08 13:51:19 +02:00
|
|
|
|
auto n = string2IntWithUnitPrefix<uint64_t>(s);
|
|
|
|
|
settings.set(dest, std::to_string(n));
|
2021-01-08 12:40:36 +02:00
|
|
|
|
}}
|
2016-02-09 22:07:48 +02:00
|
|
|
|
});
|
2017-10-24 13:45:11 +03:00
|
|
|
|
};
|
2016-02-09 22:07:48 +02:00
|
|
|
|
|
2021-01-13 15:18:04 +02:00
|
|
|
|
intSettingAlias(0, "cores", "Maximum number of CPU cores to use inside a build.", "cores");
|
|
|
|
|
intSettingAlias(0, "max-silent-time", "Number of seconds of silence before a build is killed.", "max-silent-time");
|
|
|
|
|
intSettingAlias(0, "timeout", "Number of seconds before a build is killed.", "timeout");
|
2017-02-28 13:54:50 +02:00
|
|
|
|
|
2021-01-27 13:06:03 +02:00
|
|
|
|
addFlag({
|
|
|
|
|
.longName = "readonly-mode",
|
|
|
|
|
.description = "Do not write to the Nix store.",
|
|
|
|
|
.handler = {&settings.readOnlyMode, true},
|
|
|
|
|
});
|
2016-02-09 22:07:48 +02:00
|
|
|
|
|
2021-01-27 13:06:03 +02:00
|
|
|
|
addFlag({
|
|
|
|
|
.longName = "no-gc-warning",
|
|
|
|
|
.description = "Disable warnings about not using `--add-root`.",
|
2021-07-25 17:06:55 +03:00
|
|
|
|
.handler = {&gcWarning, false},
|
2021-01-27 13:06:03 +02:00
|
|
|
|
});
|
2017-10-24 16:41:11 +03:00
|
|
|
|
|
2020-05-04 23:40:19 +03:00
|
|
|
|
addFlag({
|
|
|
|
|
.longName = "store",
|
2021-01-13 15:18:04 +02:00
|
|
|
|
.description = "The URL of the Nix store to use.",
|
2020-05-04 23:40:19 +03:00
|
|
|
|
.labels = {"store-uri"},
|
|
|
|
|
.handler = {&(std::string&) settings.storeUri},
|
|
|
|
|
});
|
2017-10-24 13:45:11 +03:00
|
|
|
|
}
|
2016-02-09 22:07:48 +02:00
|
|
|
|
|
|
|
|
|
|
2017-10-24 13:45:11 +03:00
|
|
|
|
bool LegacyArgs::processFlag(Strings::iterator & pos, Strings::iterator end)
|
|
|
|
|
{
|
|
|
|
|
if (MixCommonArgs::processFlag(pos, end)) return true;
|
|
|
|
|
bool res = parseArg(pos, end);
|
|
|
|
|
if (res) ++pos;
|
|
|
|
|
return res;
|
|
|
|
|
}
|
2016-02-09 22:07:48 +02:00
|
|
|
|
|
2003-12-01 17:55:05 +02:00
|
|
|
|
|
2017-10-24 13:45:11 +03:00
|
|
|
|
bool LegacyArgs::processArgs(const Strings & args, bool finish)
|
|
|
|
|
{
|
|
|
|
|
if (args.empty()) return true;
|
|
|
|
|
assert(args.size() == 1);
|
|
|
|
|
Strings ss(args);
|
|
|
|
|
auto pos = ss.begin();
|
|
|
|
|
if (!parseArg(pos, ss.end()))
|
2020-04-22 02:07:07 +03:00
|
|
|
|
throw UsageError("unexpected argument '%1%'", args.front());
|
2017-10-24 13:45:11 +03:00
|
|
|
|
return true;
|
|
|
|
|
}
|
2016-02-09 22:07:48 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void parseCmdLine(int argc, char * * argv,
|
|
|
|
|
std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
|
|
|
|
|
{
|
2019-12-05 20:11:09 +02:00
|
|
|
|
parseCmdLine(std::string(baseNameOf(argv[0])), argvToStrings(argc, argv), parseArg);
|
2017-07-25 16:09:06 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2022-02-25 17:00:00 +02:00
|
|
|
|
void parseCmdLine(const std::string & programName, const Strings & args,
|
2017-07-25 16:09:06 +03:00
|
|
|
|
std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
|
|
|
|
|
{
|
|
|
|
|
LegacyArgs(programName, parseArg).parseCmdline(args);
|
2014-08-13 04:50:44 +03:00
|
|
|
|
}
|
2012-07-31 02:55:41 +03:00
|
|
|
|
|
2006-03-01 18:36:35 +02:00
|
|
|
|
|
2022-02-25 17:00:00 +02:00
|
|
|
|
void printVersion(const std::string & programName)
|
2014-08-13 04:50:44 +03:00
|
|
|
|
{
|
2023-03-02 16:44:19 +02:00
|
|
|
|
std::cout << fmt("%1% (Nix) %2%", programName, nixVersion) << std::endl;
|
2015-07-23 15:19:49 +03:00
|
|
|
|
if (verbosity > lvlInfo) {
|
|
|
|
|
Strings cfg;
|
|
|
|
|
#if HAVE_BOEHMGC
|
|
|
|
|
cfg.push_back("gc");
|
|
|
|
|
#endif
|
|
|
|
|
cfg.push_back("signed-caches");
|
2020-07-24 12:34:01 +03:00
|
|
|
|
std::cout << "System type: " << settings.thisSystem << "\n";
|
|
|
|
|
std::cout << "Additional system types: " << concatStringsSep(", ", settings.extraPlatforms.get()) << "\n";
|
2015-07-23 15:19:49 +03:00
|
|
|
|
std::cout << "Features: " << concatStringsSep(", ", cfg) << "\n";
|
2020-03-30 16:31:14 +03:00
|
|
|
|
std::cout << "System configuration file: " << settings.nixConfDir + "/nix.conf" << "\n";
|
|
|
|
|
std::cout << "User configuration files: " <<
|
|
|
|
|
concatStringsSep(":", settings.nixUserConfFiles)
|
|
|
|
|
<< "\n";
|
2015-07-23 15:19:49 +03:00
|
|
|
|
std::cout << "Store directory: " << settings.nixStore << "\n";
|
|
|
|
|
std::cout << "State directory: " << settings.nixStateDir << "\n";
|
2023-01-03 18:30:49 +02:00
|
|
|
|
std::cout << "Data directory: " << settings.nixDataDir << "\n";
|
2015-07-23 15:19:49 +03:00
|
|
|
|
}
|
2014-08-13 04:50:44 +03:00
|
|
|
|
throw Exit();
|
2003-07-04 18:42:03 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2022-02-25 17:00:00 +02:00
|
|
|
|
void showManPage(const std::string & name)
|
2012-10-03 23:37:06 +03:00
|
|
|
|
{
|
2021-04-07 14:10:02 +03:00
|
|
|
|
restoreProcessContext();
|
2018-02-15 00:05:55 +02:00
|
|
|
|
setenv("MANPATH", settings.nixManDir.c_str(), 1);
|
2018-03-22 00:17:37 +02:00
|
|
|
|
execlp("man", "man", name.c_str(), nullptr);
|
2020-04-22 02:07:07 +03:00
|
|
|
|
throw SysError("command 'man %1%' failed", name.c_str());
|
2012-10-03 23:37:06 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2022-02-25 17:00:00 +02:00
|
|
|
|
int handleExceptions(const std::string & programName, std::function<void()> fun)
|
2003-07-04 18:42:03 +03:00
|
|
|
|
{
|
2017-01-25 14:37:02 +02:00
|
|
|
|
ReceiveInterrupts receiveInterrupts; // FIXME: need better place for this
|
|
|
|
|
|
2020-06-15 19:20:05 +03:00
|
|
|
|
ErrorInfo::programName = baseNameOf(programName);
|
2020-04-24 23:57:51 +03:00
|
|
|
|
|
2022-02-25 17:00:00 +02:00
|
|
|
|
std::string error = ANSI_RED "error:" ANSI_NORMAL " ";
|
2003-07-04 18:42:03 +03:00
|
|
|
|
try {
|
2004-05-11 21:05:44 +03:00
|
|
|
|
try {
|
2014-08-13 04:50:44 +03:00
|
|
|
|
fun();
|
2004-05-11 21:05:44 +03:00
|
|
|
|
} catch (...) {
|
|
|
|
|
/* Subtle: we have to make sure that any `interrupted'
|
|
|
|
|
condition is discharged before we reach printMsg()
|
|
|
|
|
below, since otherwise it will throw an (uncaught)
|
|
|
|
|
exception. */
|
2017-04-21 17:28:10 +03:00
|
|
|
|
setInterruptThrown();
|
2004-05-11 21:05:44 +03:00
|
|
|
|
throw;
|
|
|
|
|
}
|
2014-08-13 04:50:44 +03:00
|
|
|
|
} catch (Exit & e) {
|
|
|
|
|
return e.status;
|
2003-07-04 18:42:03 +03:00
|
|
|
|
} catch (UsageError & e) {
|
2020-05-04 22:46:15 +03:00
|
|
|
|
logError(e.info());
|
|
|
|
|
printError("Try '%1% --help' for more information.", programName);
|
2003-07-04 18:42:03 +03:00
|
|
|
|
return 1;
|
2007-08-12 03:29:28 +03:00
|
|
|
|
} catch (BaseError & e) {
|
2020-05-04 22:46:15 +03:00
|
|
|
|
logError(e.info());
|
2010-12-13 18:53:23 +02:00
|
|
|
|
return e.status;
|
2013-10-02 15:34:36 +03:00
|
|
|
|
} catch (std::bad_alloc & e) {
|
2020-05-04 22:46:15 +03:00
|
|
|
|
printError(error + "out of memory");
|
2013-10-02 15:34:36 +03:00
|
|
|
|
return 1;
|
2006-09-05 00:06:23 +03:00
|
|
|
|
} catch (std::exception & e) {
|
2020-05-04 22:46:15 +03:00
|
|
|
|
printError(error + e.what());
|
2003-07-04 18:42:03 +03:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-13 04:50:44 +03:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-08-20 16:12:58 +03:00
|
|
|
|
RunPager::RunPager()
|
|
|
|
|
{
|
2014-12-10 19:16:05 +02:00
|
|
|
|
if (!isatty(STDOUT_FILENO)) return;
|
2015-01-02 16:26:56 +02:00
|
|
|
|
char * pager = getenv("NIX_PAGER");
|
|
|
|
|
if (!pager) pager = getenv("PAGER");
|
2022-02-25 17:00:00 +02:00
|
|
|
|
if (pager && ((std::string) pager == "" || (std::string) pager == "cat")) return;
|
2014-08-20 16:12:58 +03:00
|
|
|
|
|
2022-09-13 16:29:13 +03:00
|
|
|
|
stopProgressBar();
|
|
|
|
|
|
2014-08-20 16:12:58 +03:00
|
|
|
|
Pipe toPager;
|
|
|
|
|
toPager.create();
|
|
|
|
|
|
2014-12-10 14:48:50 +02:00
|
|
|
|
pid = startProcess([&]() {
|
2016-07-11 22:44:44 +03:00
|
|
|
|
if (dup2(toPager.readSide.get(), STDIN_FILENO) == -1)
|
2014-12-10 14:48:50 +02:00
|
|
|
|
throw SysError("dupping stdin");
|
|
|
|
|
if (!getenv("LESS"))
|
|
|
|
|
setenv("LESS", "FRSXMK", 1);
|
2021-04-07 14:10:02 +03:00
|
|
|
|
restoreProcessContext();
|
2015-01-02 16:26:56 +02:00
|
|
|
|
if (pager)
|
2018-03-22 00:17:37 +02:00
|
|
|
|
execl("/bin/sh", "sh", "-c", pager, nullptr);
|
|
|
|
|
execlp("pager", "pager", nullptr);
|
|
|
|
|
execlp("less", "less", nullptr);
|
|
|
|
|
execlp("more", "more", nullptr);
|
2020-04-22 02:07:07 +03:00
|
|
|
|
throw SysError("executing '%1%'", pager);
|
2014-12-10 14:48:50 +02:00
|
|
|
|
});
|
2014-08-20 16:12:58 +03:00
|
|
|
|
|
2017-02-01 14:00:21 +02:00
|
|
|
|
pid.setKillSignal(SIGINT);
|
2021-11-26 16:38:46 +02:00
|
|
|
|
stdout = fcntl(STDOUT_FILENO, F_DUPFD_CLOEXEC, 0);
|
2016-07-11 22:44:44 +03:00
|
|
|
|
if (dup2(toPager.writeSide.get(), STDOUT_FILENO) == -1)
|
2014-08-20 16:12:58 +03:00
|
|
|
|
throw SysError("dupping stdout");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RunPager::~RunPager()
|
|
|
|
|
{
|
2014-12-12 15:05:23 +02:00
|
|
|
|
try {
|
|
|
|
|
if (pid != -1) {
|
|
|
|
|
std::cout.flush();
|
2021-11-26 16:38:46 +02:00
|
|
|
|
dup2(stdout, STDOUT_FILENO);
|
2017-01-19 17:58:39 +02:00
|
|
|
|
pid.wait();
|
2014-12-12 15:05:23 +02:00
|
|
|
|
}
|
|
|
|
|
} catch (...) {
|
2017-03-16 11:52:28 +02:00
|
|
|
|
ignoreException();
|
2014-08-20 16:12:58 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-05-21 16:21:38 +03:00
|
|
|
|
PrintFreed::~PrintFreed()
|
|
|
|
|
{
|
|
|
|
|
if (show)
|
2020-10-06 11:40:49 +03:00
|
|
|
|
std::cout << fmt("%d store paths deleted, %s freed\n",
|
|
|
|
|
results.paths.size(),
|
|
|
|
|
showBytes(results.bytesFreed));
|
2015-05-21 16:21:38 +03:00
|
|
|
|
}
|
|
|
|
|
|
2017-11-07 22:42:34 +02:00
|
|
|
|
Exit::~Exit() { }
|
2015-05-21 16:21:38 +03:00
|
|
|
|
|
2003-07-04 18:42:03 +03:00
|
|
|
|
}
|