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