gnu: hurd: Update to hurd-headers version: 0.9-91a51672.
[jackhill/guix/guix.git] / nix / libstore / build.cc
CommitLineData
36457566
LC
1#include "config.h"
2
3#include "references.hh"
4#include "pathlocks.hh"
5#include "misc.hh"
6#include "globals.hh"
7#include "local-store.hh"
8#include "util.hh"
9#include "archive.hh"
10#include "affinity.hh"
94d92c77 11#include "builtins.hh"
36457566
LC
12
13#include <map>
14#include <sstream>
15#include <algorithm>
16
15ddeff5 17#include <limits.h>
36457566
LC
18#include <time.h>
19#include <sys/time.h>
20#include <sys/wait.h>
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <sys/utsname.h>
24#include <fcntl.h>
25#include <unistd.h>
26#include <errno.h>
27#include <stdio.h>
28#include <cstring>
a1aa5dab 29#include <stdint.h>
36457566
LC
30
31#include <pwd.h>
32#include <grp.h>
33
29a68668 34#include <zlib.h>
f997137d
LC
35
36#if HAVE_BZLIB_H
37# include <bzlib.h>
38#endif
36457566
LC
39
40/* Includes required for chroot support. */
41#if HAVE_SYS_PARAM_H
42#include <sys/param.h>
43#endif
44#if HAVE_SYS_MOUNT_H
45#include <sys/mount.h>
46#endif
54c260e6
LC
47#if HAVE_SYS_SYSCALL_H
48#include <sys/syscall.h>
49#endif
36457566
LC
50#if HAVE_SCHED_H
51#include <sched.h>
52#endif
53
36457566 54
cbe95af7 55#define CHROOT_ENABLED HAVE_CHROOT && HAVE_SYS_MOUNT_H && defined(MS_BIND) && defined(MS_PRIVATE) && defined(CLONE_NEWNS) && defined(SYS_pivot_root)
36457566
LC
56
57#if CHROOT_ENABLED
58#include <sys/socket.h>
59#include <sys/ioctl.h>
60#include <net/if.h>
61#include <netinet/ip.h>
62#endif
63
2bb04905 64#if __linux__
36457566 65#include <sys/personality.h>
36457566
LC
66#endif
67
68#if HAVE_STATVFS
69#include <sys/statvfs.h>
70#endif
71
72
73namespace nix {
74
75using std::map;
76
77
78static string pathNullDevice = "/dev/null";
79
80
81/* Forward definition. */
82class Worker;
83struct HookInstance;
84
85
86/* A pointer to a goal. */
87class Goal;
f3ff1da4 88class DerivationGoal;
36457566
LC
89typedef std::shared_ptr<Goal> GoalPtr;
90typedef std::weak_ptr<Goal> WeakGoalPtr;
91
2bb04905
LC
92struct CompareGoalPtrs {
93 bool operator() (const GoalPtr & a, const GoalPtr & b);
94};
95
36457566 96/* Set of goals. */
2bb04905 97typedef set<GoalPtr, CompareGoalPtrs> Goals;
36457566
LC
98typedef list<WeakGoalPtr> WeakGoals;
99
100/* A map of paths to goals (and the other way around). */
101typedef map<Path, WeakGoalPtr> WeakGoalMap;
102
103
104
105class Goal : public std::enable_shared_from_this<Goal>
106{
107public:
108 typedef enum {ecBusy, ecSuccess, ecFailed, ecNoSubstituters, ecIncompleteClosure} ExitCode;
109
110protected:
111
112 /* Backlink to the worker. */
113 Worker & worker;
114
115 /* Goals that this goal is waiting for. */
116 Goals waitees;
117
118 /* Goals waiting for this one to finish. Must use weak pointers
119 here to prevent cycles. */
120 WeakGoals waiters;
121
122 /* Number of goals we are/were waiting for that have failed. */
123 unsigned int nrFailed;
124
125 /* Number of substitution goals we are/were waiting for that
126 failed because there are no substituters. */
127 unsigned int nrNoSubstituters;
128
129 /* Number of substitution goals we are/were waiting for that
130 failed because othey had unsubstitutable references. */
131 unsigned int nrIncompleteClosure;
132
133 /* Name of this goal for debugging purposes. */
134 string name;
135
136 /* Whether the goal is finished. */
137 ExitCode exitCode;
138
139 Goal(Worker & worker) : worker(worker)
140 {
141 nrFailed = nrNoSubstituters = nrIncompleteClosure = 0;
142 exitCode = ecBusy;
143 }
144
145 virtual ~Goal()
146 {
147 trace("goal destroyed");
148 }
149
150public:
151 virtual void work() = 0;
152
153 void addWaitee(GoalPtr waitee);
154
155 virtual void waiteeDone(GoalPtr waitee, ExitCode result);
156
157 virtual void handleChildOutput(int fd, const string & data)
158 {
159 abort();
160 }
161
162 virtual void handleEOF(int fd)
163 {
164 abort();
165 }
166
167 void trace(const format & f);
168
169 string getName()
170 {
171 return name;
172 }
173
174 ExitCode getExitCode()
175 {
176 return exitCode;
177 }
178
f3ff1da4
ED
179 /* Callback in case of a timeout. It should wake up its waiters,
180 get rid of any running child processes that are being monitored
181 by the worker (important!), etc. */
182 virtual void timedOut() = 0;
36457566 183
2bb04905
LC
184 virtual string key() = 0;
185
36457566
LC
186protected:
187 void amDone(ExitCode result);
188};
189
190
2bb04905
LC
191bool CompareGoalPtrs::operator() (const GoalPtr & a, const GoalPtr & b) {
192 string s1 = a->key();
193 string s2 = b->key();
194 return s1 < s2;
195}
196
197
36457566
LC
198/* A mapping used to remember for each child process to what goal it
199 belongs, and file descriptors for receiving log data and output
200 path creation commands. */
201struct Child
202{
203 WeakGoalPtr goal;
204 set<int> fds;
205 bool respectTimeouts;
206 bool inBuildSlot;
207 time_t lastOutput; /* time we last got output on stdout/stderr */
208 time_t timeStarted;
209};
210
211typedef map<pid_t, Child> Children;
212
213
214/* The worker class. */
215class Worker
216{
217private:
218
219 /* Note: the worker should only have strong pointers to the
220 top-level goals. */
221
222 /* The top-level goals of the worker. */
223 Goals topGoals;
224
225 /* Goals that are ready to do some work. */
226 WeakGoals awake;
227
228 /* Goals waiting for a build slot. */
229 WeakGoals wantingToBuild;
230
231 /* Child processes currently running. */
232 Children children;
233
234 /* Number of build slots occupied. This includes local builds and
235 substitutions but not remote builds via the build hook. */
236 unsigned int nrLocalBuilds;
237
238 /* Maps used to prevent multiple instantiations of a goal for the
239 same derivation / path. */
240 WeakGoalMap derivationGoals;
241 WeakGoalMap substitutionGoals;
242
243 /* Goals waiting for busy paths to be unlocked. */
244 WeakGoals waitingForAnyGoal;
245
246 /* Goals sleeping for a few seconds (polling a lock). */
247 WeakGoals waitingForAWhile;
248
249 /* Last time the goals in `waitingForAWhile' where woken up. */
250 time_t lastWokenUp;
251
252public:
253
254 /* Set if at least one derivation had a BuildError (i.e. permanent
255 failure). */
256 bool permanentFailure;
257
2bb04905
LC
258 /* Set if at least one derivation had a timeout. */
259 bool timedOut;
260
36457566
LC
261 LocalStore & store;
262
263 std::shared_ptr<HookInstance> hook;
264
265 Worker(LocalStore & store);
266 ~Worker();
267
268 /* Make a goal (with caching). */
269 GoalPtr makeDerivationGoal(const Path & drvPath, const StringSet & wantedOutputs, BuildMode buildMode = bmNormal);
270 GoalPtr makeSubstitutionGoal(const Path & storePath, bool repair = false);
271
272 /* Remove a dead goal. */
273 void removeGoal(GoalPtr goal);
274
275 /* Wake up a goal (i.e., there is something for it to do). */
276 void wakeUp(GoalPtr goal);
277
278 /* Return the number of local build and substitution processes
279 currently running (but not remote builds via the build
280 hook). */
281 unsigned int getNrLocalBuilds();
282
283 /* Registers a running child process. `inBuildSlot' means that
284 the process counts towards the jobs limit. */
285 void childStarted(GoalPtr goal, pid_t pid,
286 const set<int> & fds, bool inBuildSlot, bool respectTimeouts);
287
288 /* Unregisters a running child process. `wakeSleepers' should be
289 false if there is no sense in waking up goals that are sleeping
290 because they can't run yet (e.g., there is no free build slot,
291 or the hook would still say `postpone'). */
292 void childTerminated(pid_t pid, bool wakeSleepers = true);
293
294 /* Put `goal' to sleep until a build slot becomes available (which
295 might be right away). */
296 void waitForBuildSlot(GoalPtr goal);
297
298 /* Wait for any goal to finish. Pretty indiscriminate way to
299 wait for some resource that some other goal is holding. */
300 void waitForAnyGoal(GoalPtr goal);
301
302 /* Wait for a few seconds and then retry this goal. Used when
303 waiting for a lock held by another process. This kind of
304 polling is inefficient, but POSIX doesn't really provide a way
305 to wait for multiple locks in the main select() loop. */
306 void waitForAWhile(GoalPtr goal);
307
308 /* Loop until the specified top-level goals have finished. */
309 void run(const Goals & topGoals);
310
311 /* Wait for input to become available. */
312 void waitForInput();
313
314 unsigned int exitStatus();
315};
316
317
318//////////////////////////////////////////////////////////////////////
319
320
321void addToWeakGoals(WeakGoals & goals, GoalPtr p)
322{
323 // FIXME: necessary?
2bb04905 324 // FIXME: O(n)
36457566
LC
325 foreach (WeakGoals::iterator, i, goals)
326 if (i->lock() == p) return;
327 goals.push_back(p);
328}
329
330
331void Goal::addWaitee(GoalPtr waitee)
332{
333 waitees.insert(waitee);
334 addToWeakGoals(waitee->waiters, shared_from_this());
335}
336
337
338void Goal::waiteeDone(GoalPtr waitee, ExitCode result)
339{
340 assert(waitees.find(waitee) != waitees.end());
341 waitees.erase(waitee);
342
343 trace(format("waitee `%1%' done; %2% left") %
344 waitee->name % waitees.size());
345
346 if (result == ecFailed || result == ecNoSubstituters || result == ecIncompleteClosure) ++nrFailed;
347
348 if (result == ecNoSubstituters) ++nrNoSubstituters;
349
350 if (result == ecIncompleteClosure) ++nrIncompleteClosure;
351
352 if (waitees.empty() || (result == ecFailed && !settings.keepGoing)) {
353
354 /* If we failed and keepGoing is not set, we remove all
355 remaining waitees. */
356 foreach (Goals::iterator, i, waitees) {
357 GoalPtr goal = *i;
358 WeakGoals waiters2;
359 foreach (WeakGoals::iterator, j, goal->waiters)
360 if (j->lock() != shared_from_this()) waiters2.push_back(*j);
361 goal->waiters = waiters2;
362 }
363 waitees.clear();
364
365 worker.wakeUp(shared_from_this());
366 }
367}
368
369
370void Goal::amDone(ExitCode result)
371{
372 trace("done");
373 assert(exitCode == ecBusy);
374 assert(result == ecSuccess || result == ecFailed || result == ecNoSubstituters || result == ecIncompleteClosure);
375 exitCode = result;
376 foreach (WeakGoals::iterator, i, waiters) {
377 GoalPtr goal = i->lock();
378 if (goal) goal->waiteeDone(shared_from_this(), result);
379 }
380 waiters.clear();
381 worker.removeGoal(shared_from_this());
382}
383
384
385void Goal::trace(const format & f)
386{
387 debug(format("%1%: %2%") % name % f);
388}
389
390
391
392//////////////////////////////////////////////////////////////////////
393
394
395/* Common initialisation performed in child processes. */
396static void commonChildInit(Pipe & logPipe)
397{
36457566
LC
398 /* Put the child in a separate session (and thus a separate
399 process group) so that it has no controlling terminal (meaning
400 that e.g. ssh cannot open /dev/tty) and it doesn't receive
401 terminal signals. */
402 if (setsid() == -1)
403 throw SysError(format("creating a new session"));
404
405 /* Dup the write side of the logger pipe into stderr. */
406 if (dup2(logPipe.writeSide, STDERR_FILENO) == -1)
407 throw SysError("cannot pipe standard error into log file");
408
409 /* Dup stderr to stdout. */
410 if (dup2(STDERR_FILENO, STDOUT_FILENO) == -1)
411 throw SysError("cannot dup stderr into stdout");
412
413 /* Reroute stdin to /dev/null. */
414 int fdDevNull = open(pathNullDevice.c_str(), O_RDWR);
415 if (fdDevNull == -1)
416 throw SysError(format("cannot open `%1%'") % pathNullDevice);
417 if (dup2(fdDevNull, STDIN_FILENO) == -1)
418 throw SysError("cannot dup null device into stdin");
419 close(fdDevNull);
420}
421
36457566
LC
422/* Restore default handling of SIGPIPE, otherwise some programs will
423 randomly say "Broken pipe". */
424static void restoreSIGPIPE()
425{
426 struct sigaction act, oact;
427 act.sa_handler = SIG_DFL;
428 act.sa_flags = 0;
429 sigemptyset(&act.sa_mask);
430 if (sigaction(SIGPIPE, &act, &oact)) throw SysError("resetting SIGPIPE");
431}
432
433
434//////////////////////////////////////////////////////////////////////
435
436
437class UserLock
438{
439private:
440 /* POSIX locks suck. If we have a lock on a file, and we open and
441 close that file again (without closing the original file
442 descriptor), we lose the lock. So we have to be *very* careful
443 not to open a lock file on which we are holding a lock. */
444 static PathSet lockedPaths; /* !!! not thread-safe */
445
446 Path fnUserLock;
447 AutoCloseFD fdUserLock;
448
449 string user;
450 uid_t uid;
451 gid_t gid;
322eeb87 452 std::vector<gid_t> supplementaryGIDs;
36457566
LC
453
454public:
455 UserLock();
456 ~UserLock();
457
458 void acquire();
459 void release();
460
461 void kill();
462
463 string getUser() { return user; }
464 uid_t getUID() { return uid; }
465 uid_t getGID() { return gid; }
322eeb87 466 std::vector<gid_t> getSupplementaryGIDs() { return supplementaryGIDs; }
36457566
LC
467
468 bool enabled() { return uid != 0; }
469
470};
471
472
473PathSet UserLock::lockedPaths;
474
475
476UserLock::UserLock()
477{
478 uid = gid = 0;
479}
480
481
482UserLock::~UserLock()
483{
484 release();
485}
486
487
488void UserLock::acquire()
489{
490 assert(uid == 0);
491
492 assert(settings.buildUsersGroup != "");
493
494 /* Get the members of the build-users-group. */
495 struct group * gr = getgrnam(settings.buildUsersGroup.c_str());
496 if (!gr)
497 throw Error(format("the group `%1%' specified in `build-users-group' does not exist")
498 % settings.buildUsersGroup);
499 gid = gr->gr_gid;
500
501 /* Copy the result of getgrnam. */
502 Strings users;
503 for (char * * p = gr->gr_mem; *p; ++p) {
504 debug(format("found build user `%1%'") % *p);
505 users.push_back(*p);
506 }
507
508 if (users.empty())
509 throw Error(format("the build users group `%1%' has no members")
510 % settings.buildUsersGroup);
511
512 /* Find a user account that isn't currently in use for another
513 build. */
514 foreach (Strings::iterator, i, users) {
515 debug(format("trying user `%1%'") % *i);
516
517 struct passwd * pw = getpwnam(i->c_str());
518 if (!pw)
519 throw Error(format("the user `%1%' in the group `%2%' does not exist")
520 % *i % settings.buildUsersGroup);
521
522 createDirs(settings.nixStateDir + "/userpool");
523
524 fnUserLock = (format("%1%/userpool/%2%") % settings.nixStateDir % pw->pw_uid).str();
525
526 if (lockedPaths.find(fnUserLock) != lockedPaths.end())
527 /* We already have a lock on this one. */
528 continue;
529
530 AutoCloseFD fd = open(fnUserLock.c_str(), O_RDWR | O_CREAT, 0600);
531 if (fd == -1)
532 throw SysError(format("opening user lock `%1%'") % fnUserLock);
533 closeOnExec(fd);
534
535 if (lockFile(fd, ltWrite, false)) {
536 fdUserLock = fd.borrow();
537 lockedPaths.insert(fnUserLock);
538 user = *i;
539 uid = pw->pw_uid;
540
541 /* Sanity check... */
542 if (uid == getuid() || uid == geteuid())
8327e733 543 throw Error(format("the build user should not be a member of `%1%'")
36457566
LC
544 % settings.buildUsersGroup);
545
322eeb87
LC
546 /* Get the list of supplementary groups of this build user. This
547 is usually either empty or contains a group such as "kvm". */
548 supplementaryGIDs.resize(10);
549 int ngroups = supplementaryGIDs.size();
550 int err = getgrouplist(pw->pw_name, pw->pw_gid,
551 supplementaryGIDs.data(), &ngroups);
552 if (err == -1)
553 throw Error(format("failed to get list of supplementary groups for ‘%1%’") % pw->pw_name);
554
555 supplementaryGIDs.resize(ngroups);
556
36457566
LC
557 return;
558 }
559 }
560
561 throw Error(format("all build users are currently in use; "
562 "consider creating additional users and adding them to the `%1%' group")
563 % settings.buildUsersGroup);
564}
565
566
567void UserLock::release()
568{
569 if (uid == 0) return;
570 fdUserLock.close(); /* releases lock */
571 assert(lockedPaths.find(fnUserLock) != lockedPaths.end());
572 lockedPaths.erase(fnUserLock);
573 fnUserLock = "";
574 uid = 0;
575}
576
577
578void UserLock::kill()
579{
580 assert(enabled());
581 killUser(uid);
582}
583
584
585//////////////////////////////////////////////////////////////////////
586
587
588struct HookInstance
589{
590 /* Pipes for talking to the build hook. */
591 Pipe toHook;
592
593 /* Pipe for the hook's standard output/error. */
594 Pipe fromHook;
595
596 /* Pipe for the builder's standard output/error. */
597 Pipe builderOut;
598
599 /* The process ID of the hook. */
600 Pid pid;
601
602 HookInstance();
603
604 ~HookInstance();
605};
606
607
608HookInstance::HookInstance()
609{
610 debug("starting build hook");
611
bc69ea2d 612 const Path &buildHook = settings.guixProgram;
36457566
LC
613
614 /* Create a pipe to get the output of the child. */
615 fromHook.create();
616
617 /* Create the communication pipes. */
618 toHook.create();
619
620 /* Create a pipe to get the output of the builder. */
621 builderOut.create();
622
623 /* Fork the hook. */
2bb04905 624 pid = startProcess([&]() {
36457566 625
2bb04905 626 commonChildInit(fromHook);
36457566 627
2bb04905 628 if (chdir("/") == -1) throw SysError("changing into `/");
36457566 629
2bb04905
LC
630 /* Dup the communication pipes. */
631 if (dup2(toHook.readSide, STDIN_FILENO) == -1)
632 throw SysError("dupping to-hook read side");
36457566 633
2bb04905
LC
634 /* Use fd 4 for the builder's stdout/stderr. */
635 if (dup2(builderOut.writeSide, 4) == -1)
636 throw SysError("dupping builder's stdout/stderr");
36457566 637
bc69ea2d
LC
638 execl(buildHook.c_str(), buildHook.c_str(), "offload",
639 settings.thisSystem.c_str(),
2bb04905
LC
640 (format("%1%") % settings.maxSilentTime).str().c_str(),
641 (format("%1%") % settings.printBuildTrace).str().c_str(),
642 (format("%1%") % settings.buildTimeout).str().c_str(),
643 NULL);
36457566 644
bc69ea2d 645 throw SysError(format("executing `%1% offload'") % buildHook);
2bb04905 646 });
36457566 647
36457566 648 pid.setSeparatePG(true);
36457566
LC
649 fromHook.writeSide.close();
650 toHook.readSide.close();
651}
652
653
654HookInstance::~HookInstance()
655{
656 try {
2bb04905
LC
657 toHook.writeSide.close();
658 pid.kill(true);
36457566
LC
659 } catch (...) {
660 ignoreException();
661 }
662}
663
664
665//////////////////////////////////////////////////////////////////////
666
667
668typedef map<string, string> HashRewrites;
669
670
671string rewriteHashes(string s, const HashRewrites & rewrites)
672{
673 foreach (HashRewrites::const_iterator, i, rewrites) {
674 assert(i->first.size() == i->second.size());
675 size_t j = 0;
676 while ((j = s.find(i->first, j)) != string::npos) {
677 debug(format("rewriting @ %1%") % j);
678 s.replace(j, i->second.size(), i->second);
679 }
680 }
681 return s;
682}
683
684
685//////////////////////////////////////////////////////////////////////
686
687
688typedef enum {rpAccept, rpDecline, rpPostpone} HookReply;
689
690class SubstitutionGoal;
691
692class DerivationGoal : public Goal
693{
694private:
695 /* The path of the derivation. */
696 Path drvPath;
697
698 /* The specific outputs that we need to build. Empty means all of
699 them. */
700 StringSet wantedOutputs;
701
702 /* Whether additional wanted outputs have been added. */
703 bool needRestart;
704
705 /* Whether to retry substituting the outputs after building the
706 inputs. */
707 bool retrySubstitution;
708
709 /* The derivation stored at drvPath. */
710 Derivation drv;
711
712 /* The remainder is state held during the build. */
713
714 /* Locks on the output paths. */
715 PathLocks outputLocks;
716
717 /* All input paths (that is, the union of FS closures of the
718 immediate input paths). */
719 PathSet inputPaths;
720
721 /* Referenceable paths (i.e., input and output paths). */
722 PathSet allPaths;
723
724 /* Outputs that are already valid. If we're repairing, these are
725 the outputs that are valid *and* not corrupt. */
726 PathSet validPaths;
727
728 /* Outputs that are corrupt or not valid. */
729 PathSet missingPaths;
730
731 /* User selected for running the builder. */
732 UserLock buildUser;
733
734 /* The process ID of the builder. */
735 Pid pid;
736
737 /* The temporary directory. */
738 Path tmpDir;
739
cb960102
ED
740 /* The path of the temporary directory in the sandbox. */
741 Path tmpDirInSandbox;
742
36457566
LC
743 /* File descriptor for the log file. */
744 FILE * fLogFile;
29a68668 745 gzFile gzLogFile;
f997137d 746#if HAVE_BZLIB_H
36457566 747 BZFILE * bzLogFile;
f997137d 748#endif
36457566
LC
749 AutoCloseFD fdLogFile;
750
751 /* Number of bytes received from the builder's stdout/stderr. */
752 unsigned long logSize;
753
754 /* Pipe for the builder's standard output/error. */
755 Pipe builderOut;
756
757 /* The build hook. */
758 std::shared_ptr<HookInstance> hook;
759
760 /* Whether we're currently doing a chroot build. */
761 bool useChroot;
762
763 Path chrootRootDir;
764
765 /* RAII object to delete the chroot directory. */
766 std::shared_ptr<AutoDelete> autoDelChroot;
767
768 /* All inputs that are regular files. */
769 PathSet regularInputPaths;
770
771 /* Whether this is a fixed-output derivation. */
772 bool fixedOutput;
773
774 typedef void (DerivationGoal::*GoalState)();
775 GoalState state;
776
54c260e6 777 /* Stuff we need to pass to runChild(). */
36457566
LC
778 typedef map<Path, Path> DirsInChroot; // maps target path to source path
779 DirsInChroot dirsInChroot;
780 typedef map<string, string> Environment;
781 Environment env;
782
783 /* Hash rewriting. */
784 HashRewrites rewritesToTmp, rewritesFromTmp;
785 typedef map<Path, Path> RedirectedOutputs;
786 RedirectedOutputs redirectedOutputs;
787
788 BuildMode buildMode;
789
790 /* If we're repairing without a chroot, there may be outputs that
791 are valid but corrupt. So we redirect these outputs to
792 temporary paths. */
793 PathSet redirectedBadOutputs;
794
b23b4d39
ED
795 /* The current round, if we're building multiple times. */
796 unsigned int curRound = 1;
797
798 unsigned int nrRounds;
799
800 /* Path registration info from the previous round, if we're
801 building multiple times. Since this contains the hash, it
802 allows us to compare whether two rounds produced the same
803 result. */
804 ValidPathInfos prevInfos;
36457566 805
f3ff1da4
ED
806 BuildResult result;
807
36457566
LC
808public:
809 DerivationGoal(const Path & drvPath, const StringSet & wantedOutputs, Worker & worker, BuildMode buildMode = bmNormal);
810 ~DerivationGoal();
811
f3ff1da4 812 void timedOut() override;
36457566 813
2bb04905
LC
814 string key()
815 {
816 /* Ensure that derivations get built in order of their name,
817 i.e. a derivation named "aardvark" always comes before
818 "baboon". And substitution goals always happen before
819 derivation goals (due to "b$"). */
820 return "b$" + storePathToName(drvPath) + "$" + drvPath;
821 }
822
36457566
LC
823 void work();
824
825 Path getDrvPath()
826 {
827 return drvPath;
828 }
829
830 /* Add wanted outputs to an already existing derivation goal. */
831 void addWantedOutputs(const StringSet & outputs);
832
f3ff1da4
ED
833 BuildResult getResult() { return result; }
834
36457566
LC
835private:
836 /* The states. */
837 void init();
838 void haveDerivation();
839 void outputsSubstituted();
840 void closureRepaired();
841 void inputsRealised();
842 void tryToBuild();
843 void buildDone();
844
845 /* Is the build hook willing to perform the build? */
846 HookReply tryBuildHook();
847
848 /* Start building a derivation. */
849 void startBuilder();
850
54c260e6
LC
851 /* Run the builder's process. */
852 void runChild();
36457566
LC
853
854 friend int childEntry(void *);
855
856 /* Check that the derivation outputs all exist and register them
857 as valid. */
858 void registerOutputs();
859
860 /* Open a log file and a pipe to it. */
861 Path openLogFile();
862
863 /* Close the log file. */
864 void closeLogFile();
865
866 /* Delete the temporary directory, if we have one. */
867 void deleteTmpDir(bool force);
868
869 /* Callback used by the worker to write to the log. */
870 void handleChildOutput(int fd, const string & data);
871 void handleEOF(int fd);
872
873 /* Return the set of (in)valid paths. */
874 PathSet checkPathValidity(bool returnValid, bool checkHash);
875
876 /* Abort the goal if `path' failed to build. */
877 bool pathFailed(const Path & path);
878
879 /* Forcibly kill the child process, if any. */
880 void killChild();
881
882 Path addHashRewrite(const Path & path);
883
884 void repairClosure();
f3ff1da4
ED
885
886 void done(BuildResult::Status status, const string & msg = "");
36457566
LC
887};
888
889
890DerivationGoal::DerivationGoal(const Path & drvPath, const StringSet & wantedOutputs, Worker & worker, BuildMode buildMode)
891 : Goal(worker)
892 , wantedOutputs(wantedOutputs)
893 , needRestart(false)
894 , retrySubstitution(false)
895 , fLogFile(0)
29a68668 896 , gzLogFile(0)
f997137d 897#if HAVE_BZLIB_H
36457566 898 , bzLogFile(0)
f997137d 899#endif
36457566
LC
900 , useChroot(false)
901 , buildMode(buildMode)
902{
903 this->drvPath = drvPath;
904 state = &DerivationGoal::init;
905 name = (format("building of `%1%'") % drvPath).str();
906 trace("created");
538684d0
ED
907
908 /* Prevent the .chroot directory from being
909 garbage-collected. (See isActiveTempFile() in gc.cc.) */
910 worker.store.addTempRoot(drvPath);
36457566
LC
911}
912
913
914DerivationGoal::~DerivationGoal()
915{
916 /* Careful: we should never ever throw an exception from a
917 destructor. */
2bb04905
LC
918 try { killChild(); } catch (...) { ignoreException(); }
919 try { deleteTmpDir(false); } catch (...) { ignoreException(); }
920 try { closeLogFile(); } catch (...) { ignoreException(); }
36457566
LC
921}
922
923
924void DerivationGoal::killChild()
925{
926 if (pid != -1) {
927 worker.childTerminated(pid);
928
929 if (buildUser.enabled()) {
930 /* If we're using a build user, then there is a tricky
931 race condition: if we kill the build user before the
932 child has done its setuid() to the build user uid, then
933 it won't be killed, and we'll potentially lock up in
934 pid.wait(). So also send a conventional kill to the
935 child. */
936 ::kill(-pid, SIGKILL); /* ignore the result */
937 buildUser.kill();
938 pid.wait(true);
939 } else
940 pid.kill();
941
942 assert(pid == -1);
943 }
944
af73beeb
LC
945 /* If there was a build hook involved, remove it from the worker's
946 children. */
947 if (hook && hook->pid != -1) {
948 worker.childTerminated(hook->pid);
949 }
36457566
LC
950 hook.reset();
951}
952
953
f3ff1da4 954void DerivationGoal::timedOut()
36457566 955{
f3ff1da4 956 if (settings.printBuildTrace)
36457566
LC
957 printMsg(lvlError, format("@ build-failed %1% - timeout") % drvPath);
958 killChild();
f3ff1da4 959 done(BuildResult::TimedOut);
36457566
LC
960}
961
962
963void DerivationGoal::work()
964{
965 (this->*state)();
966}
967
968
969void DerivationGoal::addWantedOutputs(const StringSet & outputs)
970{
971 /* If we already want all outputs, there is nothing to do. */
972 if (wantedOutputs.empty()) return;
973
974 if (outputs.empty()) {
975 wantedOutputs.clear();
976 needRestart = true;
977 } else
978 foreach (StringSet::const_iterator, i, outputs)
979 if (wantedOutputs.find(*i) == wantedOutputs.end()) {
980 wantedOutputs.insert(*i);
981 needRestart = true;
982 }
983}
984
985
986void DerivationGoal::init()
987{
988 trace("init");
989
990 if (settings.readOnlyMode)
8327e733 991 throw Error(format("cannot build derivation `%1%' - no write access to the store") % drvPath);
36457566
LC
992
993 /* The first thing to do is to make sure that the derivation
994 exists. If it doesn't, it may be created through a
995 substitute. */
2bb04905
LC
996 if (buildMode == bmNormal && worker.store.isValidPath(drvPath)) {
997 haveDerivation();
998 return;
999 }
1000
36457566
LC
1001 addWaitee(worker.makeSubstitutionGoal(drvPath));
1002
1003 state = &DerivationGoal::haveDerivation;
1004}
1005
1006
1007void DerivationGoal::haveDerivation()
1008{
1009 trace("loading derivation");
1010
1011 if (nrFailed != 0) {
f3ff1da4
ED
1012 printMsg(lvlError, format("cannot build missing derivation ‘%1%’") % drvPath);
1013 done(BuildResult::MiscFailure);
36457566
LC
1014 return;
1015 }
1016
1017 /* `drvPath' should already be a root, but let's be on the safe
1018 side: if the user forgot to make it a root, we wouldn't want
1019 things being garbage collected while we're busy. */
1020 worker.store.addTempRoot(drvPath);
1021
1022 assert(worker.store.isValidPath(drvPath));
1023
1024 /* Get the derivation. */
1025 drv = derivationFromPath(worker.store, drvPath);
1026
1027 foreach (DerivationOutputs::iterator, i, drv.outputs)
1028 worker.store.addTempRoot(i->second.path);
1029
1030 /* Check what outputs paths are not already valid. */
1031 PathSet invalidOutputs = checkPathValidity(false, buildMode == bmRepair);
1032
1033 /* If they are all valid, then we're done. */
1034 if (invalidOutputs.size() == 0 && buildMode == bmNormal) {
f3ff1da4 1035 done(BuildResult::AlreadyValid);
36457566
LC
1036 return;
1037 }
1038
1039 /* Check whether any output previously failed to build. If so,
1040 don't bother. */
1041 foreach (PathSet::iterator, i, invalidOutputs)
1042 if (pathFailed(*i)) return;
1043
1044 /* We are first going to try to create the invalid output paths
1045 through substitutes. If that doesn't work, we'll build
1046 them. */
322eeb87 1047 if (settings.useSubstitutes && substitutesAllowed(drv))
36457566
LC
1048 foreach (PathSet::iterator, i, invalidOutputs)
1049 addWaitee(worker.makeSubstitutionGoal(*i, buildMode == bmRepair));
1050
1051 if (waitees.empty()) /* to prevent hang (no wake-up event) */
1052 outputsSubstituted();
1053 else
1054 state = &DerivationGoal::outputsSubstituted;
1055}
1056
1057
1058void DerivationGoal::outputsSubstituted()
1059{
1060 trace("all outputs substituted (maybe)");
1061
1062 if (nrFailed > 0 && nrFailed > nrNoSubstituters + nrIncompleteClosure && !settings.tryFallback)
1063 throw Error(format("some substitutes for the outputs of derivation `%1%' failed (usually happens due to networking issues); try `--fallback' to build derivation from source ") % drvPath);
1064
1065 /* If the substitutes form an incomplete closure, then we should
1066 build the dependencies of this derivation, but after that, we
1067 can still use the substitutes for this derivation itself. */
1068 if (nrIncompleteClosure > 0 && !retrySubstitution) retrySubstitution = true;
1069
1070 nrFailed = nrNoSubstituters = nrIncompleteClosure = 0;
1071
1072 if (needRestart) {
1073 needRestart = false;
1074 haveDerivation();
1075 return;
1076 }
1077
1078 unsigned int nrInvalid = checkPathValidity(false, buildMode == bmRepair).size();
1079 if (buildMode == bmNormal && nrInvalid == 0) {
f3ff1da4 1080 done(BuildResult::Substituted);
36457566
LC
1081 return;
1082 }
1083 if (buildMode == bmRepair && nrInvalid == 0) {
1084 repairClosure();
1085 return;
1086 }
1087 if (buildMode == bmCheck && nrInvalid > 0)
1088 throw Error(format("some outputs of `%1%' are not valid, so checking is not possible") % drvPath);
1089
1090 /* Otherwise, at least one of the output paths could not be
1091 produced using a substitute. So we have to build instead. */
1092
1093 /* Make sure checkPathValidity() from now on checks all
1094 outputs. */
1095 wantedOutputs = PathSet();
1096
1097 /* The inputs must be built before we can build this goal. */
1098 foreach (DerivationInputs::iterator, i, drv.inputDrvs)
1099 addWaitee(worker.makeDerivationGoal(i->first, i->second, buildMode == bmRepair ? bmRepair : bmNormal));
1100
1101 foreach (PathSet::iterator, i, drv.inputSrcs)
1102 addWaitee(worker.makeSubstitutionGoal(*i));
1103
1104 if (waitees.empty()) /* to prevent hang (no wake-up event) */
1105 inputsRealised();
1106 else
1107 state = &DerivationGoal::inputsRealised;
1108}
1109
1110
1111void DerivationGoal::repairClosure()
1112{
1113 /* If we're repairing, we now know that our own outputs are valid.
1114 Now check whether the other paths in the outputs closure are
1115 good. If not, then start derivation goals for the derivations
1116 that produced those outputs. */
1117
1118 /* Get the output closure. */
1119 PathSet outputClosure;
1a9574e3
ED
1120 foreach (DerivationOutputs::iterator, i, drv.outputs) {
1121 if (!wantOutput(i->first, wantedOutputs)) continue;
36457566 1122 computeFSClosure(worker.store, i->second.path, outputClosure);
1a9574e3 1123 }
36457566
LC
1124
1125 /* Filter out our own outputs (which we have already checked). */
1126 foreach (DerivationOutputs::iterator, i, drv.outputs)
1127 outputClosure.erase(i->second.path);
1128
1129 /* Get all dependencies of this derivation so that we know which
1130 derivation is responsible for which path in the output
1131 closure. */
1132 PathSet inputClosure;
1133 computeFSClosure(worker.store, drvPath, inputClosure);
1134 std::map<Path, Path> outputsToDrv;
1135 foreach (PathSet::iterator, i, inputClosure)
1136 if (isDerivation(*i)) {
1137 Derivation drv = derivationFromPath(worker.store, *i);
1138 foreach (DerivationOutputs::iterator, j, drv.outputs)
1139 outputsToDrv[j->second.path] = *i;
1140 }
1141
1142 /* Check each path (slow!). */
1143 PathSet broken;
1144 foreach (PathSet::iterator, i, outputClosure) {
1145 if (worker.store.pathContentsGood(*i)) continue;
1146 printMsg(lvlError, format("found corrupted or missing path `%1%' in the output closure of `%2%'") % *i % drvPath);
1147 Path drvPath2 = outputsToDrv[*i];
1148 if (drvPath2 == "")
1149 addWaitee(worker.makeSubstitutionGoal(*i, true));
1150 else
1151 addWaitee(worker.makeDerivationGoal(drvPath2, PathSet(), bmRepair));
1152 }
1153
1154 if (waitees.empty()) {
f3ff1da4 1155 done(BuildResult::AlreadyValid);
36457566
LC
1156 return;
1157 }
1158
1159 state = &DerivationGoal::closureRepaired;
1160}
1161
1162
1163void DerivationGoal::closureRepaired()
1164{
1165 trace("closure repaired");
1166 if (nrFailed > 0)
f3ff1da4
ED
1167 throw Error(format("some paths in the output closure of derivation ‘%1%’ could not be repaired") % drvPath);
1168 done(BuildResult::AlreadyValid);
36457566
LC
1169}
1170
1171
1172void DerivationGoal::inputsRealised()
1173{
1174 trace("all inputs realised");
1175
1176 if (nrFailed != 0) {
1177 printMsg(lvlError,
1178 format("cannot build derivation `%1%': %2% dependencies couldn't be built")
1179 % drvPath % nrFailed);
f3ff1da4 1180 done(BuildResult::DependencyFailed);
36457566
LC
1181 return;
1182 }
1183
1184 if (retrySubstitution) {
1185 haveDerivation();
1186 return;
1187 }
1188
1189 /* Gather information necessary for computing the closure and/or
1190 running the build hook. */
1191
1192 /* The outputs are referenceable paths. */
1193 foreach (DerivationOutputs::iterator, i, drv.outputs) {
1194 debug(format("building path `%1%'") % i->second.path);
1195 allPaths.insert(i->second.path);
1196 }
1197
1198 /* Determine the full set of input paths. */
1199
1200 /* First, the input derivations. */
1201 foreach (DerivationInputs::iterator, i, drv.inputDrvs) {
1202 /* Add the relevant output closures of the input derivation
1203 `*i' as input paths. Only add the closures of output paths
1204 that are specified as inputs. */
1205 assert(worker.store.isValidPath(i->first));
1206 Derivation inDrv = derivationFromPath(worker.store, i->first);
1207 foreach (StringSet::iterator, j, i->second)
1208 if (inDrv.outputs.find(*j) != inDrv.outputs.end())
1209 computeFSClosure(worker.store, inDrv.outputs[*j].path, inputPaths);
1210 else
1211 throw Error(
1212 format("derivation `%1%' requires non-existent output `%2%' from input derivation `%3%'")
1213 % drvPath % *j % i->first);
1214 }
1215
1216 /* Second, the input sources. */
1217 foreach (PathSet::iterator, i, drv.inputSrcs)
1218 computeFSClosure(worker.store, *i, inputPaths);
1219
1220 debug(format("added input paths %1%") % showPaths(inputPaths));
1221
1222 allPaths.insert(inputPaths.begin(), inputPaths.end());
1223
1224 /* Is this a fixed-output derivation? */
1225 fixedOutput = true;
b23b4d39
ED
1226 for (auto & i : drv.outputs)
1227 if (i.second.hash == "") fixedOutput = false;
1228
1229 /* Don't repeat fixed-output derivations since they're already
1230 verified by their output hash.*/
1231 nrRounds = fixedOutput ? 1 : settings.get("build-repeat", 0) + 1;
36457566
LC
1232
1233 /* Okay, try to build. Note that here we don't wait for a build
1234 slot to become available, since we don't need one if there is a
1235 build hook. */
1236 state = &DerivationGoal::tryToBuild;
1237 worker.wakeUp(shared_from_this());
1238}
1239
1240
322eeb87 1241static bool canBuildLocally(const string & platform)
36457566 1242{
322eeb87
LC
1243 return platform == settings.thisSystem
1244#if __linux__
1245 || (platform == "i686-linux" && settings.thisSystem == "x86_64-linux")
162825f9 1246 || (platform == "armhf-linux" && settings.thisSystem == "aarch64-linux")
322eeb87
LC
1247#endif
1248 ;
36457566
LC
1249}
1250
1251
322eeb87 1252static string get(const StringPairs & map, const string & key, const string & def = "")
36457566
LC
1253{
1254 StringPairs::const_iterator i = map.find(key);
322eeb87 1255 return i == map.end() ? def : i->second;
36457566
LC
1256}
1257
1258
322eeb87 1259bool willBuildLocally(const Derivation & drv)
36457566 1260{
322eeb87 1261 return get(drv.env, "preferLocalBuild") == "1" && canBuildLocally(drv.platform);
36457566
LC
1262}
1263
1264
322eeb87 1265bool substitutesAllowed(const Derivation & drv)
36457566 1266{
322eeb87 1267 return get(drv.env, "allowSubstitutes", "1") == "1";
36457566
LC
1268}
1269
1270
1271void DerivationGoal::tryToBuild()
1272{
1273 trace("trying to build");
1274
1275 /* Check for the possibility that some other goal in this process
1276 has locked the output since we checked in haveDerivation().
1277 (It can't happen between here and the lockPaths() call below
1278 because we're not allowing multi-threading.) If so, put this
1279 goal to sleep until another goal finishes, then try again. */
1280 foreach (DerivationOutputs::iterator, i, drv.outputs)
1281 if (pathIsLockedByMe(i->second.path)) {
1282 debug(format("putting derivation `%1%' to sleep because `%2%' is locked by another goal")
1283 % drvPath % i->second.path);
1284 worker.waitForAnyGoal(shared_from_this());
1285 return;
1286 }
1287
1288 /* Obtain locks on all output paths. The locks are automatically
8327e733 1289 released when we exit this function or the client crashes. If we
36457566
LC
1290 can't acquire the lock, then continue; hopefully some other
1291 goal can start a build, and if not, the main loop will sleep a
1292 few seconds and then retry this goal. */
322eeb87 1293 if (!outputLocks.lockPaths(outputPaths(drv), "", false)) {
36457566
LC
1294 worker.waitForAWhile(shared_from_this());
1295 return;
1296 }
1297
1298 /* Now check again whether the outputs are valid. This is because
1299 another process may have started building in parallel. After
1300 it has finished and released the locks, we can (and should)
1301 reuse its results. (Strictly speaking the first check can be
1302 omitted, but that would be less efficient.) Note that since we
1303 now hold the locks on the output paths, no other process can
1304 build this derivation, so no further checks are necessary. */
1305 validPaths = checkPathValidity(true, buildMode == bmRepair);
36457566
LC
1306 if (buildMode != bmCheck && validPaths.size() == drv.outputs.size()) {
1307 debug(format("skipping build of derivation `%1%', someone beat us to it") % drvPath);
1308 outputLocks.setDeletion(true);
f3ff1da4 1309 done(BuildResult::AlreadyValid);
36457566
LC
1310 return;
1311 }
1312
322eeb87 1313 missingPaths = outputPaths(drv);
36457566
LC
1314 if (buildMode != bmCheck)
1315 foreach (PathSet::iterator, i, validPaths) missingPaths.erase(*i);
1316
1317 /* If any of the outputs already exist but are not valid, delete
1318 them. */
1319 foreach (DerivationOutputs::iterator, i, drv.outputs) {
1320 Path path = i->second.path;
1321 if (worker.store.isValidPath(path)) continue;
1322 if (!pathExists(path)) continue;
1323 debug(format("removing invalid path `%1%'") % path);
1324 deletePath(path);
1325 }
1326
1327 /* Check again whether any output previously failed to build,
1328 because some other process may have tried and failed before we
1329 acquired the lock. */
1330 foreach (DerivationOutputs::iterator, i, drv.outputs)
1331 if (pathFailed(i->second.path)) return;
1332
1333 /* Don't do a remote build if the derivation has the attribute
1334 `preferLocalBuild' set. Also, check and repair modes are only
1335 supported for local builds. */
1336 bool buildLocally = buildMode != bmNormal || willBuildLocally(drv);
1337
1338 /* Is the build hook willing to accept this job? */
1339 if (!buildLocally) {
1340 switch (tryBuildHook()) {
1341 case rpAccept:
1342 /* Yes, it has started doing so. Wait until we get
1343 EOF from the hook. */
1344 state = &DerivationGoal::buildDone;
1345 return;
1346 case rpPostpone:
1347 /* Not now; wait until at least one child finishes or
1348 the wake-up timeout expires. */
1349 worker.waitForAWhile(shared_from_this());
1350 outputLocks.unlock();
1351 return;
1352 case rpDecline:
1353 /* We should do it ourselves. */
1354 break;
1355 }
1356 }
1357
1358 /* Make sure that we are allowed to start a build. If this
1359 derivation prefers to be done locally, do it even if
1360 maxBuildJobs is 0. */
1361 unsigned int curBuilds = worker.getNrLocalBuilds();
1362 if (curBuilds >= settings.maxBuildJobs && !(buildLocally && curBuilds == 0)) {
1363 worker.waitForBuildSlot(shared_from_this());
1364 outputLocks.unlock();
1365 return;
1366 }
1367
1368 try {
1369
1370 /* Okay, we have to build. */
1371 startBuilder();
1372
1373 } catch (BuildError & e) {
1374 printMsg(lvlError, e.msg());
1375 outputLocks.unlock();
1376 buildUser.release();
1377 if (settings.printBuildTrace)
1378 printMsg(lvlError, format("@ build-failed %1% - %2% %3%")
1379 % drvPath % 0 % e.msg());
1380 worker.permanentFailure = true;
f3ff1da4 1381 done(BuildResult::InputRejected, e.msg());
36457566
LC
1382 return;
1383 }
1384
1385 /* This state will be reached when we get EOF on the child's
1386 log pipe. */
1387 state = &DerivationGoal::buildDone;
1388}
1389
1390
1391void replaceValidPath(const Path & storePath, const Path tmpPath)
1392{
1393 /* We can't atomically replace storePath (the original) with
1394 tmpPath (the replacement), so we have to move it out of the
1395 way first. We'd better not be interrupted here, because if
1396 we're repairing (say) Glibc, we end up with a broken system. */
1397 Path oldPath = (format("%1%.old-%2%-%3%") % storePath % getpid() % rand()).str();
1398 if (pathExists(storePath))
1399 rename(storePath.c_str(), oldPath.c_str());
1400 if (rename(tmpPath.c_str(), storePath.c_str()) == -1)
1401 throw SysError(format("moving `%1%' to `%2%'") % tmpPath % storePath);
1402 if (pathExists(oldPath))
1403 deletePath(oldPath);
1404}
1405
1406
b23b4d39
ED
1407MakeError(NotDeterministic, BuildError)
1408
1409
36457566
LC
1410void DerivationGoal::buildDone()
1411{
1412 trace("build done");
1413
1414 /* Since we got an EOF on the logger pipe, the builder is presumed
1415 to have terminated. In fact, the builder could also have
1416 simply have closed its end of the pipe --- just don't do that
1417 :-) */
1418 int status;
1419 pid_t savedPid;
1420 if (hook) {
1421 savedPid = hook->pid;
1422 status = hook->pid.wait(true);
1423 } else {
1424 /* !!! this could block! security problem! solution: kill the
1425 child */
1426 savedPid = pid;
1427 status = pid.wait(true);
1428 }
1429
1430 debug(format("builder process for `%1%' finished") % drvPath);
1431
1432 /* So the child is gone now. */
1433 worker.childTerminated(savedPid);
1434
1435 /* Close the read side of the logger pipe. */
1436 if (hook) {
1437 hook->builderOut.readSide.close();
1438 hook->fromHook.readSide.close();
1439 }
1440 else builderOut.readSide.close();
1441
1442 /* Close the log file. */
1443 closeLogFile();
1444
1445 /* When running under a build user, make sure that all processes
1446 running under that uid are gone. This is to prevent a
1447 malicious user from leaving behind a process that keeps files
1448 open and modifies them after they have been chown'ed to
1449 root. */
1450 if (buildUser.enabled()) buildUser.kill();
1451
1452 bool diskFull = false;
1453
1454 try {
1455
1456 /* Check the exit status. */
1457 if (!statusOk(status)) {
1458
1459 /* Heuristically check whether the build failure may have
1460 been caused by a disk full condition. We have no way
1461 of knowing whether the build actually got an ENOSPC.
1462 So instead, check if the disk is (nearly) full now. If
1463 so, we don't mark this build as a permanent failure. */
1464#if HAVE_STATVFS
1465 unsigned long long required = 8ULL * 1024 * 1024; // FIXME: make configurable
1466 struct statvfs st;
1467 if (statvfs(settings.nixStore.c_str(), &st) == 0 &&
1468 (unsigned long long) st.f_bavail * st.f_bsize < required)
1469 diskFull = true;
1470 if (statvfs(tmpDir.c_str(), &st) == 0 &&
1471 (unsigned long long) st.f_bavail * st.f_bsize < required)
1472 diskFull = true;
1473#endif
1474
1475 deleteTmpDir(false);
1476
1477 /* Move paths out of the chroot for easier debugging of
1478 build failures. */
1479 if (useChroot && buildMode == bmNormal)
1480 foreach (PathSet::iterator, i, missingPaths)
1481 if (pathExists(chrootRootDir + *i))
1482 rename((chrootRootDir + *i).c_str(), i->c_str());
1483
36457566
LC
1484 if (diskFull)
1485 printMsg(lvlError, "note: build failure may have been caused by lack of free disk space");
1486
1487 throw BuildError(format("builder for `%1%' %2%")
1488 % drvPath % statusToString(status));
1489 }
1490
1491 /* Compute the FS closure of the outputs and register them as
1492 being valid. */
1493 registerOutputs();
1494
1495 if (buildMode == bmCheck) {
f3ff1da4 1496 done(BuildResult::Built);
36457566
LC
1497 return;
1498 }
1499
1500 /* Delete unused redirected outputs (when doing hash rewriting). */
1501 foreach (RedirectedOutputs::iterator, i, redirectedOutputs)
1502 if (pathExists(i->second)) deletePath(i->second);
1503
1504 /* Delete the chroot (if we were using one). */
1505 autoDelChroot.reset(); /* this runs the destructor */
1506
1507 deleteTmpDir(true);
1508
b23b4d39
ED
1509 /* Repeat the build if necessary. */
1510 if (curRound++ < nrRounds) {
1511 outputLocks.unlock();
1512 buildUser.release();
1513 state = &DerivationGoal::tryToBuild;
1514 worker.wakeUp(shared_from_this());
1515 return;
1516 }
1517
36457566
LC
1518 /* It is now safe to delete the lock files, since all future
1519 lockers will see that the output paths are valid; they will
1520 not create new lock files with the same names as the old
1521 (unlinked) lock files. */
1522 outputLocks.setDeletion(true);
1523 outputLocks.unlock();
1524
1525 } catch (BuildError & e) {
2bb04905
LC
1526 if (!hook)
1527 printMsg(lvlError, e.msg());
36457566
LC
1528 outputLocks.unlock();
1529 buildUser.release();
1530
f3ff1da4
ED
1531 BuildResult::Status st = BuildResult::MiscFailure;
1532
2bb04905
LC
1533 if (hook && WIFEXITED(status) && WEXITSTATUS(status) == 101) {
1534 if (settings.printBuildTrace)
1535 printMsg(lvlError, format("@ build-failed %1% - timeout") % drvPath);
f3ff1da4 1536 st = BuildResult::TimedOut;
2bb04905 1537 }
36457566 1538
2bb04905
LC
1539 else if (hook && (!WIFEXITED(status) || WEXITSTATUS(status) != 100)) {
1540 if (settings.printBuildTrace)
36457566
LC
1541 printMsg(lvlError, format("@ hook-failed %1% - %2% %3%")
1542 % drvPath % status % e.msg());
2bb04905
LC
1543 }
1544
1545 else {
1546 if (settings.printBuildTrace)
36457566
LC
1547 printMsg(lvlError, format("@ build-failed %1% - %2% %3%")
1548 % drvPath % 1 % e.msg());
f3ff1da4
ED
1549
1550 st =
1551 statusOk(status) ? BuildResult::OutputRejected :
1552 fixedOutput || diskFull ? BuildResult::TransientFailure :
1553 BuildResult::PermanentFailure;
2bb04905
LC
1554
1555 /* Register the outputs of this build as "failed" so we
1556 won't try to build them again (negative caching).
1557 However, don't do this for fixed-output derivations,
1558 since they're likely to fail for transient reasons
1559 (e.g., fetchurl not being able to access the network).
1560 Hook errors (like communication problems with the
1561 remote machine) shouldn't be cached either. */
1562 if (settings.cacheFailure && !fixedOutput && !diskFull)
1563 foreach (DerivationOutputs::iterator, i, drv.outputs)
1564 worker.store.registerFailedPath(i->second.path);
36457566
LC
1565 }
1566
f3ff1da4 1567 done(st, e.msg());
36457566
LC
1568 return;
1569 }
1570
1571 /* Release the build user, if applicable. */
1572 buildUser.release();
1573
1574 if (settings.printBuildTrace)
1575 printMsg(lvlError, format("@ build-succeeded %1% -") % drvPath);
1576
f3ff1da4 1577 done(BuildResult::Built);
36457566
LC
1578}
1579
1580
1581HookReply DerivationGoal::tryBuildHook()
1582{
bc69ea2d 1583 if (!settings.useBuildHook) return rpDecline;
36457566
LC
1584
1585 if (!worker.hook)
1586 worker.hook = std::shared_ptr<HookInstance>(new HookInstance);
1587
1588 /* Tell the hook about system features (beyond the system type)
1589 required from the build machine. (The hook could parse the
1590 drv file itself, but this is easier.) */
1591 Strings features = tokenizeString<Strings>(get(drv.env, "requiredSystemFeatures"));
1592 foreach (Strings::iterator, i, features) checkStoreName(*i); /* !!! abuse */
1593
1594 /* Send the request to the hook. */
1595 writeLine(worker.hook->toHook.writeSide, (format("%1% %2% %3% %4%")
1596 % (worker.getNrLocalBuilds() < settings.maxBuildJobs ? "1" : "0")
1597 % drv.platform % drvPath % concatStringsSep(",", features)).str());
1598
1599 /* Read the first line of input, which should be a word indicating
1600 whether the hook wishes to perform the build. */
1601 string reply;
1602 while (true) {
1603 string s = readLine(worker.hook->fromHook.readSide);
1604 if (string(s, 0, 2) == "# ") {
1605 reply = string(s, 2);
1606 break;
1607 }
1608 s += "\n";
1609 writeToStderr(s);
1610 }
1611
1612 debug(format("hook reply is `%1%'") % reply);
1613
1614 if (reply == "decline" || reply == "postpone")
1615 return reply == "decline" ? rpDecline : rpPostpone;
1616 else if (reply != "accept")
1617 throw Error(format("bad hook reply `%1%'") % reply);
1618
1619 printMsg(lvlTalkative, format("using hook to build path(s) %1%") % showPaths(missingPaths));
1620
1621 hook = worker.hook;
1622 worker.hook.reset();
1623
1624 /* Tell the hook all the inputs that have to be copied to the
1625 remote system. This unfortunately has to contain the entire
1626 derivation closure to ensure that the validity invariant holds
1627 on the remote system. (I.e., it's unfortunate that we have to
1628 list it since the remote system *probably* already has it.) */
1629 PathSet allInputs;
1630 allInputs.insert(inputPaths.begin(), inputPaths.end());
1631 computeFSClosure(worker.store, drvPath, allInputs);
1632
1633 string s;
1634 foreach (PathSet::iterator, i, allInputs) { s += *i; s += ' '; }
1635 writeLine(hook->toHook.writeSide, s);
1636
1637 /* Tell the hooks the missing outputs that have to be copied back
1638 from the remote system. */
1639 s = "";
1640 foreach (PathSet::iterator, i, missingPaths) { s += *i; s += ' '; }
1641 writeLine(hook->toHook.writeSide, s);
1642
1643 hook->toHook.writeSide.close();
1644
1645 /* Create the log file and pipe. */
1646 Path logFile = openLogFile();
1647
1648 set<int> fds;
1649 fds.insert(hook->fromHook.readSide);
1650 fds.insert(hook->builderOut.readSide);
ada9a19a 1651 worker.childStarted(shared_from_this(), hook->pid, fds, false, true);
36457566
LC
1652
1653 if (settings.printBuildTrace)
6ef61cc4
LC
1654 printMsg(lvlError, format("@ build-started %1% - %2% %3% %4%")
1655 % drvPath % drv.platform % logFile % hook->pid);
36457566
LC
1656
1657 return rpAccept;
1658}
1659
1660
1661void chmod_(const Path & path, mode_t mode)
1662{
1663 if (chmod(path.c_str(), mode) == -1)
1664 throw SysError(format("setting permissions on `%1%'") % path);
1665}
1666
1667
1668int childEntry(void * arg)
1669{
54c260e6 1670 ((DerivationGoal *) arg)->runChild();
36457566
LC
1671 return 1;
1672}
1673
1674
1675void DerivationGoal::startBuilder()
1676{
b23b4d39
ED
1677 auto f = format(
1678 buildMode == bmRepair ? "repairing path(s) %1%" :
1679 buildMode == bmCheck ? "checking path(s) %1%" :
1680 nrRounds > 1 ? "building path(s) %1% (round %2%/%3%)" :
1681 "building path(s) %1%");
1682 f.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit);
1683 startNest(nest, lvlInfo, f % showPaths(missingPaths) % curRound % nrRounds);
36457566 1684
8ecc3c6c
LC
1685 /* Note: built-in builders are *not* running in a chroot environment so
1686 that we can easily implement them in Guile without having it as a
1687 derivation input (they are running under a separate build user,
1688 though). */
1689 useChroot = settings.useChroot && !isBuiltin(drv);
cb960102 1690
36457566 1691 /* Construct the environment passed to the builder. */
b23b4d39 1692 env.clear();
36457566
LC
1693
1694 /* Most shells initialise PATH to some default (/bin:/usr/bin:...) when
1695 PATH is not set. We don't want this, so we fill it in with some dummy
1696 value. */
1697 env["PATH"] = "/path-not-set";
1698
1699 /* Set HOME to a non-existing path to prevent certain programs from using
1700 /etc/passwd (or NIS, or whatever) to locate the home directory (for
1701 example, wget looks for ~/.wgetrc). I.e., these tools use /etc/passwd
1702 if HOME is not set, but they will just assume that the settings file
1703 they are looking for does not exist if HOME is set but points to some
1704 non-existing path. */
1705 Path homeDir = "/homeless-shelter";
1706 env["HOME"] = homeDir;
1707
8327e733 1708 /* Tell the builder where the store is. Usually they
36457566
LC
1709 shouldn't care, but this is useful for purity checking (e.g.,
1710 the compiler or linker might only want to accept paths to files
1711 in the store or in the build directory). */
1712 env["NIX_STORE"] = settings.nixStore;
1713
1714 /* The maximum number of cores to utilize for parallel building. */
1715 env["NIX_BUILD_CORES"] = (format("%d") % settings.buildCores).str();
1716
1717 /* Add all bindings specified in the derivation. */
1718 foreach (StringPairs::iterator, i, drv.env)
1719 env[i->first] = i->second;
1720
1721 /* Create a temporary directory where the build will take
1722 place. */
cb960102 1723 auto drvName = storePathToName(drvPath);
7a57c96a 1724 tmpDir = createTempDir("", "guix-build-" + drvName, false, false, 0700);
cb960102
ED
1725
1726 /* In a sandbox, for determinism, always use the same temporary
1727 directory. */
4078fa8f 1728 tmpDirInSandbox = useChroot ? canonPath("/tmp", true) + "/guix-build-" + drvName + "-0" : tmpDir;
36457566
LC
1729
1730 /* For convenience, set an environment pointing to the top build
1731 directory. */
cb960102 1732 env["NIX_BUILD_TOP"] = tmpDirInSandbox;
36457566
LC
1733
1734 /* Also set TMPDIR and variants to point to this directory. */
cb960102 1735 env["TMPDIR"] = env["TEMPDIR"] = env["TMP"] = env["TEMP"] = tmpDirInSandbox;
36457566
LC
1736
1737 /* Explicitly set PWD to prevent problems with chroot builds. In
1738 particular, dietlibc cannot figure out the cwd because the
1739 inode of the current directory doesn't appear in .. (because
1740 getdents returns the inode of the mount point). */
cb960102 1741 env["PWD"] = tmpDirInSandbox;
36457566
LC
1742
1743 /* Compatibility hack with Nix <= 0.7: if this is a fixed-output
1744 derivation, tell the builder, so that for instance `fetchurl'
1745 can skip checking the output. On older Nixes, this environment
1746 variable won't be set, so `fetchurl' will do the check. */
1747 if (fixedOutput) env["NIX_OUTPUT_CHECKED"] = "1";
1748
1749 /* *Only* if this is a fixed-output derivation, propagate the
1750 values of the environment variables specified in the
1751 `impureEnvVars' attribute to the builder. This allows for
1752 instance environment variables for proxy configuration such as
1753 `http_proxy' to be easily passed to downloaders like
1754 `fetchurl'. Passing such environment variables from the caller
1755 to the builder is generally impure, but the output of
1756 fixed-output derivations is by definition pure (since we
1757 already know the cryptographic hash of the output). */
1758 if (fixedOutput) {
1759 Strings varNames = tokenizeString<Strings>(get(drv.env, "impureEnvVars"));
1760 foreach (Strings::iterator, i, varNames) env[*i] = getEnv(*i);
1761 }
1762
1763 /* The `exportReferencesGraph' feature allows the references graph
1764 to be passed to a builder. This attribute should be a list of
1765 pairs [name1 path1 name2 path2 ...]. The references graph of
1766 each `pathN' will be stored in a text file `nameN' in the
1767 temporary build directory. The text files have the format used
1768 by `nix-store --register-validity'. However, the deriver
1769 fields are left empty. */
1770 string s = get(drv.env, "exportReferencesGraph");
1771 Strings ss = tokenizeString<Strings>(s);
1772 if (ss.size() % 2 != 0)
1773 throw BuildError(format("odd number of tokens in `exportReferencesGraph': `%1%'") % s);
1774 for (Strings::iterator i = ss.begin(); i != ss.end(); ) {
1775 string fileName = *i++;
1776 checkStoreName(fileName); /* !!! abuse of this function */
1777
1778 /* Check that the store path is valid. */
1779 Path storePath = *i++;
1780 if (!isInStore(storePath))
1781 throw BuildError(format("`exportReferencesGraph' contains a non-store path `%1%'")
1782 % storePath);
1783 storePath = toStorePath(storePath);
1784 if (!worker.store.isValidPath(storePath))
1785 throw BuildError(format("`exportReferencesGraph' contains an invalid path `%1%'")
1786 % storePath);
1787
1788 /* If there are derivations in the graph, then include their
1789 outputs as well. This is useful if you want to do things
1790 like passing all build-time dependencies of some path to a
1791 derivation that builds a NixOS DVD image. */
1792 PathSet paths, paths2;
1793 computeFSClosure(worker.store, storePath, paths);
1794 paths2 = paths;
1795
1796 foreach (PathSet::iterator, j, paths2) {
1797 if (isDerivation(*j)) {
1798 Derivation drv = derivationFromPath(worker.store, *j);
1799 foreach (DerivationOutputs::iterator, k, drv.outputs)
1800 computeFSClosure(worker.store, k->second.path, paths);
1801 }
1802 }
1803
1804 /* Write closure info to `fileName'. */
1805 writeFile(tmpDir + "/" + fileName,
1806 worker.store.makeValidityRegistration(paths, false, false));
1807 }
1808
1809
1810 /* If `build-users-group' is not empty, then we have to build as
1811 one of the members of that group. */
1812 if (settings.buildUsersGroup != "") {
1813 buildUser.acquire();
1814 assert(buildUser.getUID() != 0);
1815 assert(buildUser.getGID() != 0);
1816
1817 /* Make sure that no other processes are executing under this
1818 uid. */
1819 buildUser.kill();
1820
1821 /* Change ownership of the temporary build directory. */
1822 if (chown(tmpDir.c_str(), buildUser.getUID(), buildUser.getGID()) == -1)
54c260e6
LC
1823 throw SysError(format("cannot change ownership of '%1%'") % tmpDir);
1824 }
36457566 1825
36457566
LC
1826 if (useChroot) {
1827#if CHROOT_ENABLED
1828 /* Create a temporary directory in which we set up the chroot
8327e733 1829 environment using bind-mounts. We put it in the store
36457566 1830 to ensure that we can create hard-links to non-directory
8327e733 1831 inputs in the fake store in the chroot (see below). */
36457566
LC
1832 chrootRootDir = drvPath + ".chroot";
1833 if (pathExists(chrootRootDir)) deletePath(chrootRootDir);
1834
1835 /* Clean up the chroot directory automatically. */
1836 autoDelChroot = std::shared_ptr<AutoDelete>(new AutoDelete(chrootRootDir));
1837
1838 printMsg(lvlChatty, format("setting up chroot environment in `%1%'") % chrootRootDir);
1839
54c260e6
LC
1840 if (mkdir(chrootRootDir.c_str(), 0750) == -1)
1841 throw SysError(format("cannot create ‘%1%’") % chrootRootDir);
1842
1843 if (chown(chrootRootDir.c_str(), 0, buildUser.getGID()) == -1)
1844 throw SysError(format("cannot change ownership of ‘%1%’") % chrootRootDir);
1845
36457566
LC
1846 /* Create a writable /tmp in the chroot. Many builders need
1847 this. (Of course they should really respect $TMPDIR
1848 instead.) */
1849 Path chrootTmpDir = chrootRootDir + "/tmp";
1850 createDirs(chrootTmpDir);
1851 chmod_(chrootTmpDir, 01777);
1852
1853 /* Create a /etc/passwd with entries for the build user and the
1854 nobody account. The latter is kind of a hack to support
1855 Samba-in-QEMU. */
1856 createDirs(chrootRootDir + "/etc");
1857
1858 writeFile(chrootRootDir + "/etc/passwd",
1859 (format(
1860 "nixbld:x:%1%:%2%:Nix build user:/:/noshell\n"
1861 "nobody:x:65534:65534:Nobody:/:/noshell\n")
1862 % (buildUser.enabled() ? buildUser.getUID() : getuid())
1863 % (buildUser.enabled() ? buildUser.getGID() : getgid())).str());
1864
1865 /* Declare the build user's group so that programs get a consistent
1866 view of the system (e.g., "id -gn"). */
1867 writeFile(chrootRootDir + "/etc/group",
1868 (format("nixbld:!:%1%:\n")
1869 % (buildUser.enabled() ? buildUser.getGID() : getgid())).str());
1870
1871 /* Create /etc/hosts with localhost entry. */
54c260e6
LC
1872 if (!fixedOutput)
1873 writeFile(chrootRootDir + "/etc/hosts", "127.0.0.1 localhost\n");
36457566
LC
1874
1875 /* Bind-mount a user-configurable set of directories from the
1876 host file system. */
2bb04905
LC
1877 PathSet dirs = tokenizeString<StringSet>(settings.get("build-chroot-dirs", string(DEFAULT_CHROOT_DIRS)));
1878 PathSet dirs2 = tokenizeString<StringSet>(settings.get("build-extra-chroot-dirs", string("")));
1879 dirs.insert(dirs2.begin(), dirs2.end());
1880 for (auto & i : dirs) {
1881 size_t p = i.find('=');
36457566 1882 if (p == string::npos)
2bb04905 1883 dirsInChroot[i] = i;
36457566 1884 else
2bb04905 1885 dirsInChroot[string(i, 0, p)] = string(i, p + 1);
36457566 1886 }
cb960102 1887 dirsInChroot[tmpDirInSandbox] = tmpDir;
36457566
LC
1888
1889 /* Make the closure of the inputs available in the chroot,
8327e733 1890 rather than the whole store. This prevents any access
36457566
LC
1891 to undeclared dependencies. Directories are bind-mounted,
1892 while other inputs are hard-linked (since only directories
1893 can be bind-mounted). !!! As an extra security
8327e733 1894 precaution, make the fake store only writable by the
36457566 1895 build user. */
54c260e6
LC
1896 Path chrootStoreDir = chrootRootDir + settings.nixStore;
1897 createDirs(chrootStoreDir);
1898 chmod_(chrootStoreDir, 01775);
1899
1900 if (chown(chrootStoreDir.c_str(), 0, buildUser.getGID()) == -1)
1901 throw SysError(format("cannot change ownership of ‘%1%’") % chrootStoreDir);
36457566
LC
1902
1903 foreach (PathSet::iterator, i, inputPaths) {
1904 struct stat st;
1905 if (lstat(i->c_str(), &st))
1906 throw SysError(format("getting attributes of path `%1%'") % *i);
1907 if (S_ISDIR(st.st_mode))
1908 dirsInChroot[*i] = *i;
1909 else {
1910 Path p = chrootRootDir + *i;
1911 if (link(i->c_str(), p.c_str()) == -1) {
1912 /* Hard-linking fails if we exceed the maximum
1913 link count on a file (e.g. 32000 of ext3),
1914 which is quite possible after a `nix-store
1915 --optimise'. */
1916 if (errno != EMLINK)
1917 throw SysError(format("linking `%1%' to `%2%'") % p % *i);
1918 StringSink sink;
1919 dumpPath(*i, sink);
1920 StringSource source(sink.s);
1921 restorePath(p, source);
1922 }
1923
1924 regularInputPaths.insert(*i);
1925 }
1926 }
1927
60c7c364
ED
1928 /* If we're repairing, checking or rebuilding part of a
1929 multiple-outputs derivation, it's possible that we're
36457566
LC
1930 rebuilding a path that is in settings.dirsInChroot
1931 (typically the dependencies of /bin/sh). Throw them
1932 out. */
60c7c364
ED
1933 for (auto & i : drv.outputs)
1934 dirsInChroot.erase(i.second.path);
36457566
LC
1935
1936#else
1937 throw Error("chroot builds are not supported on this platform");
1938#endif
1939 }
1940
1941 else {
1942
1943 if (pathExists(homeDir))
1944 throw Error(format("directory `%1%' exists; please remove it") % homeDir);
1945
1946 /* We're not doing a chroot build, but we have some valid
1947 output paths. Since we can't just overwrite or delete
1948 them, we have to do hash rewriting: i.e. in the
1949 environment/arguments passed to the build, we replace the
1950 hashes of the valid outputs with unique dummy strings;
1951 after the build, we discard the redirected outputs
1952 corresponding to the valid outputs, and rewrite the
1953 contents of the new outputs to replace the dummy strings
1954 with the actual hashes. */
1955 if (validPaths.size() > 0)
1956 foreach (PathSet::iterator, i, validPaths)
1957 addHashRewrite(*i);
1958
1959 /* If we're repairing, then we don't want to delete the
1960 corrupt outputs in advance. So rewrite them as well. */
1961 if (buildMode == bmRepair)
1962 foreach (PathSet::iterator, i, missingPaths)
1963 if (worker.store.isValidPath(*i) && pathExists(*i)) {
1964 addHashRewrite(*i);
1965 redirectedBadOutputs.insert(*i);
1966 }
1967 }
1968
1969
1970 /* Run the builder. */
1971 printMsg(lvlChatty, format("executing builder `%1%'") % drv.builder);
1972
1973 /* Create the log file. */
1974 Path logFile = openLogFile();
1975
1976 /* Create a pipe to get the output of the builder. */
1977 builderOut.create();
1978
1979 /* Fork a child to build the package. Note that while we
1980 currently use forks to run and wait for the children, it
1981 shouldn't be hard to use threads for this on systems where
1982 fork() is unavailable or inefficient.
1983
1984 If we're building in a chroot, then also set up private
1985 namespaces for the build:
1986
1987 - The PID namespace causes the build to start as PID 1.
1988 Processes outside of the chroot are not visible to those on
1989 the inside, but processes inside the chroot are visible from
1990 the outside (though with different PIDs).
1991
1992 - The private mount namespace ensures that all the bind mounts
1993 we do will only show up in this process and its children, and
1994 will disappear automatically when we're done.
1995
1996 - The private network namespace ensures that the builder cannot
1997 talk to the outside world (or vice versa). It only has a
1998 private loopback interface.
1999
2000 - The IPC namespace prevents the builder from communicating
2001 with outside processes using SysV IPC mechanisms (shared
2002 memory, message queues, semaphores). It also ensures that
2003 all IPC objects are destroyed when the builder exits.
2004
2005 - The UTS namespace ensures that builders see a hostname of
2006 localhost rather than the actual hostname.
2007 */
2008#if CHROOT_ENABLED
2009 if (useChroot) {
54c260e6
LC
2010 char stack[32 * 1024];
2011 int flags = CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWUTS | SIGCHLD;
2012 if (!fixedOutput) flags |= CLONE_NEWNET;
a1aa5dab
MW
2013 /* Ensure proper alignment on the stack. On aarch64, it has to be 16
2014 bytes. */
2015 pid = clone(childEntry,
2016 (char *)(((uintptr_t)stack + sizeof(stack) - 8) & ~(uintptr_t)0xf),
2017 flags, this);
54c260e6
LC
2018 if (pid == -1)
2019 throw SysError("cloning builder process");
36457566
LC
2020 } else
2021#endif
2022 {
2023 pid = fork();
54c260e6 2024 if (pid == 0) runChild();
36457566
LC
2025 }
2026
2027 if (pid == -1) throw SysError("unable to fork");
2028
2029 /* parent */
2030 pid.setSeparatePG(true);
2031 builderOut.writeSide.close();
2032 worker.childStarted(shared_from_this(), pid,
2033 singleton<set<int> >(builderOut.readSide), true, true);
2034
2bb04905
LC
2035 /* Check if setting up the build environment failed. */
2036 string msg = readLine(builderOut.readSide);
2037 if (!msg.empty()) throw Error(msg);
2038
36457566 2039 if (settings.printBuildTrace) {
6ef61cc4
LC
2040 printMsg(lvlError, format("@ build-started %1% - %2% %3% %4%")
2041 % drvPath % drv.platform % logFile % pid);
36457566 2042 }
2bb04905 2043
36457566
LC
2044}
2045
2046
54c260e6 2047void DerivationGoal::runChild()
36457566
LC
2048{
2049 /* Warning: in the child we should absolutely not make any SQLite
2050 calls! */
2051
36457566
LC
2052 try { /* child */
2053
2bb04905
LC
2054 _writeToStderr = 0;
2055
2056 restoreAffinity();
2057
2058 commonChildInit(builderOut);
2059
36457566 2060#if CHROOT_ENABLED
8ecc3c6c 2061 if (useChroot) {
36457566
LC
2062 /* Initialise the loopback interface. */
2063 AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP));
2064 if (fd == -1) throw SysError("cannot open IP socket");
2065
2066 struct ifreq ifr;
2067 strcpy(ifr.ifr_name, "lo");
2068 ifr.ifr_flags = IFF_UP | IFF_LOOPBACK | IFF_RUNNING;
2069 if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1)
2070 throw SysError("cannot set loopback interface flags");
2071
2072 fd.close();
2073
2074 /* Set the hostname etc. to fixed values. */
2075 char hostname[] = "localhost";
54c260e6
LC
2076 if (sethostname(hostname, sizeof(hostname)) == -1)
2077 throw SysError("cannot set host name");
36457566 2078 char domainname[] = "(none)"; // kernel default
54c260e6
LC
2079 if (setdomainname(domainname, sizeof(domainname)) == -1)
2080 throw SysError("cannot set domain name");
36457566
LC
2081
2082 /* Make all filesystems private. This is necessary
2083 because subtrees may have been mounted as "shared"
2084 (MS_SHARED). (Systemd does this, for instance.) Even
2085 though we have a private mount namespace, mounting
2086 filesystems on top of a shared subtree still propagates
2087 outside of the namespace. Making a subtree private is
2088 local to the namespace, though, so setting MS_PRIVATE
2089 does not affect the outside world. */
842e0e43
JT
2090 if (mount(0, "/", 0, MS_REC|MS_PRIVATE, 0) == -1) {
2091 throw SysError("unable to make ‘/’ private mount");
36457566
LC
2092 }
2093
54c260e6
LC
2094 /* Bind-mount chroot directory to itself, to treat it as a
2095 different filesystem from /, as needed for pivot_root. */
2096 if (mount(chrootRootDir.c_str(), chrootRootDir.c_str(), 0, MS_BIND, 0) == -1)
2097 throw SysError(format("unable to bind mount ‘%1%’") % chrootRootDir);
2098
36457566
LC
2099 /* Set up a nearly empty /dev, unless the user asked to
2100 bind-mount the host /dev. */
54c260e6 2101 Strings ss;
36457566
LC
2102 if (dirsInChroot.find("/dev") == dirsInChroot.end()) {
2103 createDirs(chrootRootDir + "/dev/shm");
2104 createDirs(chrootRootDir + "/dev/pts");
36457566
LC
2105 ss.push_back("/dev/full");
2106#ifdef __linux__
2107 if (pathExists("/dev/kvm"))
2108 ss.push_back("/dev/kvm");
2109#endif
2110 ss.push_back("/dev/null");
2111 ss.push_back("/dev/random");
2112 ss.push_back("/dev/tty");
2113 ss.push_back("/dev/urandom");
2114 ss.push_back("/dev/zero");
36457566
LC
2115 createSymlink("/proc/self/fd", chrootRootDir + "/dev/fd");
2116 createSymlink("/proc/self/fd/0", chrootRootDir + "/dev/stdin");
2117 createSymlink("/proc/self/fd/1", chrootRootDir + "/dev/stdout");
2118 createSymlink("/proc/self/fd/2", chrootRootDir + "/dev/stderr");
2119 }
2120
54c260e6
LC
2121 /* Fixed-output derivations typically need to access the
2122 network, so give them access to /etc/resolv.conf and so
2123 on. */
2124 if (fixedOutput) {
2125 ss.push_back("/etc/resolv.conf");
2126 ss.push_back("/etc/nsswitch.conf");
2127 ss.push_back("/etc/services");
2128 ss.push_back("/etc/hosts");
2129 }
2130
2131 for (auto & i : ss) dirsInChroot[i] = i;
2132
36457566
LC
2133 /* Bind-mount all the directories from the "host"
2134 filesystem that we want in the chroot
2135 environment. */
2136 foreach (DirsInChroot::iterator, i, dirsInChroot) {
2137 struct stat st;
2138 Path source = i->second;
2139 Path target = chrootRootDir + i->first;
2140 if (source == "/proc") continue; // backwards compatibility
2141 debug(format("bind mounting `%1%' to `%2%'") % source % target);
2142 if (stat(source.c_str(), &st) == -1)
2143 throw SysError(format("getting attributes of path `%1%'") % source);
2144 if (S_ISDIR(st.st_mode))
2145 createDirs(target);
2146 else {
2147 createDirs(dirOf(target));
2148 writeFile(target, "");
2149 }
2150 if (mount(source.c_str(), target.c_str(), "", MS_BIND, 0) == -1)
2151 throw SysError(format("bind mount from `%1%' to `%2%' failed") % source % target);
2152 }
2153
2154 /* Bind a new instance of procfs on /proc to reflect our
2155 private PID namespace. */
2156 createDirs(chrootRootDir + "/proc");
2157 if (mount("none", (chrootRootDir + "/proc").c_str(), "proc", 0, 0) == -1)
2158 throw SysError("mounting /proc");
2159
2160 /* Mount a new tmpfs on /dev/shm to ensure that whatever
2161 the builder puts in /dev/shm is cleaned up automatically. */
2162 if (pathExists("/dev/shm") && mount("none", (chrootRootDir + "/dev/shm").c_str(), "tmpfs", 0, 0) == -1)
2163 throw SysError("mounting /dev/shm");
2164
2165 /* Mount a new devpts on /dev/pts. Note that this
2166 requires the kernel to be compiled with
2167 CONFIG_DEVPTS_MULTIPLE_INSTANCES=y (which is the case
2168 if /dev/ptx/ptmx exists). */
2169 if (pathExists("/dev/pts/ptmx") &&
2170 !pathExists(chrootRootDir + "/dev/ptmx")
2171 && dirsInChroot.find("/dev/pts") == dirsInChroot.end())
2172 {
2173 if (mount("none", (chrootRootDir + "/dev/pts").c_str(), "devpts", 0, "newinstance,mode=0620") == -1)
2174 throw SysError("mounting /dev/pts");
2175 createSymlink("/dev/pts/ptmx", chrootRootDir + "/dev/ptmx");
2176
2bb04905
LC
2177 /* Make sure /dev/pts/ptmx is world-writable. With some
2178 Linux versions, it is created with permissions 0. */
2179 chmod_(chrootRootDir + "/dev/pts/ptmx", 0666);
36457566
LC
2180 }
2181
54c260e6
LC
2182 /* Do the chroot(). */
2183 if (chdir(chrootRootDir.c_str()) == -1)
2184 throw SysError(format("cannot change directory to '%1%'") % chrootRootDir);
2185
2186 if (mkdir("real-root", 0) == -1)
2187 throw SysError("cannot create real-root directory");
2188
2189#define pivot_root(new_root, put_old) (syscall(SYS_pivot_root, new_root, put_old))
2190 if (pivot_root(".", "real-root") == -1)
2191 throw SysError(format("cannot pivot old root directory onto '%1%'") % (chrootRootDir + "/real-root"));
2192#undef pivot_root
2193
2194 if (chroot(".") == -1)
2195 throw SysError(format("cannot change root directory to '%1%'") % chrootRootDir);
2196
2197 if (umount2("real-root", MNT_DETACH) == -1)
2198 throw SysError("cannot unmount real root filesystem");
2199
2200 if (rmdir("real-root") == -1)
2201 throw SysError("cannot remove real-root directory");
36457566
LC
2202 }
2203#endif
2204
cb960102 2205 if (chdir(tmpDirInSandbox.c_str()) == -1)
36457566
LC
2206 throw SysError(format("changing into `%1%'") % tmpDir);
2207
2208 /* Close all other file descriptors. */
2209 closeMostFDs(set<int>());
2210
2bb04905 2211#if __linux__
36457566
LC
2212 /* Change the personality to 32-bit if we're doing an
2213 i686-linux build on an x86_64-linux machine. */
2214 struct utsname utsbuf;
2215 uname(&utsbuf);
2216 if (drv.platform == "i686-linux" &&
2217 (settings.thisSystem == "x86_64-linux" ||
2218 (!strcmp(utsbuf.sysname, "Linux") && !strcmp(utsbuf.machine, "x86_64")))) {
2bb04905 2219 if (personality(PER_LINUX32) == -1)
36457566
LC
2220 throw SysError("cannot set i686-linux personality");
2221 }
2222
162825f9
EF
2223 if (drv.platform == "armhf-linux" &&
2224 (settings.thisSystem == "aarch64-linux" ||
2225 (!strcmp(utsbuf.sysname, "Linux") && !strcmp(utsbuf.machine, "aarch64")))) {
2226 if (personality(PER_LINUX32) == -1)
2227 throw SysError("cannot set armhf-linux personality");
2228 }
2229
36457566
LC
2230 /* Impersonate a Linux 2.6 machine to get some determinism in
2231 builds that depend on the kernel version. */
2232 if ((drv.platform == "i686-linux" || drv.platform == "x86_64-linux") && settings.impersonateLinux26) {
2233 int cur = personality(0xffffffff);
2234 if (cur != -1) personality(cur | 0x0020000 /* == UNAME26 */);
2235 }
2bb04905
LC
2236
2237 /* Disable address space randomization for improved
2238 determinism. */
2239 int cur = personality(0xffffffff);
2240 if (cur != -1) personality(cur | ADDR_NO_RANDOMIZE);
36457566
LC
2241#endif
2242
2243 /* Fill in the environment. */
2244 Strings envStrs;
2245 foreach (Environment::const_iterator, i, env)
2246 envStrs.push_back(rewriteHashes(i->first + "=" + i->second, rewritesToTmp));
36457566
LC
2247
2248 /* If we are running in `build-users' mode, then switch to the
2249 user we allocated above. Make sure that we drop all root
2250 privileges. Note that above we have closed all file
2251 descriptors except std*, so that's safe. Also note that
2252 setuid() when run as root sets the real, effective and
2253 saved UIDs. */
2254 if (buildUser.enabled()) {
322eeb87
LC
2255 /* Preserve supplementary groups of the build user, to allow
2256 admins to specify groups such as "kvm". */
2257 if (setgroups(buildUser.getSupplementaryGIDs().size(),
2258 buildUser.getSupplementaryGIDs().data()) == -1)
2259 throw SysError("cannot set supplementary groups of build user");
36457566
LC
2260
2261 if (setgid(buildUser.getGID()) == -1 ||
2262 getgid() != buildUser.getGID() ||
2263 getegid() != buildUser.getGID())
2264 throw SysError("setgid failed");
2265
2266 if (setuid(buildUser.getUID()) == -1 ||
2267 getuid() != buildUser.getUID() ||
2268 geteuid() != buildUser.getUID())
2269 throw SysError("setuid failed");
2270 }
2271
94d92c77
LC
2272 restoreSIGPIPE();
2273
2274 /* Indicate that we managed to set up the build environment. */
2275 writeFull(STDERR_FILENO, "\n");
2276
2277 /* Execute the program. This should not return. */
2278 if (isBuiltin(drv)) {
2279 try {
2280 logType = ltFlat;
2281
2282 auto buildDrv = lookupBuiltinBuilder(drv.builder);
9b5364a3
LC
2283 if (buildDrv != NULL) {
2284 /* Check what the output file name is. When doing a
2285 'bmCheck' build, the output file name is different from
2286 that specified in DRV due to hash rewriting. */
2287 Path output = drv.outputs["out"].path;
2288 auto redirected = redirectedOutputs.find(output);
2289 if (redirected != redirectedOutputs.end())
2290 output = redirected->second;
2291
2292 buildDrv(drv, drvPath, output);
2293 }
94d92c77
LC
2294 else
2295 throw Error(format("unsupported builtin function '%1%'") % string(drv.builder, 8));
2296 _exit(0);
2297 } catch (std::exception & e) {
2298 writeFull(STDERR_FILENO, "error: " + string(e.what()) + "\n");
2299 _exit(1);
2300 }
2301 }
2302
36457566 2303 /* Fill in the arguments. */
54c260e6 2304 Strings args;
36457566 2305 string builderBasename = baseNameOf(drv.builder);
54c260e6
LC
2306 args.push_back(builderBasename);
2307 foreach (Strings::iterator, i, drv.args)
2308 args.push_back(rewriteHashes(*i, rewritesToTmp));
36457566 2309
322eeb87 2310 execve(drv.builder.c_str(), stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data());
36457566 2311
7bf2a70a
LC
2312 int error = errno;
2313
2314 /* Right platform? Check this after we've tried 'execve' to allow for
2315 transparent emulation of different platforms with binfmt_misc
2316 handlers that invoke QEMU. */
2317 if (error == ENOEXEC && !canBuildLocally(drv.platform)) {
2318 if (settings.printBuildTrace)
2319 printMsg(lvlError, format("@ unsupported-platform %1% %2%") % drvPath % drv.platform);
2320 throw Error(
2321 format("a `%1%' is required to build `%3%', but I am a `%2%'")
2322 % drv.platform % settings.thisSystem % drvPath);
2323 }
2324
2325 errno = error;
36457566
LC
2326 throw SysError(format("executing `%1%'") % drv.builder);
2327
2328 } catch (std::exception & e) {
54c260e6 2329 writeFull(STDERR_FILENO, "while setting up the build environment: " + string(e.what()) + "\n");
2bb04905 2330 _exit(1);
36457566
LC
2331 }
2332
2333 abort(); /* never reached */
2334}
2335
2336
2337/* Parse a list of reference specifiers. Each element must either be
2338 a store path, or the symbolic name of the output of the derivation
2339 (such as `out'). */
2340PathSet parseReferenceSpecifiers(const Derivation & drv, string attr)
2341{
2342 PathSet result;
2343 Paths paths = tokenizeString<Paths>(attr);
2344 foreach (Strings::iterator, i, paths) {
2345 if (isStorePath(*i))
2346 result.insert(*i);
2347 else if (drv.outputs.find(*i) != drv.outputs.end())
2348 result.insert(drv.outputs.find(*i)->second.path);
2349 else throw BuildError(
76533c52 2350 format("derivation contains an invalid reference specifier `%1%'")
36457566
LC
2351 % *i);
2352 }
2353 return result;
2354}
2355
2356
2357void DerivationGoal::registerOutputs()
2358{
2359 /* When using a build hook, the build hook can register the output
2360 as valid (by doing `nix-store --import'). If so we don't have
2361 to do anything here. */
2362 if (hook) {
2363 bool allValid = true;
2364 foreach (DerivationOutputs::iterator, i, drv.outputs)
2365 if (!worker.store.isValidPath(i->second.path)) allValid = false;
2366 if (allValid) return;
2367 }
2368
2369 ValidPathInfos infos;
2370
b23b4d39
ED
2371 /* Set of inodes seen during calls to canonicalisePathMetaData()
2372 for this build's outputs. This needs to be shared between
2373 outputs to allow hard links between outputs. */
2374 InodesSeen inodesSeen;
2375
b4528110
ED
2376 Path checkSuffix = "-check";
2377
36457566
LC
2378 /* Check whether the output paths were created, and grep each
2379 output path to determine what other paths it references. Also make all
2380 output paths read-only. */
2381 foreach (DerivationOutputs::iterator, i, drv.outputs) {
2382 Path path = i->second.path;
2383 if (missingPaths.find(path) == missingPaths.end()) continue;
2384
2385 Path actualPath = path;
2386 if (useChroot) {
2387 actualPath = chrootRootDir + path;
2388 if (pathExists(actualPath)) {
8327e733 2389 /* Move output paths from the chroot to the store. */
36457566
LC
2390 if (buildMode == bmRepair)
2391 replaceValidPath(path, actualPath);
2392 else
2393 if (buildMode != bmCheck && rename(actualPath.c_str(), path.c_str()) == -1)
8327e733 2394 throw SysError(format("moving build output `%1%' from the chroot to the store") % path);
36457566
LC
2395 }
2396 if (buildMode != bmCheck) actualPath = path;
2397 } else {
2398 Path redirected = redirectedOutputs[path];
2399 if (buildMode == bmRepair
2400 && redirectedBadOutputs.find(path) != redirectedBadOutputs.end()
2401 && pathExists(redirected))
2402 replaceValidPath(path, redirected);
7889e72d 2403 if (buildMode == bmCheck && redirected != "")
36457566
LC
2404 actualPath = redirected;
2405 }
2406
2407 struct stat st;
2408 if (lstat(actualPath.c_str(), &st) == -1) {
2409 if (errno == ENOENT)
2410 throw BuildError(
2411 format("builder for `%1%' failed to produce output path `%2%'")
2412 % drvPath % path);
2413 throw SysError(format("getting attributes of path `%1%'") % actualPath);
2414 }
2415
2416#ifndef __CYGWIN__
2417 /* Check that the output is not group or world writable, as
2418 that means that someone else can have interfered with the
2419 build. Also, the output should be owned by the build
2420 user. */
2421 if ((!S_ISLNK(st.st_mode) && (st.st_mode & (S_IWGRP | S_IWOTH))) ||
2422 (buildUser.enabled() && st.st_uid != buildUser.getUID()))
2423 throw BuildError(format("suspicious ownership or permission on `%1%'; rejecting this build output") % path);
2424#endif
2425
2426 /* Apply hash rewriting if necessary. */
2427 bool rewritten = false;
2428 if (!rewritesFromTmp.empty()) {
2429 printMsg(lvlError, format("warning: rewriting hashes in `%1%'; cross fingers") % path);
2430
2431 /* Canonicalise first. This ensures that the path we're
2432 rewriting doesn't contain a hard link to /etc/shadow or
2433 something like that. */
2434 canonicalisePathMetaData(actualPath, buildUser.enabled() ? buildUser.getUID() : -1, inodesSeen);
2435
2436 /* FIXME: this is in-memory. */
2437 StringSink sink;
2438 dumpPath(actualPath, sink);
2439 deletePath(actualPath);
2440 sink.s = rewriteHashes(sink.s, rewritesFromTmp);
2441 StringSource source(sink.s);
2442 restorePath(actualPath, source);
2443
2444 rewritten = true;
2445 }
2446
2447 startNest(nest, lvlTalkative,
2448 format("scanning for references inside `%1%'") % path);
2449
2450 /* Check that fixed-output derivations produced the right
2451 outputs (i.e., the content hash should match the specified
2452 hash). */
2453 if (i->second.hash != "") {
2454
2455 bool recursive; HashType ht; Hash h;
2456 i->second.parseHashInfo(recursive, ht, h);
2457
2458 if (!recursive) {
2459 /* The output path should be a regular file without
2460 execute permission. */
2461 if (!S_ISREG(st.st_mode) || (st.st_mode & S_IXUSR) != 0)
2462 throw BuildError(
2463 format("output path `%1% should be a non-executable regular file") % path);
2464 }
2465
2466 /* Check the hash. */
2467 Hash h2 = recursive ? hashPath(ht, actualPath).first : hashFile(ht, actualPath);
dc0f74e5
LC
2468 if (h != h2) {
2469 if (settings.printBuildTrace)
2470 printMsg(lvlError, format("@ hash-mismatch %1% %2% %3% %4%")
2471 % path % i->second.hashAlgo
2472 % printHash16or32(h) % printHash16or32(h2));
2473 throw BuildError(format("hash mismatch for store item '%1%'") % path);
2474 }
36457566
LC
2475 }
2476
2477 /* Get rid of all weird permissions. This also checks that
2478 all files are owned by the build user, if applicable. */
2479 canonicalisePathMetaData(actualPath,
2480 buildUser.enabled() && !rewritten ? buildUser.getUID() : -1, inodesSeen);
2481
2482 /* For this output path, find the references to other paths
2483 contained in it. Compute the SHA-256 NAR hash at the same
2484 time. The hash is stored in the database so that we can
2485 verify later on whether nobody has messed with the store. */
2486 HashResult hash;
2487 PathSet references = scanForReferences(actualPath, allPaths, hash);
2488
2489 if (buildMode == bmCheck) {
f83e82cd 2490 if (!store->isValidPath(path)) continue;
36457566 2491 ValidPathInfo info = worker.store.queryPathInfo(path);
7f3b2510
ED
2492 if (hash.first != info.hash) {
2493 if (settings.keepFailed) {
b4528110 2494 Path dst = path + checkSuffix;
7f3b2510
ED
2495 if (pathExists(dst)) deletePath(dst);
2496 if (rename(actualPath.c_str(), dst.c_str()))
2497 throw SysError(format("renaming `%1%' to `%2%'") % actualPath % dst);
2498 throw Error(format("derivation `%1%' may not be deterministic: output `%2%' differs from ‘%3%’")
2499 % drvPath % path % dst);
2500 } else
2501 throw Error(format("derivation `%1%' may not be deterministic: output `%2%' differs")
2502 % drvPath % path);
2503 }
d5912428
LC
2504
2505 if (settings.printBuildTrace)
2506 printMsg(lvlError, format("@ build-succeeded %1% -") % drvPath);
2507
36457566
LC
2508 continue;
2509 }
2510
2511 /* For debugging, print out the referenced and unreferenced
2512 paths. */
2513 foreach (PathSet::iterator, i, inputPaths) {
2514 PathSet::iterator j = references.find(*i);
2515 if (j == references.end())
2516 debug(format("unreferenced input: `%1%'") % *i);
2517 else
2518 debug(format("referenced input: `%1%'") % *i);
2519 }
2520
2bb04905
LC
2521 /* Enforce `allowedReferences' and friends. */
2522 auto checkRefs = [&](const string & attrName, bool allowed, bool recursive) {
2523 if (drv.env.find(attrName) == drv.env.end()) return;
2524
2525 PathSet spec = parseReferenceSpecifiers(drv, get(drv.env, attrName));
2526
2527 PathSet used;
2528 if (recursive) {
2529 /* Our requisites are the union of the closures of our references. */
2530 for (auto & i : references)
2531 /* Don't call computeFSClosure on ourselves. */
2532 if (actualPath != i)
2533 computeFSClosure(worker.store, i, used);
2534 } else
2535 used = references;
2536
2537 for (auto & i : used)
2538 if (allowed) {
2539 if (spec.find(i) == spec.end())
2540 throw BuildError(format("output (`%1%') is not allowed to refer to path `%2%'") % actualPath % i);
2541 } else {
2542 if (spec.find(i) != spec.end())
2543 throw BuildError(format("output (`%1%') is not allowed to refer to path `%2%'") % actualPath % i);
2544 }
2545 };
2546
2547 checkRefs("allowedReferences", true, false);
2548 checkRefs("allowedRequisites", true, true);
2549 checkRefs("disallowedReferences", false, false);
2550 checkRefs("disallowedRequisites", false, true);
36457566 2551
b4528110
ED
2552 if (curRound == nrRounds) {
2553 worker.store.optimisePath(path); // FIXME: combine with scanForReferences()
36457566 2554
b4528110
ED
2555 worker.store.markContentsGood(path);
2556 }
36457566
LC
2557
2558 ValidPathInfo info;
2559 info.path = path;
2560 info.hash = hash.first;
2561 info.narSize = hash.second;
2562 info.references = references;
2563 info.deriver = drvPath;
2564 infos.push_back(info);
2565 }
2566
2567 if (buildMode == bmCheck) return;
2568
b4528110
ED
2569 /* Compare the result with the previous round, and report which
2570 path is different, if any.*/
2571 if (curRound > 1 && prevInfos != infos) {
2572 assert(prevInfos.size() == infos.size());
2573 for (auto i = prevInfos.begin(), j = infos.begin(); i != prevInfos.end(); ++i, ++j)
2574 if (!(*i == *j)) {
2575 Path prev = i->path + checkSuffix;
2576 if (pathExists(prev))
2577 throw NotDeterministic(
2578 format("output ‘%1%’ of ‘%2%’ differs from ‘%3%’ from previous round")
2579 % i->path % drvPath % prev);
2580 else
2581 throw NotDeterministic(
2582 format("output ‘%1%’ of ‘%2%’ differs from previous round")
2583 % i->path % drvPath);
2584 }
2585 assert(false); // shouldn't happen
2586 }
2587
2588 if (settings.keepFailed) {
2589 for (auto & i : drv.outputs) {
2590 Path prev = i.second.path + checkSuffix;
2591 if (pathExists(prev)) deletePath(prev);
2592 if (curRound < nrRounds) {
2593 Path dst = i.second.path + checkSuffix;
2594 if (rename(i.second.path.c_str(), dst.c_str()))
2595 throw SysError(format("renaming ‘%1%’ to ‘%2%’") % i.second.path % dst);
2596 }
2597 }
2598
2599 }
b23b4d39
ED
2600
2601 if (curRound < nrRounds) {
2602 prevInfos = infos;
2603 return;
2604 }
2605
36457566
LC
2606 /* Register each output path as valid, and register the sets of
2607 paths referenced by each of them. If there are cycles in the
2608 outputs, this will fail. */
2609 worker.store.registerValidPaths(infos);
2610}
2611
2612
2613string drvsLogDir = "drvs";
2614
2615
2616Path DerivationGoal::openLogFile()
2617{
2618 logSize = 0;
2619
2620 if (!settings.keepLog) return "";
2621
2622 string baseName = baseNameOf(drvPath);
2623
2624 /* Create a log file. */
2625 Path dir = (format("%1%/%2%/%3%/") % settings.nixLogDir % drvsLogDir % string(baseName, 0, 2)).str();
2626 createDirs(dir);
2627
29a68668
LC
2628 switch (settings.logCompression)
2629 {
2630 case COMPRESSION_GZIP: {
2631 Path logFileName = (format("%1%/%2%.gz") % dir % string(baseName, 2)).str();
2632 AutoCloseFD fd = open(logFileName.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0666);
2633 if (fd == -1) throw SysError(format("creating log file `%1%'") % logFileName);
2634 closeOnExec(fd);
2635
2636 /* Note: FD will be closed by 'gzclose'. */
2637 if (!(gzLogFile = gzdopen(fd.borrow(), "w")))
2638 throw Error(format("cannot open compressed log file `%1%'") % logFileName);
2639
2640 gzbuffer(gzLogFile, 32768);
2641 gzsetparams(gzLogFile, Z_BEST_COMPRESSION, Z_DEFAULT_STRATEGY);
36457566 2642
29a68668
LC
2643 return logFileName;
2644 }
2645
f997137d 2646#if HAVE_BZLIB_H
29a68668 2647 case COMPRESSION_BZIP2: {
36457566
LC
2648 Path logFileName = (format("%1%/%2%.bz2") % dir % string(baseName, 2)).str();
2649 AutoCloseFD fd = open(logFileName.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0666);
2650 if (fd == -1) throw SysError(format("creating log file `%1%'") % logFileName);
2651 closeOnExec(fd);
2652
2653 if (!(fLogFile = fdopen(fd.borrow(), "w")))
2654 throw SysError(format("opening file `%1%'") % logFileName);
2655
2656 int err;
2657 if (!(bzLogFile = BZ2_bzWriteOpen(&err, fLogFile, 9, 0, 0)))
2658 throw Error(format("cannot open compressed log file `%1%'") % logFileName);
2659
2660 return logFileName;
29a68668 2661 }
f997137d 2662#endif
36457566 2663
29a68668 2664 case COMPRESSION_NONE: {
36457566
LC
2665 Path logFileName = (format("%1%/%2%") % dir % string(baseName, 2)).str();
2666 fdLogFile = open(logFileName.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0666);
2667 if (fdLogFile == -1) throw SysError(format("creating log file `%1%'") % logFileName);
2668 closeOnExec(fdLogFile);
2669 return logFileName;
29a68668 2670 }
36457566 2671 }
29a68668
LC
2672
2673 abort();
36457566
LC
2674}
2675
2676
2677void DerivationGoal::closeLogFile()
2678{
29a68668
LC
2679 if (gzLogFile) {
2680 int err;
2681 err = gzclose(gzLogFile);
2682 gzLogFile = NULL;
2683 if (err != Z_OK) throw Error(format("cannot close compressed log file (gzip error = %1%)") % err);
2684 }
f997137d 2685#if HAVE_BZLIB_H
29a68668 2686 else if (bzLogFile) {
36457566
LC
2687 int err;
2688 BZ2_bzWriteClose(&err, bzLogFile, 0, 0, 0);
2689 bzLogFile = 0;
2690 if (err != BZ_OK) throw Error(format("cannot close compressed log file (BZip2 error = %1%)") % err);
2691 }
f997137d 2692#endif
36457566
LC
2693
2694 if (fLogFile) {
2695 fclose(fLogFile);
2696 fLogFile = 0;
2697 }
2698
2699 fdLogFile.close();
2700}
2701
2702
2608e409
HG
2703static void _chown(const Path & path, uid_t uid, gid_t gid)
2704{
2705 checkInterrupt();
2706
2707 if (lchown(path.c_str(), uid, gid) == -1) {
2708 throw SysError(format("change owner and group of `%1%'") % path);
2709 }
2710 struct stat st = lstat(path);
2711 if (S_ISDIR(st.st_mode)) {
2712 for (auto & i : readDirectory(path))
2713 _chown(path + "/" + i.name, uid, gid);
2714 }
2715}
2716
2717
36457566
LC
2718void DerivationGoal::deleteTmpDir(bool force)
2719{
2720 if (tmpDir != "") {
2721 if (settings.keepFailed && !force) {
2722 printMsg(lvlError,
2723 format("note: keeping build directory `%2%'")
2724 % drvPath % tmpDir);
2725 chmod(tmpDir.c_str(), 0755);
2608e409
HG
2726 // Change the ownership if clientUid is set. Never change the
2727 // ownership or the group to "root" for security reasons.
2728 if (settings.clientUid != (uid_t) -1 && settings.clientUid != 0) {
2729 _chown(tmpDir, settings.clientUid,
2730 settings.clientGid != 0 ? settings.clientGid : -1);
2731 }
36457566
LC
2732 }
2733 else
2734 deletePath(tmpDir);
2735 tmpDir = "";
2736 }
2737}
2738
2739
2740void DerivationGoal::handleChildOutput(int fd, const string & data)
2741{
6ef61cc4
LC
2742 string prefix;
2743
2744 if (settings.multiplexedBuildOutput) {
2745 /* Print a prefix that allows clients to determine whether a message
2746 comes from the daemon or from a build process, and in the latter
2747 case, which build process it comes from. The PID here matches the
2748 one given in "@ build-started" traces; it's shorter that the
2749 derivation file name, hence this choice. */
2750 prefix = "@ build-log "
2751 + std::to_string(pid < 0 ? hook->pid : pid)
2752 + " " + std::to_string(data.size()) + "\n";
2753 }
2754
36457566
LC
2755 if ((hook && fd == hook->builderOut.readSide) ||
2756 (!hook && fd == builderOut.readSide))
2757 {
2758 logSize += data.size();
2759 if (settings.maxLogSize && logSize > settings.maxLogSize) {
2760 printMsg(lvlError,
2761 format("%1% killed after writing more than %2% bytes of log output")
2762 % getName() % settings.maxLogSize);
f3ff1da4 2763 timedOut(); // not really a timeout, but close enough
36457566
LC
2764 return;
2765 }
2766 if (verbosity >= settings.buildVerbosity)
6ef61cc4 2767 writeToStderr(prefix + data);
29a68668
LC
2768
2769 if (gzLogFile) {
2770 if (data.size() > 0) {
2771 int count, err;
2772 count = gzwrite(gzLogFile, data.data(), data.size());
2773 if (count == 0) throw Error(format("cannot write to compressed log file (gzip error = %1%)") % gzerror(gzLogFile, &err));
2774 }
f997137d 2775#if HAVE_BZLIB_H
29a68668 2776 } else if (bzLogFile) {
36457566
LC
2777 int err;
2778 BZ2_bzWrite(&err, bzLogFile, (unsigned char *) data.data(), data.size());
2779 if (err != BZ_OK) throw Error(format("cannot write to compressed log file (BZip2 error = %1%)") % err);
f997137d 2780#endif
36457566 2781 } else if (fdLogFile != -1)
54c260e6 2782 writeFull(fdLogFile, data);
36457566
LC
2783 }
2784
2785 if (hook && fd == hook->fromHook.readSide)
6ef61cc4 2786 writeToStderr(prefix + data);
36457566
LC
2787}
2788
2789
2790void DerivationGoal::handleEOF(int fd)
2791{
2792 worker.wakeUp(shared_from_this());
2793}
2794
2795
2796PathSet DerivationGoal::checkPathValidity(bool returnValid, bool checkHash)
2797{
2798 PathSet result;
2799 foreach (DerivationOutputs::iterator, i, drv.outputs) {
2800 if (!wantOutput(i->first, wantedOutputs)) continue;
2801 bool good =
2802 worker.store.isValidPath(i->second.path) &&
2803 (!checkHash || worker.store.pathContentsGood(i->second.path));
2804 if (good == returnValid) result.insert(i->second.path);
2805 }
2806 return result;
2807}
2808
2809
2810bool DerivationGoal::pathFailed(const Path & path)
2811{
2812 if (!settings.cacheFailure) return false;
2813
2814 if (!worker.store.hasPathFailed(path)) return false;
2815
2816 printMsg(lvlError, format("builder for `%1%' failed previously (cached)") % path);
2817
2818 if (settings.printBuildTrace)
2819 printMsg(lvlError, format("@ build-failed %1% - cached") % drvPath);
2820
f3ff1da4 2821 done(BuildResult::CachedFailure);
36457566
LC
2822
2823 return true;
2824}
2825
2826
2827Path DerivationGoal::addHashRewrite(const Path & path)
2828{
2829 string h1 = string(path, settings.nixStore.size() + 1, 32);
2830 string h2 = string(printHash32(hashString(htSHA256, "rewrite:" + drvPath + ":" + path)), 0, 32);
2831 Path p = settings.nixStore + "/" + h2 + string(path, settings.nixStore.size() + 33);
2832 if (pathExists(p)) deletePath(p);
2833 assert(path.size() == p.size());
2834 rewritesToTmp[h1] = h2;
2835 rewritesFromTmp[h2] = h1;
2836 redirectedOutputs[path] = p;
9b5364a3
LC
2837 printMsg(lvlChatty, format("output '%1%' redirected to '%2%'")
2838 % path % p);
36457566
LC
2839 return p;
2840}
2841
2842
f3ff1da4
ED
2843void DerivationGoal::done(BuildResult::Status status, const string & msg)
2844{
2845 result.status = status;
2846 result.errorMsg = msg;
2847 amDone(result.success() ? ecSuccess : ecFailed);
2848 if (result.status == BuildResult::TimedOut)
2849 worker.timedOut = true;
2850 if (result.status == BuildResult::PermanentFailure || result.status == BuildResult::CachedFailure)
2851 worker.permanentFailure = true;
2852}
2853
2854
36457566
LC
2855//////////////////////////////////////////////////////////////////////
2856
2857
2858class SubstitutionGoal : public Goal
2859{
2860 friend class Worker;
2861
2862private:
2863 /* The store path that should be realised through a substitute. */
2864 Path storePath;
2865
36457566
LC
2866 /* Path info returned by the substituter's query info operation. */
2867 SubstitutablePathInfo info;
2868
2869 /* Pipe for the substituter's standard output. */
2870 Pipe outPipe;
2871
2872 /* Pipe for the substituter's standard error. */
2873 Pipe logPipe;
2874
2875 /* The process ID of the builder. */
2876 Pid pid;
2877
2878 /* Lock on the store path. */
2879 std::shared_ptr<PathLocks> outputLock;
2880
2881 /* Whether to try to repair a valid path. */
2882 bool repair;
2883
2884 /* Location where we're downloading the substitute. Differs from
2885 storePath when doing a repair. */
2886 Path destPath;
2887
2888 typedef void (SubstitutionGoal::*GoalState)();
2889 GoalState state;
2890
f6919ebd
LC
2891 void tryNext();
2892
36457566
LC
2893public:
2894 SubstitutionGoal(const Path & storePath, Worker & worker, bool repair = false);
2895 ~SubstitutionGoal();
2896
f3ff1da4 2897 void timedOut();
36457566 2898
2bb04905
LC
2899 string key()
2900 {
2901 /* "a$" ensures substitution goals happen before derivation
2902 goals. */
2903 return "a$" + storePathToName(storePath) + "$" + storePath;
2904 }
2905
36457566
LC
2906 void work();
2907
2908 /* The states. */
2909 void init();
36457566
LC
2910 void gotInfo();
2911 void referencesValid();
2912 void tryToRun();
2913 void finished();
2914
2915 /* Callback used by the worker to write to the log. */
2916 void handleChildOutput(int fd, const string & data);
2917 void handleEOF(int fd);
2918
2919 Path getStorePath() { return storePath; }
2920};
2921
2922
2923SubstitutionGoal::SubstitutionGoal(const Path & storePath, Worker & worker, bool repair)
2924 : Goal(worker)
36457566
LC
2925 , repair(repair)
2926{
2927 this->storePath = storePath;
2928 state = &SubstitutionGoal::init;
2929 name = (format("substitution of `%1%'") % storePath).str();
2930 trace("created");
2931}
2932
2933
2934SubstitutionGoal::~SubstitutionGoal()
2935{
2936 if (pid != -1) worker.childTerminated(pid);
2937}
2938
2939
f3ff1da4 2940void SubstitutionGoal::timedOut()
36457566 2941{
f3ff1da4 2942 if (settings.printBuildTrace)
36457566
LC
2943 printMsg(lvlError, format("@ substituter-failed %1% timeout") % storePath);
2944 if (pid != -1) {
2945 pid_t savedPid = pid;
2946 pid.kill();
2947 worker.childTerminated(savedPid);
2948 }
2949 amDone(ecFailed);
2950}
2951
2952
2953void SubstitutionGoal::work()
2954{
2955 (this->*state)();
2956}
2957
2958
2959void SubstitutionGoal::init()
2960{
2961 trace("init");
2962
2963 worker.store.addTempRoot(storePath);
2964
2965 /* If the path already exists we're done. */
2966 if (!repair && worker.store.isValidPath(storePath)) {
2967 amDone(ecSuccess);
2968 return;
2969 }
2970
2971 if (settings.readOnlyMode)
8327e733 2972 throw Error(format("cannot substitute path `%1%' - no write access to the store") % storePath);
36457566 2973
36457566
LC
2974 tryNext();
2975}
2976
2977
2978void SubstitutionGoal::tryNext()
2979{
f6919ebd 2980 trace("trying substituter");
36457566 2981
f6919ebd
LC
2982 SubstitutablePathInfos infos;
2983 PathSet dummy(singleton<PathSet>(storePath));
2984 worker.store.querySubstitutablePathInfos(dummy, infos);
2985 SubstitutablePathInfos::iterator k = infos.find(storePath);
2986 if (k == infos.end()) {
36457566
LC
2987 /* None left. Terminate this goal and let someone else deal
2988 with it. */
2989 debug(format("path `%1%' is required, but there is no substituter that can build it") % storePath);
2990 /* Hack: don't indicate failure if there were no substituters.
2991 In that case the calling derivation should just do a
2992 build. */
f6919ebd
LC
2993 amDone(ecNoSubstituters);
2994 return;
36457566
LC
2995 }
2996
f6919ebd 2997 /* Found a substitute. */
36457566 2998 info = k->second;
36457566
LC
2999
3000 /* To maintain the closure invariant, we first have to realise the
3001 paths referenced by this one. */
3002 foreach (PathSet::iterator, i, info.references)
3003 if (*i != storePath) /* ignore self-references */
3004 addWaitee(worker.makeSubstitutionGoal(*i));
3005
3006 if (waitees.empty()) /* to prevent hang (no wake-up event) */
3007 referencesValid();
3008 else
3009 state = &SubstitutionGoal::referencesValid;
3010}
3011
3012
3013void SubstitutionGoal::referencesValid()
3014{
3015 trace("all references realised");
3016
3017 if (nrFailed > 0) {
3018 debug(format("some references of path `%1%' could not be realised") % storePath);
3019 amDone(nrNoSubstituters > 0 || nrIncompleteClosure > 0 ? ecIncompleteClosure : ecFailed);
3020 return;
3021 }
3022
3023 foreach (PathSet::iterator, i, info.references)
3024 if (*i != storePath) /* ignore self-references */
3025 assert(worker.store.isValidPath(*i));
3026
3027 state = &SubstitutionGoal::tryToRun;
3028 worker.wakeUp(shared_from_this());
3029}
3030
3031
3032void SubstitutionGoal::tryToRun()
3033{
3034 trace("trying to run");
3035
3036 /* Make sure that we are allowed to start a build. Note that even
3037 is maxBuildJobs == 0 (no local builds allowed), we still allow
3038 a substituter to run. This is because substitutions cannot be
3039 distributed to another machine via the build hook. */
3040 if (worker.getNrLocalBuilds() >= (settings.maxBuildJobs == 0 ? 1 : settings.maxBuildJobs)) {
3041 worker.waitForBuildSlot(shared_from_this());
3042 return;
3043 }
3044
3045 /* Maybe a derivation goal has already locked this path
3046 (exceedingly unlikely, since it should have used a substitute
3047 first, but let's be defensive). */
3048 outputLock.reset(); // make sure this goal's lock is gone
3049 if (pathIsLockedByMe(storePath)) {
3050 debug(format("restarting substitution of `%1%' because it's locked by another goal")
3051 % storePath);
3052 worker.waitForAnyGoal(shared_from_this());
3053 return; /* restart in the tryToRun() state when another goal finishes */
3054 }
3055
3056 /* Acquire a lock on the output path. */
3057 outputLock = std::shared_ptr<PathLocks>(new PathLocks);
3058 if (!outputLock->lockPaths(singleton<PathSet>(storePath), "", false)) {
3059 worker.waitForAWhile(shared_from_this());
3060 return;
3061 }
3062
3063 /* Check again whether the path is invalid. */
3064 if (!repair && worker.store.isValidPath(storePath)) {
3065 debug(format("store path `%1%' has become valid") % storePath);
3066 outputLock->setDeletion(true);
3067 amDone(ecSuccess);
3068 return;
3069 }
3070
3071 printMsg(lvlInfo, format("fetching path `%1%'...") % storePath);
3072
3073 outPipe.create();
3074 logPipe.create();
3075
3076 destPath = repair ? storePath + ".tmp" : storePath;
3077
3078 /* Remove the (stale) output path if it exists. */
3079 if (pathExists(destPath))
3080 deletePath(destPath);
3081
3082 worker.store.setSubstituterEnv();
3083
3084 /* Fill in the arguments. */
3085 Strings args;
f6919ebd
LC
3086 args.push_back("guix");
3087 args.push_back("substitute");
36457566
LC
3088 args.push_back("--substitute");
3089 args.push_back(storePath);
3090 args.push_back(destPath);
36457566
LC
3091
3092 /* Fork the substitute program. */
2bb04905 3093 pid = startProcess([&]() {
36457566 3094
2bb04905 3095 commonChildInit(logPipe);
36457566 3096
2bb04905
LC
3097 if (dup2(outPipe.writeSide, STDOUT_FILENO) == -1)
3098 throw SysError("cannot dup output pipe into stdout");
36457566 3099
f6919ebd 3100 execv(settings.guixProgram.c_str(), stringsToCharPtrs(args).data());
36457566 3101
f6919ebd 3102 throw SysError(format("executing `%1% substitute'") % settings.guixProgram);
2bb04905 3103 });
36457566 3104
36457566
LC
3105 pid.setSeparatePG(true);
3106 pid.setKillSignal(SIGTERM);
3107 outPipe.writeSide.close();
3108 logPipe.writeSide.close();
3109 worker.childStarted(shared_from_this(),
3110 pid, singleton<set<int> >(logPipe.readSide), true, true);
3111
3112 state = &SubstitutionGoal::finished;
3113
3114 if (settings.printBuildTrace)
f6919ebd
LC
3115 /* The second element in the message used to be the name of the
3116 substituter but we're left with only one. */
3117 printMsg(lvlError, format("@ substituter-started %1% substitute") % storePath);
36457566
LC
3118}
3119
3120
3121void SubstitutionGoal::finished()
3122{
3123 trace("substitute finished");
3124
3125 /* Since we got an EOF on the logger pipe, the substitute is
3126 presumed to have terminated. */
3127 pid_t savedPid = pid;
3128 int status = pid.wait(true);
3129
3130 /* So the child is gone now. */
3131 worker.childTerminated(savedPid);
3132
3133 /* Close the read side of the logger pipe. */
3134 logPipe.readSide.close();
3135
3136 /* Get the hash info from stdout. */
3137 string dummy = readLine(outPipe.readSide);
3138 string expectedHashStr = statusOk(status) ? readLine(outPipe.readSide) : "";
3139 outPipe.readSide.close();
3140
3141 /* Check the exit status and the build result. */
3142 HashResult hash;
3143 try {
3144
3145 if (!statusOk(status))
3146 throw SubstError(format("fetching path `%1%' %2%")
3147 % storePath % statusToString(status));
3148
3149 if (!pathExists(destPath))
3150 throw SubstError(format("substitute did not produce path `%1%'") % destPath);
3151
3152 hash = hashPath(htSHA256, destPath);
3153
3154 /* Verify the expected hash we got from the substituer. */
3155 if (expectedHashStr != "") {
3156 size_t n = expectedHashStr.find(':');
3157 if (n == string::npos)
3158 throw Error(format("bad hash from substituter: %1%") % expectedHashStr);
3159 HashType hashType = parseHashType(string(expectedHashStr, 0, n));
3160 if (hashType == htUnknown)
3161 throw Error(format("unknown hash algorithm in `%1%'") % expectedHashStr);
3162 Hash expectedHash = parseHash16or32(hashType, string(expectedHashStr, n + 1));
3163 Hash actualHash = hashType == htSHA256 ? hash.first : hashPath(hashType, destPath).first;
dc0f74e5
LC
3164 if (expectedHash != actualHash) {
3165 if (settings.printBuildTrace)
3166 printMsg(lvlError, format("@ hash-mismatch %1% %2% %3% %4%")
3167 % storePath % "sha256"
3168 % printHash16or32(expectedHash)
3169 % printHash16or32(actualHash));
3170 throw SubstError(format("hash mismatch for substituted item `%1%'") % storePath);
3171 }
36457566
LC
3172 }
3173
3174 } catch (SubstError & e) {
3175
3176 printMsg(lvlInfo, e.msg());
3177
3178 if (settings.printBuildTrace) {
3179 printMsg(lvlError, format("@ substituter-failed %1% %2% %3%")
3180 % storePath % status % e.msg());
3181 }
3182
f6919ebd 3183 amDone(ecFailed);
36457566
LC
3184 return;
3185 }
3186
3187 if (repair) replaceValidPath(storePath, destPath);
3188
3189 canonicalisePathMetaData(storePath, -1);
3190
3191 worker.store.optimisePath(storePath); // FIXME: combine with hashPath()
3192
3193 ValidPathInfo info2;
3194 info2.path = storePath;
3195 info2.hash = hash.first;
3196 info2.narSize = hash.second;
3197 info2.references = info.references;
3198 info2.deriver = info.deriver;
3199 worker.store.registerValidPath(info2);
3200
3201 outputLock->setDeletion(true);
3202 outputLock.reset();
3203
3204 worker.store.markContentsGood(storePath);
3205
3206 printMsg(lvlChatty,
3207 format("substitution of path `%1%' succeeded") % storePath);
3208
3209 if (settings.printBuildTrace)
3210 printMsg(lvlError, format("@ substituter-succeeded %1%") % storePath);
3211
3212 amDone(ecSuccess);
3213}
3214
3215
3216void SubstitutionGoal::handleChildOutput(int fd, const string & data)
3217{
3218 assert(fd == logPipe.readSide);
3219 if (verbosity >= settings.buildVerbosity) writeToStderr(data);
3220 /* Don't write substitution output to a log file for now. We
3221 probably should, though. */
3222}
3223
3224
3225void SubstitutionGoal::handleEOF(int fd)
3226{
3227 if (fd == logPipe.readSide) worker.wakeUp(shared_from_this());
3228}
3229
3230
3231
3232//////////////////////////////////////////////////////////////////////
3233
3234
3235static bool working = false;
3236
3237
3238Worker::Worker(LocalStore & store)
3239 : store(store)
3240{
3241 /* Debugging: prevent recursive workers. */
3242 if (working) abort();
3243 working = true;
3244 nrLocalBuilds = 0;
3245 lastWokenUp = 0;
3246 permanentFailure = false;
2bb04905 3247 timedOut = false;
36457566
LC
3248}
3249
3250
3251Worker::~Worker()
3252{
3253 working = false;
3254
3255 /* Explicitly get rid of all strong pointers now. After this all
3256 goals that refer to this worker should be gone. (Otherwise we
3257 are in trouble, since goals may call childTerminated() etc. in
3258 their destructors). */
3259 topGoals.clear();
3260}
3261
3262
f3ff1da4
ED
3263GoalPtr Worker::makeDerivationGoal(const Path & path,
3264 const StringSet & wantedOutputs, BuildMode buildMode)
36457566
LC
3265{
3266 GoalPtr goal = derivationGoals[path].lock();
3267 if (!goal) {
3268 goal = GoalPtr(new DerivationGoal(path, wantedOutputs, *this, buildMode));
3269 derivationGoals[path] = goal;
3270 wakeUp(goal);
3271 } else
3272 (dynamic_cast<DerivationGoal *>(goal.get()))->addWantedOutputs(wantedOutputs);
3273 return goal;
3274}
3275
3276
3277GoalPtr Worker::makeSubstitutionGoal(const Path & path, bool repair)
3278{
3279 GoalPtr goal = substitutionGoals[path].lock();
3280 if (!goal) {
3281 goal = GoalPtr(new SubstitutionGoal(path, *this, repair));
3282 substitutionGoals[path] = goal;
3283 wakeUp(goal);
3284 }
3285 return goal;
3286}
3287
3288
3289static void removeGoal(GoalPtr goal, WeakGoalMap & goalMap)
3290{
3291 /* !!! inefficient */
3292 for (WeakGoalMap::iterator i = goalMap.begin();
3293 i != goalMap.end(); )
3294 if (i->second.lock() == goal) {
3295 WeakGoalMap::iterator j = i; ++j;
3296 goalMap.erase(i);
3297 i = j;
3298 }
3299 else ++i;
3300}
3301
3302
3303void Worker::removeGoal(GoalPtr goal)
3304{
3305 nix::removeGoal(goal, derivationGoals);
3306 nix::removeGoal(goal, substitutionGoals);
3307 if (topGoals.find(goal) != topGoals.end()) {
3308 topGoals.erase(goal);
3309 /* If a top-level goal failed, then kill all other goals
3310 (unless keepGoing was set). */
3311 if (goal->getExitCode() == Goal::ecFailed && !settings.keepGoing)
3312 topGoals.clear();
3313 }
3314
3315 /* Wake up goals waiting for any goal to finish. */
3316 foreach (WeakGoals::iterator, i, waitingForAnyGoal) {
3317 GoalPtr goal = i->lock();
3318 if (goal) wakeUp(goal);
3319 }
3320
3321 waitingForAnyGoal.clear();
3322}
3323
3324
3325void Worker::wakeUp(GoalPtr goal)
3326{
3327 goal->trace("woken up");
3328 addToWeakGoals(awake, goal);
3329}
3330
3331
3332unsigned Worker::getNrLocalBuilds()
3333{
3334 return nrLocalBuilds;
3335}
3336
3337
3338void Worker::childStarted(GoalPtr goal,
3339 pid_t pid, const set<int> & fds, bool inBuildSlot,
3340 bool respectTimeouts)
3341{
3342 Child child;
3343 child.goal = goal;
3344 child.fds = fds;
3345 child.timeStarted = child.lastOutput = time(0);
3346 child.inBuildSlot = inBuildSlot;
3347 child.respectTimeouts = respectTimeouts;
3348 children[pid] = child;
3349 if (inBuildSlot) nrLocalBuilds++;
3350}
3351
3352
3353void Worker::childTerminated(pid_t pid, bool wakeSleepers)
3354{
3355 assert(pid != -1); /* common mistake */
3356
3357 Children::iterator i = children.find(pid);
3358 assert(i != children.end());
3359
3360 if (i->second.inBuildSlot) {
3361 assert(nrLocalBuilds > 0);
3362 nrLocalBuilds--;
3363 }
3364
3365 children.erase(pid);
3366
3367 if (wakeSleepers) {
3368
3369 /* Wake up goals waiting for a build slot. */
3370 foreach (WeakGoals::iterator, i, wantingToBuild) {
3371 GoalPtr goal = i->lock();
3372 if (goal) wakeUp(goal);
3373 }
3374
3375 wantingToBuild.clear();
3376 }
3377}
3378
3379
3380void Worker::waitForBuildSlot(GoalPtr goal)
3381{
3382 debug("wait for build slot");
3383 if (getNrLocalBuilds() < settings.maxBuildJobs)
3384 wakeUp(goal); /* we can do it right away */
3385 else
3386 addToWeakGoals(wantingToBuild, goal);
3387}
3388
3389
3390void Worker::waitForAnyGoal(GoalPtr goal)
3391{
3392 debug("wait for any goal");
3393 addToWeakGoals(waitingForAnyGoal, goal);
3394}
3395
3396
3397void Worker::waitForAWhile(GoalPtr goal)
3398{
3399 debug("wait for a while");
3400 addToWeakGoals(waitingForAWhile, goal);
3401}
3402
3403
3404void Worker::run(const Goals & _topGoals)
3405{
3406 foreach (Goals::iterator, i, _topGoals) topGoals.insert(*i);
3407
3408 startNest(nest, lvlDebug, format("entered goal loop"));
3409
3410 while (1) {
3411
3412 checkInterrupt();
3413
2bb04905
LC
3414 /* Call every wake goal (in the ordering established by
3415 CompareGoalPtrs). */
36457566 3416 while (!awake.empty() && !topGoals.empty()) {
2bb04905
LC
3417 Goals awake2;
3418 for (auto & i : awake) {
3419 GoalPtr goal = i.lock();
3420 if (goal) awake2.insert(goal);
3421 }
36457566 3422 awake.clear();
2bb04905 3423 for (auto & goal : awake2) {
36457566 3424 checkInterrupt();
2bb04905
LC
3425 goal->work();
3426 if (topGoals.empty()) break; // stuff may have been cancelled
36457566
LC
3427 }
3428 }
3429
3430 if (topGoals.empty()) break;
3431
3432 /* Wait for input. */
3433 if (!children.empty() || !waitingForAWhile.empty())
3434 waitForInput();
3435 else {
3436 if (awake.empty() && settings.maxBuildJobs == 0) throw Error(
3437 "unable to start any build; either increase `--max-jobs' "
3438 "or enable distributed builds");
3439 assert(!awake.empty());
3440 }
3441 }
3442
3443 /* If --keep-going is not set, it's possible that the main goal
3444 exited while some of its subgoals were still active. But if
3445 --keep-going *is* set, then they must all be finished now. */
3446 assert(!settings.keepGoing || awake.empty());
3447 assert(!settings.keepGoing || wantingToBuild.empty());
3448 assert(!settings.keepGoing || children.empty());
3449}
3450
3451
3452void Worker::waitForInput()
3453{
3454 printMsg(lvlVomit, "waiting for children");
3455
3456 /* Process output from the file descriptors attached to the
3457 children, namely log output and output path creation commands.
3458 We also use this to detect child termination: if we get EOF on
3459 the logger pipe of a build, we assume that the builder has
3460 terminated. */
3461
3462 bool useTimeout = false;
3463 struct timeval timeout;
3464 timeout.tv_usec = 0;
3465 time_t before = time(0);
3466
3467 /* If we're monitoring for silence on stdout/stderr, or if there
3468 is a build timeout, then wait for input until the first
3469 deadline for any child. */
3470 assert(sizeof(time_t) >= sizeof(long));
3471 time_t nearest = LONG_MAX; // nearest deadline
3472 foreach (Children::iterator, i, children) {
3473 if (!i->second.respectTimeouts) continue;
3474 if (settings.maxSilentTime != 0)
3475 nearest = std::min(nearest, i->second.lastOutput + settings.maxSilentTime);
3476 if (settings.buildTimeout != 0)
3477 nearest = std::min(nearest, i->second.timeStarted + settings.buildTimeout);
3478 }
3479 if (nearest != LONG_MAX) {
3480 timeout.tv_sec = std::max((time_t) 1, nearest - before);
3481 useTimeout = true;
3482 printMsg(lvlVomit, format("sleeping %1% seconds") % timeout.tv_sec);
3483 }
3484
3485 /* If we are polling goals that are waiting for a lock, then wake
3486 up after a few seconds at most. */
3487 if (!waitingForAWhile.empty()) {
3488 useTimeout = true;
3489 if (lastWokenUp == 0)
3490 printMsg(lvlError, "waiting for locks or build slots...");
3491 if (lastWokenUp == 0 || lastWokenUp > before) lastWokenUp = before;
3492 timeout.tv_sec = std::max((time_t) 1, (time_t) (lastWokenUp + settings.pollInterval - before));
3493 } else lastWokenUp = 0;
3494
3495 using namespace std;
3496 /* Use select() to wait for the input side of any logger pipe to
3497 become `available'. Note that `available' (i.e., non-blocking)
3498 includes EOF. */
3499 fd_set fds;
3500 FD_ZERO(&fds);
3501 int fdMax = 0;
3502 foreach (Children::iterator, i, children) {
3503 foreach (set<int>::iterator, j, i->second.fds) {
3504 FD_SET(*j, &fds);
3505 if (*j >= fdMax) fdMax = *j + 1;
3506 }
3507 }
3508
3509 if (select(fdMax, &fds, 0, 0, useTimeout ? &timeout : 0) == -1) {
3510 if (errno == EINTR) return;
3511 throw SysError("waiting for input");
3512 }
3513
3514 time_t after = time(0);
3515
3516 /* Process all available file descriptors. */
3517
3518 /* Since goals may be canceled from inside the loop below (causing
3519 them go be erased from the `children' map), we have to be
3520 careful that we don't keep iterators alive across calls to
f3ff1da4 3521 timedOut(). */
36457566
LC
3522 set<pid_t> pids;
3523 foreach (Children::iterator, i, children) pids.insert(i->first);
3524
3525 foreach (set<pid_t>::iterator, i, pids) {
3526 checkInterrupt();
3527 Children::iterator j = children.find(*i);
3528 if (j == children.end()) continue; // child destroyed
3529 GoalPtr goal = j->second.goal.lock();
3530 assert(goal);
3531
3532 set<int> fds2(j->second.fds);
3533 foreach (set<int>::iterator, k, fds2) {
3534 if (FD_ISSET(*k, &fds)) {
3535 unsigned char buffer[4096];
3536 ssize_t rd = read(*k, buffer, sizeof(buffer));
3537 if (rd == -1) {
3538 if (errno != EINTR)
3539 throw SysError(format("reading from %1%")
3540 % goal->getName());
3541 } else if (rd == 0) {
3542 debug(format("%1%: got EOF") % goal->getName());
3543 goal->handleEOF(*k);
3544 j->second.fds.erase(*k);
3545 } else {
3546 printMsg(lvlVomit, format("%1%: read %2% bytes")
3547 % goal->getName() % rd);
3548 string data((char *) buffer, rd);
3549 j->second.lastOutput = after;
3550 goal->handleChildOutput(*k, data);
3551 }
3552 }
3553 }
3554
3555 if (goal->getExitCode() == Goal::ecBusy &&
3556 settings.maxSilentTime != 0 &&
3557 j->second.respectTimeouts &&
3558 after - j->second.lastOutput >= (time_t) settings.maxSilentTime)
3559 {
3560 printMsg(lvlError,
3561 format("%1% timed out after %2% seconds of silence")
3562 % goal->getName() % settings.maxSilentTime);
f3ff1da4 3563 goal->timedOut();
36457566
LC
3564 }
3565
3566 else if (goal->getExitCode() == Goal::ecBusy &&
3567 settings.buildTimeout != 0 &&
3568 j->second.respectTimeouts &&
3569 after - j->second.timeStarted >= (time_t) settings.buildTimeout)
3570 {
3571 printMsg(lvlError,
3572 format("%1% timed out after %2% seconds")
3573 % goal->getName() % settings.buildTimeout);
f3ff1da4 3574 goal->timedOut();
36457566
LC
3575 }
3576 }
3577
3578 if (!waitingForAWhile.empty() && lastWokenUp + settings.pollInterval <= after) {
3579 lastWokenUp = after;
3580 foreach (WeakGoals::iterator, i, waitingForAWhile) {
3581 GoalPtr goal = i->lock();
3582 if (goal) wakeUp(goal);
3583 }
3584 waitingForAWhile.clear();
3585 }
3586}
3587
3588
3589unsigned int Worker::exitStatus()
3590{
2bb04905 3591 return timedOut ? 101 : (permanentFailure ? 100 : 1);
36457566
LC
3592}
3593
3594
3595//////////////////////////////////////////////////////////////////////
3596
3597
3598void LocalStore::buildPaths(const PathSet & drvPaths, BuildMode buildMode)
3599{
3600 startNest(nest, lvlDebug,
3601 format("building %1%") % showPaths(drvPaths));
3602
3603 Worker worker(*this);
3604
3605 Goals goals;
3606 foreach (PathSet::const_iterator, i, drvPaths) {
3607 DrvPathWithOutputs i2 = parseDrvPathWithOutputs(*i);
3608 if (isDerivation(i2.first))
3609 goals.insert(worker.makeDerivationGoal(i2.first, i2.second, buildMode));
3610 else
3611 goals.insert(worker.makeSubstitutionGoal(*i, buildMode));
3612 }
3613
3614 worker.run(goals);
3615
3616 PathSet failed;
3617 foreach (Goals::iterator, i, goals)
3618 if ((*i)->getExitCode() == Goal::ecFailed) {
3619 DerivationGoal * i2 = dynamic_cast<DerivationGoal *>(i->get());
3620 if (i2) failed.insert(i2->getDrvPath());
3621 else failed.insert(dynamic_cast<SubstitutionGoal *>(i->get())->getStorePath());
3622 }
3623
3624 if (!failed.empty())
3625 throw Error(format("build of %1% failed") % showPaths(failed), worker.exitStatus());
3626}
3627
3628
3629void LocalStore::ensurePath(const Path & path)
3630{
3631 /* If the path is already valid, we're done. */
3632 if (isValidPath(path)) return;
3633
3634 Worker worker(*this);
3635 GoalPtr goal = worker.makeSubstitutionGoal(path);
3636 Goals goals = singleton<Goals>(goal);
3637
3638 worker.run(goals);
3639
3640 if (goal->getExitCode() != Goal::ecSuccess)
3641 throw Error(format("path `%1%' does not exist and cannot be created") % path, worker.exitStatus());
3642}
3643
3644
3645void LocalStore::repairPath(const Path & path)
3646{
3647 Worker worker(*this);
3648 GoalPtr goal = worker.makeSubstitutionGoal(path, true);
3649 Goals goals = singleton<Goals>(goal);
3650
3651 worker.run(goals);
3652
c56cd90c
ED
3653 if (goal->getExitCode() != Goal::ecSuccess) {
3654 /* Since substituting the path didn't work, if we have a valid
3655 deriver, then rebuild the deriver. */
3656 Path deriver = queryDeriver(path);
3657 if (deriver != "" && isValidPath(deriver)) {
3658 goals.clear();
3659 goals.insert(worker.makeDerivationGoal(deriver, StringSet(), bmRepair));
3660 worker.run(goals);
3661 } else
3662 throw Error(format("cannot repair path `%1%'") % path, worker.exitStatus());
3663 }
36457566
LC
3664}
3665
3666
3667}