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