1 #include "globals.hh"
2 #include "util.hh"
3 #include "archive.hh"
4 #include "args.hh"
5 
6 #include <algorithm>
7 #include <map>
8 #include <thread>
9 #include <dlfcn.h>
10 #include <sys/utsname.h>
11 
12 
13 namespace nix {
14 
15 
16 /* The default location of the daemon socket, relative to nixStateDir.
17    The socket is in a directory to allow you to control access to the
18    Nix daemon by setting the mode/ownership of the directory
19    appropriately.  (This wouldn't work on the socket itself since it
20    must be deleted and recreated on startup.) */
21 #define DEFAULT_SOCKET_PATH "/daemon-socket/socket"
22 
23 Settings settings;
24 
25 static GlobalConfig::Register r1(&settings);
26 
Settings()27 Settings::Settings()
28     : nixPrefix(NIX_PREFIX)
29     , nixStore(canonPath(getEnv("NIX_STORE_DIR", getEnv("NIX_STORE", NIX_STORE_DIR))))
30     , nixDataDir(canonPath(getEnv("NIX_DATA_DIR", NIX_DATA_DIR)))
31     , nixLogDir(canonPath(getEnv("NIX_LOG_DIR", NIX_LOG_DIR)))
32     , nixStateDir(canonPath(getEnv("NIX_STATE_DIR", NIX_STATE_DIR)))
33     , nixConfDir(canonPath(getEnv("NIX_CONF_DIR", NIX_CONF_DIR)))
34     , nixLibexecDir(canonPath(getEnv("NIX_LIBEXEC_DIR", NIX_LIBEXEC_DIR)))
35     , nixBinDir(canonPath(getEnv("NIX_BIN_DIR", NIX_BIN_DIR)))
36     , nixManDir(canonPath(NIX_MAN_DIR))
37     , nixDaemonSocketFile(canonPath(nixStateDir + DEFAULT_SOCKET_PATH))
38 {
39     buildUsersGroup = getuid() == 0 ? "nixbld" : "";
40     lockCPU = getEnv("NIX_AFFINITY_HACK", "1") == "1";
41 
42     caFile = getEnv("NIX_SSL_CERT_FILE", getEnv("SSL_CERT_FILE", ""));
43     if (caFile == "") {
44         for (auto & fn : {"/etc/ssl/certs/ca-certificates.crt", "/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt"})
45             if (pathExists(fn)) {
46                 caFile = fn;
47                 break;
48             }
49     }
50 
51     /* Backwards compatibility. */
52     auto s = getEnv("NIX_REMOTE_SYSTEMS");
53     if (s != "") {
54         Strings ss;
55         for (auto & p : tokenizeString<Strings>(s, ":"))
56             ss.push_back("@" + p);
57         builders = concatStringsSep(" ", ss);
58     }
59 
60 #if defined(__linux__) && defined(SANDBOX_SHELL)
61     sandboxPaths = tokenizeString<StringSet>("/bin/sh=" SANDBOX_SHELL);
62 #endif
63 
64 
65 /* chroot-like behavior from Apple's sandbox */
66 #if __APPLE__
67     sandboxPaths = tokenizeString<StringSet>("/System/Library/Frameworks /System/Library/PrivateFrameworks /bin/sh /bin/bash /private/tmp /private/var/tmp /usr/lib");
68     allowedImpureHostPrefixes = tokenizeString<StringSet>("/System/Library /usr/lib /dev /bin/sh");
69 #endif
70 }
71 
loadConfFile()72 void loadConfFile()
73 {
74     globalConfig.applyConfigFile(settings.nixConfDir + "/nix.conf");
75 
76     /* We only want to send overrides to the daemon, i.e. stuff from
77        ~/.nix/nix.conf or the command line. */
78     globalConfig.resetOverriden();
79 
80     auto dirs = getConfigDirs();
81     // Iterate over them in reverse so that the ones appearing first in the path take priority
82     for (auto dir = dirs.rbegin(); dir != dirs.rend(); dir++) {
83         globalConfig.applyConfigFile(*dir + "/nix/nix.conf");
84     }
85 }
86 
getDefaultCores()87 unsigned int Settings::getDefaultCores()
88 {
89     return std::max(1U, std::thread::hardware_concurrency());
90 }
91 
getDefaultSystemFeatures()92 StringSet Settings::getDefaultSystemFeatures()
93 {
94     /* For backwards compatibility, accept some "features" that are
95        used in Nixpkgs to route builds to certain machines but don't
96        actually require anything special on the machines. */
97     StringSet features{"nixos-test", "benchmark", "big-parallel"};
98 
99     #if __linux__
100     if (access("/dev/kvm", R_OK | W_OK) == 0)
101         features.insert("kvm");
102     #endif
103 
104     return features;
105 }
106 
isWSL1()107 bool Settings::isWSL1()
108 {
109     struct utsname utsbuf;
110     uname(&utsbuf);
111     // WSL1 uses -Microsoft suffix
112     // WSL2 uses -microsoft-standard suffix
113     return hasSuffix(utsbuf.release, "-Microsoft");
114 }
115 
116 const string nixVersion = PACKAGE_VERSION;
117 
set(const std::string & str)118 template<> void BaseSetting<SandboxMode>::set(const std::string & str)
119 {
120     if (str == "true") value = smEnabled;
121     else if (str == "relaxed") value = smRelaxed;
122     else if (str == "false") value = smDisabled;
123     else throw UsageError("option '%s' has invalid value '%s'", name, str);
124 }
125 
to_string()126 template<> std::string BaseSetting<SandboxMode>::to_string()
127 {
128     if (value == smEnabled) return "true";
129     else if (value == smRelaxed) return "relaxed";
130     else if (value == smDisabled) return "false";
131     else abort();
132 }
133 
toJSON(JSONPlaceholder & out)134 template<> void BaseSetting<SandboxMode>::toJSON(JSONPlaceholder & out)
135 {
136     AbstractSetting::toJSON(out);
137 }
138 
convertToArg(Args & args,const std::string & category)139 template<> void BaseSetting<SandboxMode>::convertToArg(Args & args, const std::string & category)
140 {
141     args.mkFlag()
142         .longName(name)
143         .description("Enable sandboxing.")
144         .handler([=](std::vector<std::string> ss) { override(smEnabled); })
145         .category(category);
146     args.mkFlag()
147         .longName("no-" + name)
148         .description("Disable sandboxing.")
149         .handler([=](std::vector<std::string> ss) { override(smDisabled); })
150         .category(category);
151     args.mkFlag()
152         .longName("relaxed-" + name)
153         .description("Enable sandboxing, but allow builds to disable it.")
154         .handler([=](std::vector<std::string> ss) { override(smRelaxed); })
155         .category(category);
156 }
157 
set(const std::string & str)158 void MaxBuildJobsSetting::set(const std::string & str)
159 {
160     if (str == "auto") value = std::max(1U, std::thread::hardware_concurrency());
161     else if (!string2Int(str, value))
162         throw UsageError("configuration setting '%s' should be 'auto' or an integer", name);
163 }
164 
165 
initPlugins()166 void initPlugins()
167 {
168     for (const auto & pluginFile : settings.pluginFiles.get()) {
169         Paths pluginFiles;
170         try {
171             auto ents = readDirectory(pluginFile);
172             for (const auto & ent : ents)
173                 pluginFiles.emplace_back(pluginFile + "/" + ent.name);
174         } catch (SysError & e) {
175             if (e.errNo != ENOTDIR)
176                 throw;
177             pluginFiles.emplace_back(pluginFile);
178         }
179         for (const auto & file : pluginFiles) {
180             /* handle is purposefully leaked as there may be state in the
181                DSO needed by the action of the plugin. */
182             void *handle =
183                 dlopen(file.c_str(), RTLD_LAZY | RTLD_LOCAL);
184             if (!handle)
185                 throw Error("could not dynamically open plugin file '%s': %s", file, dlerror());
186         }
187     }
188 
189     /* Since plugins can add settings, try to re-apply previously
190        unknown settings. */
191     globalConfig.reapplyUnknownSettings();
192     globalConfig.warnUnknownSettings();
193 }
194 
195 }
196