gnu: weechat: Update to 1.7.
[jackhill/guix/guix.git] / nix / nix-daemon / guix-daemon.cc
1 /* GNU Guix --- Functional package management for GNU
2 Copyright (C) 2012, 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
3
4 This file is part of GNU Guix.
5
6 GNU Guix is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or (at
9 your option) any later version.
10
11 GNU Guix is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. */
18
19 #include <config.h>
20
21 #include <types.hh>
22 #include "shared.hh"
23 #include <globals.hh>
24 #include <util.hh>
25
26 #include <gcrypt.h>
27
28 #include <stdlib.h>
29 #include <argp.h>
30 #include <unistd.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <strings.h>
34 #include <exception>
35
36 #include <libintl.h>
37 #include <locale.h>
38
39 /* Variables used by `nix-daemon.cc'. */
40 volatile ::sig_atomic_t blockInt;
41 char **argvSaved;
42
43 using namespace nix;
44
45 /* Entry point in `nix-daemon.cc'. */
46 extern void run (Strings args);
47
48 \f
49 /* Command-line options. */
50
51 #define n_(str) str
52 #define _(str) gettext (str)
53 static const char guix_textdomain[] = "guix";
54
55
56 const char *argp_program_version =
57 "guix-daemon (" PACKAGE_NAME ") " PACKAGE_VERSION;
58 const char *argp_program_bug_address = PACKAGE_BUGREPORT;
59
60 static char doc[] =
61 n_("guix-daemon -- perform derivation builds and store accesses")
62 "\v\n"
63 n_("This program is a daemon meant to run in the background. It serves \
64 requests sent over a Unix-domain socket. It accesses the store, and \
65 builds derivations on behalf of its clients.");
66
67 #define GUIX_OPT_SYSTEM 1
68 #define GUIX_OPT_DISABLE_CHROOT 2
69 #define GUIX_OPT_BUILD_USERS_GROUP 3
70 #define GUIX_OPT_CACHE_FAILURES 4
71 #define GUIX_OPT_LOSE_LOGS 5
72 #define GUIX_OPT_DISABLE_LOG_COMPRESSION 6
73 #define GUIX_OPT_DISABLE_DEDUPLICATION 7
74 #define GUIX_OPT_IMPERSONATE_LINUX_26 8
75 #define GUIX_OPT_DEBUG 9
76 #define GUIX_OPT_CHROOT_DIR 10
77 #define GUIX_OPT_LISTEN 11
78 #define GUIX_OPT_NO_SUBSTITUTES 12
79 #define GUIX_OPT_SUBSTITUTE_URLS 13
80 #define GUIX_OPT_NO_BUILD_HOOK 14
81 #define GUIX_OPT_GC_KEEP_OUTPUTS 15
82 #define GUIX_OPT_GC_KEEP_DERIVATIONS 16
83 #define GUIX_OPT_BUILD_ROUNDS 17
84
85 static const struct argp_option options[] =
86 {
87 { "system", GUIX_OPT_SYSTEM, n_("SYSTEM"), 0,
88 n_("assume SYSTEM as the current system type") },
89 { "cores", 'c', n_("N"), 0,
90 n_("use N CPU cores to build each derivation; 0 means as many as available")
91 },
92 { "max-jobs", 'M', n_("N"), 0,
93 n_("allow at most N build jobs") },
94 { "disable-chroot", GUIX_OPT_DISABLE_CHROOT, 0, 0,
95 n_("disable chroot builds") },
96 { "chroot-directory", GUIX_OPT_CHROOT_DIR, n_("DIR"), 0,
97 n_("add DIR to the build chroot") },
98 { "build-users-group", GUIX_OPT_BUILD_USERS_GROUP, n_("GROUP"), 0,
99 n_("perform builds as a user of GROUP") },
100 { "no-substitutes", GUIX_OPT_NO_SUBSTITUTES, 0, 0,
101 n_("do not use substitutes") },
102 { "substitute-urls", GUIX_OPT_SUBSTITUTE_URLS, n_("URLS"), 0,
103 n_("use URLS as the default list of substitute providers") },
104 { "no-build-hook", GUIX_OPT_NO_BUILD_HOOK, 0, 0,
105 n_("do not use the 'build hook'") },
106 { "cache-failures", GUIX_OPT_CACHE_FAILURES, 0, 0,
107 n_("cache build failures") },
108 { "rounds", GUIX_OPT_BUILD_ROUNDS, "N", 0,
109 n_("build each derivation N times in a row") },
110 { "lose-logs", GUIX_OPT_LOSE_LOGS, 0, 0,
111 n_("do not keep build logs") },
112 { "disable-log-compression", GUIX_OPT_DISABLE_LOG_COMPRESSION, 0, 0,
113 n_("disable compression of the build logs") },
114
115 /* '--disable-deduplication' was known as '--disable-store-optimization'
116 up to Guix 0.7 included, so keep the alias around. */
117 { "disable-deduplication", GUIX_OPT_DISABLE_DEDUPLICATION, 0, 0,
118 n_("disable automatic file \"deduplication\" in the store") },
119 { "disable-store-optimization", GUIX_OPT_DISABLE_DEDUPLICATION, 0,
120 OPTION_ALIAS | OPTION_HIDDEN, NULL },
121
122 { "impersonate-linux-2.6", GUIX_OPT_IMPERSONATE_LINUX_26, 0,
123 #ifdef HAVE_SYS_PERSONALITY_H
124 0,
125 #else
126 OPTION_HIDDEN,
127 #endif
128 n_("impersonate Linux 2.6")
129 },
130 { "gc-keep-outputs", GUIX_OPT_GC_KEEP_OUTPUTS,
131 "yes/no", OPTION_ARG_OPTIONAL,
132 n_("tell whether the GC must keep outputs of live derivations") },
133 { "gc-keep-derivations", GUIX_OPT_GC_KEEP_DERIVATIONS,
134 "yes/no", OPTION_ARG_OPTIONAL,
135 n_("tell whether the GC must keep derivations corresponding \
136 to live outputs") },
137
138 { "listen", GUIX_OPT_LISTEN, n_("SOCKET"), 0,
139 n_("listen for connections on SOCKET") },
140 { "debug", GUIX_OPT_DEBUG, 0, 0,
141 n_("produce debugging output") },
142 { 0, 0, 0, 0, 0 }
143 };
144
145
146 /* Convert ARG to a Boolean value, or throw an error if it does not denote a
147 Boolean. */
148 static bool
149 string_to_bool (const char *arg, bool dflt = true)
150 {
151 if (arg == NULL)
152 return dflt;
153 else if (strcasecmp (arg, "yes") == 0)
154 return true;
155 else if (strcasecmp (arg, "no") == 0)
156 return false;
157 else
158 throw nix::Error (format ("'%1%': invalid Boolean value") % arg);
159 }
160
161 /* Parse a single option. */
162 static error_t
163 parse_opt (int key, char *arg, struct argp_state *state)
164 {
165 switch (key)
166 {
167 case GUIX_OPT_DISABLE_CHROOT:
168 settings.useChroot = false;
169 break;
170 case GUIX_OPT_CHROOT_DIR:
171 {
172 std::string chroot_dirs;
173
174 chroot_dirs = settings.get ("build-extra-chroot-dirs",
175 (std::string) "");
176 if (chroot_dirs == "")
177 chroot_dirs = arg;
178 else
179 chroot_dirs = chroot_dirs + " " + arg;
180 settings.set("build-extra-chroot-dirs", chroot_dirs);
181 break;
182 }
183 case GUIX_OPT_DISABLE_LOG_COMPRESSION:
184 settings.compressLog = false;
185 break;
186 case GUIX_OPT_BUILD_USERS_GROUP:
187 settings.buildUsersGroup = arg;
188 break;
189 case GUIX_OPT_DISABLE_DEDUPLICATION:
190 settings.autoOptimiseStore = false;
191 break;
192 case GUIX_OPT_CACHE_FAILURES:
193 settings.cacheFailure = true;
194 break;
195 case GUIX_OPT_BUILD_ROUNDS:
196 {
197 char *end;
198 unsigned long n = strtoul (arg, &end, 10);
199 if (end != arg + strlen (arg))
200 {
201 fprintf (stderr, _("error: %s: invalid number of rounds\n"), arg);
202 exit (EXIT_FAILURE);
203 }
204 settings.set ("build-repeat", std::to_string (std::max (0UL, n - 1)));
205 break;
206 }
207 case GUIX_OPT_IMPERSONATE_LINUX_26:
208 settings.impersonateLinux26 = true;
209 break;
210 case GUIX_OPT_LOSE_LOGS:
211 settings.keepLog = false;
212 break;
213 case GUIX_OPT_LISTEN:
214 try
215 {
216 settings.nixDaemonSocketFile = canonPath (arg);
217 }
218 catch (std::exception &e)
219 {
220 fprintf (stderr, _("error: %s\n"), e.what ());
221 exit (EXIT_FAILURE);
222 }
223 break;
224 case GUIX_OPT_SUBSTITUTE_URLS:
225 settings.set ("substitute-urls", arg);
226 break;
227 case GUIX_OPT_NO_SUBSTITUTES:
228 settings.set ("build-use-substitutes", "false");
229 break;
230 case GUIX_OPT_NO_BUILD_HOOK:
231 settings.useBuildHook = false;
232 break;
233 case GUIX_OPT_DEBUG:
234 verbosity = lvlDebug;
235 break;
236 case GUIX_OPT_GC_KEEP_OUTPUTS:
237 settings.gcKeepOutputs = string_to_bool (arg);
238 break;
239 case GUIX_OPT_GC_KEEP_DERIVATIONS:
240 settings.gcKeepDerivations = string_to_bool (arg);
241 break;
242 case 'c':
243 settings.set ("build-cores", arg);
244 break;
245 case 'M':
246 settings.set ("build-max-jobs", arg);
247 break;
248 case GUIX_OPT_SYSTEM:
249 settings.thisSystem = arg;
250 break;
251 default:
252 return (error_t) ARGP_ERR_UNKNOWN;
253 }
254
255 return (error_t) 0;
256 }
257
258 /* Argument parsing. */
259 static const struct argp argp =
260 {
261 options, parse_opt,
262 NULL, doc,
263 NULL, NULL, // children and help_filter
264 guix_textdomain
265 };
266
267
268 \f
269 int
270 main (int argc, char *argv[])
271 {
272 static const Strings nothing;
273
274 setlocale (LC_ALL, "");
275 bindtextdomain (guix_textdomain, LOCALEDIR);
276 textdomain (guix_textdomain);
277
278 /* Initialize libgcrypt. */
279 if (!gcry_check_version (GCRYPT_VERSION))
280 {
281 fprintf (stderr, _("error: libgcrypt version mismatch\n"));
282 exit (EXIT_FAILURE);
283 }
284
285 /* Tell Libgcrypt that initialization has completed, as per the Libgcrypt
286 1.6.0 manual (although this does not appear to be strictly needed.) */
287 gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
288
289 /* Set the umask so that the daemon does not end up creating group-writable
290 files, which would lead to "suspicious ownership or permission" errors.
291 See <http://lists.gnu.org/archive/html/bug-guix/2013-07/msg00033.html>. */
292 umask (S_IWGRP | S_IWOTH);
293
294 #ifndef HAVE_CHROOT
295 # error chroot is assumed to be available
296 #endif
297
298 /* Always use chroots by default. */
299 settings.useChroot = true;
300
301 /* Turn automatic deduplication on by default. */
302 settings.autoOptimiseStore = true;
303
304 /* Default to using as many cores as possible. */
305 settings.buildCores = 0;
306
307 argvSaved = argv;
308
309 try
310 {
311 settings.processEnvironment ();
312
313 /* Hackily help 'local-store.cc' find our 'guix-authenticate' program, which
314 is known as 'OPENSSL_PATH' here. */
315 std::string search_path;
316 search_path = settings.nixLibexecDir;
317 if (getenv ("PATH") != NULL)
318 {
319 search_path += ":";
320 search_path += getenv ("PATH");
321 }
322
323 setenv ("PATH", search_path.c_str (), 1);
324
325 /* Use our substituter by default. */
326 settings.substituters.clear ();
327 settings.set ("build-use-substitutes", "true");
328
329 /* Use our substitute server by default. */
330 settings.set ("substitute-urls", GUIX_SUBSTITUTE_URLS);
331
332 #ifdef HAVE_DAEMON_OFFLOAD_HOOK
333 /* Use our build hook for distributed builds by default. */
334 settings.useBuildHook = true;
335 if (getenv ("NIX_BUILD_HOOK") == NULL)
336 {
337 std::string build_hook;
338
339 build_hook = settings.nixLibexecDir + "/guix/offload";
340 setenv ("NIX_BUILD_HOOK", build_hook.c_str (), 1);
341 }
342 #else
343 /* We are not installing any build hook, so disable it. */
344 settings.useBuildHook = false;
345 #endif
346
347 argp_parse (&argp, argc, argv, 0, 0, 0);
348
349 /* Effect all the changes made via 'settings.set'. */
350 settings.update ();
351
352 if (settings.useSubstitutes)
353 {
354 string subs = getEnv ("NIX_SUBSTITUTERS", "default");
355
356 if (subs == "default")
357 {
358 string subst =
359 settings.nixLibexecDir + "/guix/substitute";
360 setenv ("NIX_SUBSTITUTERS", subst.c_str (), 1);
361 }
362 }
363 else
364 /* Clear the substituter list to make sure nothing ever gets
365 substituted, regardless of the client's settings. */
366 setenv ("NIX_SUBSTITUTERS", "", 1);
367
368 /* Effect the $NIX_SUBSTITUTERS change. */
369 settings.update ();
370
371 if (geteuid () == 0 && settings.buildUsersGroup.empty ())
372 fprintf (stderr, _("warning: daemon is running as root, so \
373 using `--build-users-group' is highly recommended\n"));
374
375 if (settings.useChroot)
376 {
377 std::string chroot_dirs;
378
379 chroot_dirs = settings.get ("build-extra-chroot-dirs",
380 (std::string) "");
381 printMsg (lvlDebug,
382 format ("extra chroot directories: '%1%'") % chroot_dirs);
383 }
384
385 printMsg (lvlDebug,
386 format ("automatic deduplication set to %1%")
387 % settings.autoOptimiseStore);
388
389 printMsg (lvlDebug,
390 format ("listening on `%1%'") % settings.nixDaemonSocketFile);
391
392 run (nothing);
393 }
394 catch (std::exception &e)
395 {
396 fprintf (stderr, _("error: %s\n"), e.what ());
397 return EXIT_FAILURE;
398 }
399
400 return EXIT_SUCCESS; /* never reached */
401 }