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