about summary refs log tree commit diff
path: root/third_party/nix/src/nix/main.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/nix/src/nix/main.cc')
-rw-r--r--third_party/nix/src/nix/main.cc185
1 files changed, 185 insertions, 0 deletions
diff --git a/third_party/nix/src/nix/main.cc b/third_party/nix/src/nix/main.cc
new file mode 100644
index 000000000000..08390fd24b9f
--- /dev/null
+++ b/third_party/nix/src/nix/main.cc
@@ -0,0 +1,185 @@
+#include <algorithm>
+
+#include <glog/logging.h>
+#include <ifaddrs.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include "libexpr/eval.hh"
+#include "libmain/common-args.hh"
+#include "libmain/shared.hh"
+#include "libstore/download.hh"
+#include "libstore/globals.hh"
+#include "libstore/store-api.hh"
+#include "libutil/finally.hh"
+#include "nix/command.hh"
+#include "nix/legacy.hh"
+
+extern std::string chrootHelperName;
+
+void chrootHelper(int argc, char** argv);
+
+namespace nix {
+
+/* Check if we have a non-loopback/link-local network interface. */
+static bool haveInternet() {
+  struct ifaddrs* addrs;
+
+  if (getifaddrs(&addrs) != 0) {
+    return true;
+  }
+
+  Finally free([&]() { freeifaddrs(addrs); });
+
+  for (auto i = addrs; i != nullptr; i = i->ifa_next) {
+    if (i->ifa_addr == nullptr) {
+      continue;
+    }
+    if (i->ifa_addr->sa_family == AF_INET) {
+      if (ntohl(
+              (reinterpret_cast<sockaddr_in*>(i->ifa_addr))->sin_addr.s_addr) !=
+          INADDR_LOOPBACK) {
+        return true;
+      }
+    } else if (i->ifa_addr->sa_family == AF_INET6) {
+      if (!IN6_IS_ADDR_LOOPBACK(&((sockaddr_in6*)i->ifa_addr)->sin6_addr) &&
+          !IN6_IS_ADDR_LINKLOCAL(&((sockaddr_in6*)i->ifa_addr)->sin6_addr)) {
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+std::string programPath;
+
+struct NixArgs : virtual MultiCommand, virtual MixCommonArgs {
+  bool printBuildLogs = false;
+  bool useNet = true;
+
+  NixArgs() : MultiCommand(*RegisterCommand::commands), MixCommonArgs("nix") {
+    mkFlag()
+        .longName("help")
+        .description("show usage information")
+        .handler([&]() { showHelpAndExit(); });
+
+    mkFlag()
+        .longName("help-config")
+        .description("show configuration options")
+        .handler([&]() {
+          std::cout << "The following configuration options are available:\n\n";
+          Table2 tbl;
+          std::map<std::string, Config::SettingInfo> settings;
+          globalConfig.getSettings(settings);
+          for (const auto& s : settings) {
+            tbl.emplace_back(s.first, s.second.description);
+          }
+          printTable(std::cout, tbl);
+          throw Exit();
+        });
+
+    mkFlag()
+        .longName("print-build-logs")
+        .shortName('L')
+        .description("print full build logs on stderr")
+        .set(&printBuildLogs, true);
+
+    mkFlag()
+        .longName("version")
+        .description("show version information")
+        .handler([&]() { printVersion(programName); });
+
+    mkFlag()
+        .longName("no-net")
+        .description(
+            "disable substituters and consider all previously downloaded files "
+            "up-to-date")
+        .handler([&]() { useNet = false; });
+  }
+
+  void printFlags(std::ostream& out) override {
+    Args::printFlags(out);
+    std::cout << "\n"
+                 "In addition, most configuration settings can be overriden "
+                 "using '--<name> <value>'.\n"
+                 "Boolean settings can be overriden using '--<name>' or "
+                 "'--no-<name>'. See 'nix\n"
+                 "--help-config' for a list of configuration settings.\n";
+  }
+
+  void showHelpAndExit() {
+    printHelp(programName, std::cout);
+    std::cout
+        << "\nNote: this program is EXPERIMENTAL and subject to change.\n";
+    throw Exit();
+  }
+};
+
+void mainWrapped(int argc, char** argv) {
+  /* The chroot helper needs to be run before any threads have been
+     started. */
+  if (argc > 0 && argv[0] == chrootHelperName) {
+    chrootHelper(argc, argv);
+    return;
+  }
+
+  initNix();
+
+  programPath = argv[0];
+  std::string programName = baseNameOf(programPath);
+
+  {
+    auto legacy = (*RegisterLegacyCommand::commands)[programName];
+    if (legacy) {
+      return legacy(argc, argv);
+    }
+  }
+
+  settings.verboseBuild = false;
+
+  NixArgs args;
+
+  args.parseCmdline(argvToStrings(argc, argv));
+
+  if (!args.command) {
+    args.showHelpAndExit();
+  }
+
+  if (args.useNet && !haveInternet()) {
+    LOG(WARNING) << "you don't have Internet access; "
+                 << "disabling some network-dependent features";
+    args.useNet = false;
+  }
+
+  if (!args.useNet) {
+    // FIXME: should check for command line overrides only.
+    if (!settings.useSubstitutes.overriden) {
+      settings.useSubstitutes = false;
+    }
+    if (!settings.tarballTtl.overriden) {
+      settings.tarballTtl = std::numeric_limits<unsigned int>::max();
+    }
+    if (!downloadSettings.tries.overriden) {
+      downloadSettings.tries = 0;
+    }
+    if (!downloadSettings.connectTimeout.overriden) {
+      downloadSettings.connectTimeout = 1;
+    }
+  }
+
+  args.command->prepare();
+  args.command->run();
+}
+
+}  // namespace nix
+
+int main(int argc, char* argv[]) {
+  FLAGS_logtostderr = true;
+  google::InitGoogleLogging(argv[0]);
+
+  return nix::handleExceptions(argv[0],
+                               [&]() { nix::mainWrapped(argc, argv); });
+}