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