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