gnu: kdenlive: Add ffmpeg to input list
[jackhill/guix/guix.git] / nix / nix-daemon / guix-daemon.cc
CommitLineData
233e7676 1/* GNU Guix --- Functional package management for GNU
4d4a38f6 2 Copyright (C) 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Ludovic Courtès <ludo@gnu.org>
1071f781 3 Copyright (C) 2006, 2010, 2012, 2014 Eelco Dolstra <e.dolstra@tudelft.nl>
c2033df4 4
233e7676 5 This file is part of GNU Guix.
c2033df4 6
233e7676 7 GNU Guix is free software; you can redistribute it and/or modify it
c2033df4
LC
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or (at
10 your option) any later version.
11
233e7676 12 GNU Guix is distributed in the hope that it will be useful, but
c2033df4
LC
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
233e7676 18 along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. */
c2033df4
LC
19
20#include <config.h>
21
22#include <types.hh>
23#include "shared.hh"
24#include <globals.hh>
da30f555 25#include <util.hh>
c2033df4 26
5501e6b6
LC
27#include <gcrypt.h>
28
c2033df4
LC
29#include <stdlib.h>
30#include <argp.h>
e2332e8a
LC
31#include <unistd.h>
32#include <sys/types.h>
b49632e7 33#include <sys/stat.h>
1071f781
LC
34#include <sys/socket.h>
35#include <sys/un.h>
36#include <netdb.h>
6e37066e 37#include <strings.h>
868fce7c 38#include <exception>
1071f781 39#include <iostream>
c2033df4 40
7887bcbf
LC
41#include <libintl.h>
42#include <locale.h>
43
c2033df4
LC
44/* Variables used by `nix-daemon.cc'. */
45volatile ::sig_atomic_t blockInt;
46char **argvSaved;
47
48using namespace nix;
49
50/* Entry point in `nix-daemon.cc'. */
1071f781 51extern void run (const std::vector<int> &);
c2033df4
LC
52
53\f
54/* Command-line options. */
55
7887bcbf
LC
56#define n_(str) str
57#define _(str) gettext (str)
58static const char guix_textdomain[] = "guix";
59
60
c2033df4
LC
61const char *argp_program_version =
62 "guix-daemon (" PACKAGE_NAME ") " PACKAGE_VERSION;
63const char *argp_program_bug_address = PACKAGE_BUGREPORT;
64
65static char doc[] =
7887bcbf
LC
66 n_("guix-daemon -- perform derivation builds and store accesses")
67 "\v\n"
68 n_("This program is a daemon meant to run in the background. It serves \
c2033df4 69requests sent over a Unix-domain socket. It accesses the store, and \
7887bcbf 70builds derivations on behalf of its clients.");
c2033df4
LC
71
72#define GUIX_OPT_SYSTEM 1
73#define GUIX_OPT_DISABLE_CHROOT 2
5c403e35
LC
74#define GUIX_OPT_BUILD_USERS_GROUP 3
75#define GUIX_OPT_CACHE_FAILURES 4
76#define GUIX_OPT_LOSE_LOGS 5
77#define GUIX_OPT_DISABLE_LOG_COMPRESSION 6
ab3893d7 78#define GUIX_OPT_DISABLE_DEDUPLICATION 7
5c403e35 79#define GUIX_OPT_IMPERSONATE_LINUX_26 8
da30f555 80#define GUIX_OPT_DEBUG 9
72ce0373 81#define GUIX_OPT_CHROOT_DIR 10
b8d2aa26 82#define GUIX_OPT_LISTEN 11
6858f9d1 83#define GUIX_OPT_NO_SUBSTITUTES 12
9176607e
LC
84#define GUIX_OPT_SUBSTITUTE_URLS 13
85#define GUIX_OPT_NO_BUILD_HOOK 14
86#define GUIX_OPT_GC_KEEP_OUTPUTS 15
87#define GUIX_OPT_GC_KEEP_DERIVATIONS 16
ecf84b7c 88#define GUIX_OPT_BUILD_ROUNDS 17
2ca9f51e
LC
89#define GUIX_OPT_TIMEOUT 18
90#define GUIX_OPT_MAX_SILENT_TIME 19
29a68668 91#define GUIX_OPT_LOG_COMPRESSION 20
c2033df4
LC
92
93static const struct argp_option options[] =
94 {
7887bcbf
LC
95 { "system", GUIX_OPT_SYSTEM, n_("SYSTEM"), 0,
96 n_("assume SYSTEM as the current system type") },
97 { "cores", 'c', n_("N"), 0,
98 n_("use N CPU cores to build each derivation; 0 means as many as available")
99 },
100 { "max-jobs", 'M', n_("N"), 0,
101 n_("allow at most N build jobs") },
2ca9f51e
LC
102 { "timeout", GUIX_OPT_TIMEOUT, n_("SECONDS"), 0,
103 n_("mark builds as failed after SECONDS of activity") },
104 { "max-silent-time", GUIX_OPT_MAX_SILENT_TIME, n_("SECONDS"), 0,
105 n_("mark builds as failed after SECONDS of silence") },
c2033df4 106 { "disable-chroot", GUIX_OPT_DISABLE_CHROOT, 0, 0,
7887bcbf
LC
107 n_("disable chroot builds") },
108 { "chroot-directory", GUIX_OPT_CHROOT_DIR, n_("DIR"), 0,
109 n_("add DIR to the build chroot") },
110 { "build-users-group", GUIX_OPT_BUILD_USERS_GROUP, n_("GROUP"), 0,
111 n_("perform builds as a user of GROUP") },
6858f9d1 112 { "no-substitutes", GUIX_OPT_NO_SUBSTITUTES, 0, 0,
7887bcbf
LC
113 n_("do not use substitutes") },
114 { "substitute-urls", GUIX_OPT_SUBSTITUTE_URLS, n_("URLS"), 0,
115 n_("use URLS as the default list of substitute providers") },
dc209d5a
LC
116 { "no-offload", GUIX_OPT_NO_BUILD_HOOK, 0, 0,
117 n_("do not attempt to offload builds") },
118 { "no-build-hook", GUIX_OPT_NO_BUILD_HOOK, 0,
119 OPTION_HIDDEN, // deprecated
120 n_("do not attempt to offload builds") },
5c403e35 121 { "cache-failures", GUIX_OPT_CACHE_FAILURES, 0, 0,
7887bcbf 122 n_("cache build failures") },
ecf84b7c
LC
123 { "rounds", GUIX_OPT_BUILD_ROUNDS, "N", 0,
124 n_("build each derivation N times in a row") },
5c403e35 125 { "lose-logs", GUIX_OPT_LOSE_LOGS, 0, 0,
7887bcbf 126 n_("do not keep build logs") },
29a68668
LC
127 { "disable-log-compression", GUIX_OPT_DISABLE_LOG_COMPRESSION, 0,
128 OPTION_HIDDEN, // deprecated
7887bcbf 129 n_("disable compression of the build logs") },
29a68668
LC
130 { "log-compression", GUIX_OPT_LOG_COMPRESSION, "TYPE", 0,
131 n_("use the specified compression type for build logs") },
ab3893d7
LC
132
133 /* '--disable-deduplication' was known as '--disable-store-optimization'
134 up to Guix 0.7 included, so keep the alias around. */
135 { "disable-deduplication", GUIX_OPT_DISABLE_DEDUPLICATION, 0, 0,
7887bcbf 136 n_("disable automatic file \"deduplication\" in the store") },
ab3893d7
LC
137 { "disable-store-optimization", GUIX_OPT_DISABLE_DEDUPLICATION, 0,
138 OPTION_ALIAS | OPTION_HIDDEN, NULL },
139
7887bcbf
LC
140 { "impersonate-linux-2.6", GUIX_OPT_IMPERSONATE_LINUX_26, 0,
141#ifdef HAVE_SYS_PERSONALITY_H
142 0,
143#else
144 OPTION_HIDDEN,
5c403e35 145#endif
7887bcbf 146 n_("impersonate Linux 2.6")
5c403e35 147 },
6e37066e
LC
148 { "gc-keep-outputs", GUIX_OPT_GC_KEEP_OUTPUTS,
149 "yes/no", OPTION_ARG_OPTIONAL,
7887bcbf 150 n_("tell whether the GC must keep outputs of live derivations") },
6e37066e
LC
151 { "gc-keep-derivations", GUIX_OPT_GC_KEEP_DERIVATIONS,
152 "yes/no", OPTION_ARG_OPTIONAL,
7887bcbf
LC
153 n_("tell whether the GC must keep derivations corresponding \
154to live outputs") },
6e37066e 155
7887bcbf
LC
156 { "listen", GUIX_OPT_LISTEN, n_("SOCKET"), 0,
157 n_("listen for connections on SOCKET") },
da30f555 158 { "debug", GUIX_OPT_DEBUG, 0, 0,
7887bcbf 159 n_("produce debugging output") },
c2033df4
LC
160 { 0, 0, 0, 0, 0 }
161 };
162
6e37066e 163
1071f781
LC
164/* Default port for '--listen' on TCP/IP. */
165#define DEFAULT_GUIX_PORT "44146"
166
167/* List of '--listen' options. */
168static std::list<std::string> listen_options;
169
6e37066e
LC
170/* Convert ARG to a Boolean value, or throw an error if it does not denote a
171 Boolean. */
172static bool
173string_to_bool (const char *arg, bool dflt = true)
174{
175 if (arg == NULL)
176 return dflt;
177 else if (strcasecmp (arg, "yes") == 0)
178 return true;
179 else if (strcasecmp (arg, "no") == 0)
180 return false;
181 else
182 throw nix::Error (format ("'%1%': invalid Boolean value") % arg);
183}
184
c2033df4
LC
185/* Parse a single option. */
186static error_t
187parse_opt (int key, char *arg, struct argp_state *state)
188{
189 switch (key)
190 {
191 case GUIX_OPT_DISABLE_CHROOT:
192 settings.useChroot = false;
193 break;
72ce0373 194 case GUIX_OPT_CHROOT_DIR:
2bb04905
LC
195 {
196 std::string chroot_dirs;
197
198 chroot_dirs = settings.get ("build-extra-chroot-dirs",
199 (std::string) "");
200 if (chroot_dirs == "")
201 chroot_dirs = arg;
202 else
203 chroot_dirs = chroot_dirs + " " + arg;
204 settings.set("build-extra-chroot-dirs", chroot_dirs);
205 break;
206 }
29a68668
LC
207 case GUIX_OPT_LOG_COMPRESSION:
208 if (strcmp (arg, "none") == 0)
209 settings.logCompression = COMPRESSION_NONE;
210 else if (strcmp (arg, "gzip") == 0)
211 settings.logCompression = COMPRESSION_GZIP;
f997137d 212#if HAVE_BZLIB_H
29a68668
LC
213 else if (strcmp (arg, "bzip2") == 0)
214 settings.logCompression = COMPRESSION_BZIP2;
f997137d 215#endif
29a68668
LC
216 else
217 {
218 fprintf (stderr, _("error: %s: unknown compression type\n"), arg);
219 exit (EXIT_FAILURE);
220 }
221 break;
c2033df4 222 case GUIX_OPT_DISABLE_LOG_COMPRESSION:
29a68668 223 settings.logCompression = COMPRESSION_NONE;
c2033df4 224 break;
5c403e35
LC
225 case GUIX_OPT_BUILD_USERS_GROUP:
226 settings.buildUsersGroup = arg;
227 break;
ab3893d7 228 case GUIX_OPT_DISABLE_DEDUPLICATION:
5c403e35
LC
229 settings.autoOptimiseStore = false;
230 break;
231 case GUIX_OPT_CACHE_FAILURES:
232 settings.cacheFailure = true;
233 break;
ecf84b7c
LC
234 case GUIX_OPT_BUILD_ROUNDS:
235 {
236 char *end;
237 unsigned long n = strtoul (arg, &end, 10);
238 if (end != arg + strlen (arg))
239 {
240 fprintf (stderr, _("error: %s: invalid number of rounds\n"), arg);
241 exit (EXIT_FAILURE);
242 }
243 settings.set ("build-repeat", std::to_string (std::max (0UL, n - 1)));
244 break;
245 }
5c403e35
LC
246 case GUIX_OPT_IMPERSONATE_LINUX_26:
247 settings.impersonateLinux26 = true;
248 break;
249 case GUIX_OPT_LOSE_LOGS:
250 settings.keepLog = false;
251 break;
b8d2aa26 252 case GUIX_OPT_LISTEN:
1071f781 253 listen_options.push_back (arg);
b8d2aa26 254 break;
9176607e
LC
255 case GUIX_OPT_SUBSTITUTE_URLS:
256 settings.set ("substitute-urls", arg);
257 break;
6858f9d1 258 case GUIX_OPT_NO_SUBSTITUTES:
ad0ab74e 259 settings.set ("build-use-substitutes", "false");
6858f9d1 260 break;
49e6291a
LC
261 case GUIX_OPT_NO_BUILD_HOOK:
262 settings.useBuildHook = false;
263 break;
da30f555
LC
264 case GUIX_OPT_DEBUG:
265 verbosity = lvlDebug;
266 break;
6e37066e
LC
267 case GUIX_OPT_GC_KEEP_OUTPUTS:
268 settings.gcKeepOutputs = string_to_bool (arg);
269 break;
270 case GUIX_OPT_GC_KEEP_DERIVATIONS:
271 settings.gcKeepDerivations = string_to_bool (arg);
272 break;
6221db61 273 case 'c':
ad0ab74e 274 settings.set ("build-cores", arg);
c2033df4
LC
275 break;
276 case 'M':
ad0ab74e 277 settings.set ("build-max-jobs", arg);
c2033df4 278 break;
2ca9f51e
LC
279 case GUIX_OPT_TIMEOUT:
280 settings.set ("build-timeout", arg);
281 break;
282 case GUIX_OPT_MAX_SILENT_TIME:
283 settings.set ("build-max-silent-time", arg);
284 break;
c2033df4
LC
285 case GUIX_OPT_SYSTEM:
286 settings.thisSystem = arg;
287 break;
288 default:
5363abb7 289 return (error_t) ARGP_ERR_UNKNOWN;
c2033df4
LC
290 }
291
5363abb7 292 return (error_t) 0;
c2033df4
LC
293}
294
295/* Argument parsing. */
7887bcbf
LC
296static const struct argp argp =
297 {
298 options, parse_opt,
299 NULL, doc,
300 NULL, NULL, // children and help_filter
301 guix_textdomain
302 };
c2033df4 303
1071f781
LC
304\f
305static int
306open_unix_domain_socket (const char *file)
307{
308 /* Create and bind to a Unix domain socket. */
309 AutoCloseFD fdSocket = socket (PF_UNIX, SOCK_STREAM, 0);
310 if (fdSocket == -1)
311 throw SysError (_("cannot create Unix domain socket"));
312
313 createDirs (dirOf (file));
314
315 /* Urgh, sockaddr_un allows path names of only 108 characters.
316 So chdir to the socket directory so that we can pass a
317 relative path name. */
318 if (chdir (dirOf (file).c_str ()) == -1)
319 throw SysError (_("cannot change current directory"));
320 Path fileRel = "./" + baseNameOf (file);
321
322 struct sockaddr_un addr;
323 addr.sun_family = AF_UNIX;
324 if (fileRel.size () >= sizeof (addr.sun_path))
325 throw Error (format (_("socket file name '%1%' is too long")) % fileRel);
326 strcpy (addr.sun_path, fileRel.c_str ());
327
328 unlink (file);
329
330 /* Make sure that the socket is created with 0666 permission
331 (everybody can connect --- provided they have access to the
332 directory containing the socket). */
333 mode_t oldMode = umask (0111);
334 int res = bind (fdSocket, (struct sockaddr *) &addr, sizeof addr);
335 umask (oldMode);
336 if (res == -1)
337 throw SysError (format (_("cannot bind to socket '%1%'")) % file);
338
339 if (chdir ("/") == -1) /* back to the root */
340 throw SysError (_("cannot change current directory"));
341
342 if (listen (fdSocket, 5) == -1)
343 throw SysError (format (_("cannot listen on socket '%1%'")) % file);
344
345 return fdSocket.borrow ();
346}
347
348/* Return a listening socket for ADDRESS, which has the given LENGTH. */
349static int
350open_inet_socket (const struct sockaddr *address, socklen_t length)
351{
352 AutoCloseFD fd = socket (address->sa_family, SOCK_STREAM, 0);
353 if (fd == -1)
354 throw SysError (_("cannot create TCP socket"));
355
356 int res = bind (fd, address, length);
357 if (res == -1)
358 throw SysError (_("cannot bind TCP socket"));
359
360 if (listen (fd, 5) == -1)
361 throw SysError (format (_("cannot listen on TCP socket")));
362
363 return fd.borrow ();
364}
365
366/* Return a list of file descriptors of listening sockets. */
367static std::vector<int>
368listening_sockets (const std::list<std::string> &options)
369{
370 std::vector<int> result;
371
372 if (options.empty ())
373 {
374 /* Open the default Unix-domain socket. */
375 auto fd = open_unix_domain_socket (settings.nixDaemonSocketFile.c_str ());
376 result.push_back (fd);
377 return result;
378 }
379
380 /* Open the user-specified sockets. */
381 for (const std::string& option: options)
382 {
383 if (option[0] == '/')
384 {
385 /* Assume OPTION is the file name of a Unix-domain socket. */
386 settings.nixDaemonSocketFile = canonPath (option);
387 int fd =
388 open_unix_domain_socket (settings.nixDaemonSocketFile.c_str ());
389 result.push_back (fd);
390 }
391 else
392 {
393 /* Assume OPTIONS has the form "HOST" or "HOST:PORT". */
394 auto colon = option.find_last_of (":");
395 auto host = colon == std::string::npos
396 ? option : option.substr (0, colon);
397 auto port = colon == std::string::npos
398 ? DEFAULT_GUIX_PORT
399 : option.substr (colon + 1, option.size () - colon - 1);
400
401 struct addrinfo *res, hints;
402
403 memset (&hints, '\0', sizeof hints);
404 hints.ai_socktype = SOCK_STREAM;
405 hints.ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG;
406
407 int err = getaddrinfo (host.c_str(), port.c_str (),
408 &hints, &res);
409
410 if (err != 0)
411 throw Error(format ("failed to look up '%1%': %2%")
412 % option % gai_strerror (err));
413
414 printMsg (lvlDebug, format ("listening on '%1%', port '%2%'")
415 % host % port);
416
417 /* XXX: Pick the first result, RES. */
418 result.push_back (open_inet_socket (res->ai_addr,
419 res->ai_addrlen));
420
421 freeaddrinfo (res);
422 }
423 }
424
425 return result;
426}
c2033df4
LC
427
428\f
429int
430main (int argc, char *argv[])
431{
7887bcbf
LC
432 setlocale (LC_ALL, "");
433 bindtextdomain (guix_textdomain, LOCALEDIR);
434 textdomain (guix_textdomain);
c2033df4 435
5501e6b6
LC
436 /* Initialize libgcrypt. */
437 if (!gcry_check_version (GCRYPT_VERSION))
438 {
7887bcbf 439 fprintf (stderr, _("error: libgcrypt version mismatch\n"));
5501e6b6
LC
440 exit (EXIT_FAILURE);
441 }
442
37dd969c
LC
443 /* Tell Libgcrypt that initialization has completed, as per the Libgcrypt
444 1.6.0 manual (although this does not appear to be strictly needed.) */
445 gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
446
b49632e7
LC
447 /* Set the umask so that the daemon does not end up creating group-writable
448 files, which would lead to "suspicious ownership or permission" errors.
449 See <http://lists.gnu.org/archive/html/bug-guix/2013-07/msg00033.html>. */
450 umask (S_IWGRP | S_IWOTH);
451
3b9855f4
LC
452#ifndef HAVE_CHROOT
453# error chroot is assumed to be available
8b15ac67
LC
454#endif
455
3b9855f4
LC
456 /* Always use chroots by default. */
457 settings.useChroot = true;
458
44d43c7a
LC
459 /* Turn automatic deduplication on by default. */
460 settings.autoOptimiseStore = true;
461
deac976d 462 /* Default to using as many cores as possible and one job at a time. */
6efc160e 463 settings.buildCores = 0;
deac976d 464 settings.maxBuildJobs = 1;
6efc160e 465
868fce7c
LC
466 argvSaved = argv;
467
468 try
469 {
470 settings.processEnvironment ();
c2033df4 471
f6919ebd 472 /* Enable substitutes by default. */
ad0ab74e 473 settings.set ("build-use-substitutes", "true");
335dd762 474
9176607e 475 /* Use our substitute server by default. */
df061d07 476 settings.set ("substitute-urls", GUIX_SUBSTITUTE_URLS);
9176607e 477
49e6291a 478#ifdef HAVE_DAEMON_OFFLOAD_HOOK
bc69ea2d 479 /* Use 'guix offload' for distributed builds by default. */
49e6291a 480 settings.useBuildHook = true;
49e6291a
LC
481#else
482 /* We are not installing any build hook, so disable it. */
483 settings.useBuildHook = false;
484#endif
485
868fce7c 486 argp_parse (&argp, argc, argv, 0, 0, 0);
c2033df4 487
1071f781
LC
488 auto sockets = listening_sockets (listen_options);
489
ad0ab74e
LC
490 /* Effect all the changes made via 'settings.set'. */
491 settings.update ();
29a68668
LC
492 printMsg(lvlDebug,
493 format ("build log compression: %1%") % settings.logCompression);
ad0ab74e 494
868fce7c 495 if (geteuid () == 0 && settings.buildUsersGroup.empty ())
7887bcbf
LC
496 fprintf (stderr, _("warning: daemon is running as root, so \
497using `--build-users-group' is highly recommended\n"));
e2332e8a 498
706d0641
LC
499 if (settings.useChroot)
500 {
2bb04905
LC
501 std::string chroot_dirs;
502
503 chroot_dirs = settings.get ("build-extra-chroot-dirs",
504 (std::string) "");
505 printMsg (lvlDebug,
506 format ("extra chroot directories: '%1%'") % chroot_dirs);
706d0641 507 }
706d0641 508
44d43c7a
LC
509 printMsg (lvlDebug,
510 format ("automatic deduplication set to %1%")
511 % settings.autoOptimiseStore);
512
b8d2aa26
LC
513 printMsg (lvlDebug,
514 format ("listening on `%1%'") % settings.nixDaemonSocketFile);
515
1071f781 516 run (sockets);
868fce7c
LC
517 }
518 catch (std::exception &e)
519 {
7887bcbf 520 fprintf (stderr, _("error: %s\n"), e.what ());
868fce7c
LC
521 return EXIT_FAILURE;
522 }
523
524 return EXIT_SUCCESS; /* never reached */
c2033df4 525}