1 #include "serialise.hh"
3 #include "remote-store.hh"
4 #include "worker-protocol.hh"
11 #include <sys/socket.h>
23 Path
readStorePath(Source
& from
)
25 Path path
= readString(from
);
26 assertStorePath(path
);
31 template<class T
> T
readStorePaths(Source
& from
)
33 T paths
= readStrings
<T
>(from
);
34 foreach (typename
T::iterator
, i
, paths
) assertStorePath(*i
);
38 template PathSet
readStorePaths(Source
& from
);
41 RemoteStore::RemoteStore()
47 void RemoteStore::openConnection(bool reserveSpace
)
49 if (initialised
) return;
52 string remoteMode
= getEnv("NIX_REMOTE");
54 if (remoteMode
== "daemon")
55 /* Connect to a daemon that does the privileged work for
59 throw Error(format("invalid setting for NIX_REMOTE, `%1%'") % remoteMode
);
64 /* Send the magic greeting, check for the reply. */
66 writeInt(WORKER_MAGIC_1
, to
);
68 unsigned int magic
= readInt(from
);
69 if (magic
!= WORKER_MAGIC_2
) throw Error("protocol mismatch");
71 daemonVersion
= readInt(from
);
72 if (GET_PROTOCOL_MAJOR(daemonVersion
) != GET_PROTOCOL_MAJOR(PROTOCOL_VERSION
))
73 throw Error("Nix daemon protocol version not supported");
74 writeInt(PROTOCOL_VERSION
, to
);
76 if (GET_PROTOCOL_MINOR(daemonVersion
) >= 14) {
77 int cpu
= settings
.lockCPU
? lockToCurrentCPU() : -1;
85 if (GET_PROTOCOL_MINOR(daemonVersion
) >= 11)
86 writeInt(reserveSpace
, to
);
91 throw Error(format("cannot start daemon worker: %1%") % e
.msg());
98 void RemoteStore::connectToDaemon()
100 fdSocket
= socket(PF_UNIX
, SOCK_STREAM
, 0);
102 throw SysError("cannot create Unix domain socket");
103 closeOnExec(fdSocket
);
105 string socketPath
= settings
.nixDaemonSocketFile
;
107 /* Urgh, sockaddr_un allows path names of only 108 characters. So
108 chdir to the socket directory so that we can pass a relative
109 path name. !!! this is probably a bad idea in multi-threaded
111 AutoCloseFD fdPrevDir
= open(".", O_RDONLY
);
112 if (fdPrevDir
== -1) throw SysError("couldn't open current directory");
113 if (chdir(dirOf(socketPath
).c_str()) == -1) throw SysError(format("couldn't change to directory of ‘%1%’") % socketPath
);
114 Path socketPathRel
= "./" + baseNameOf(socketPath
);
116 struct sockaddr_un addr
;
117 addr
.sun_family
= AF_UNIX
;
118 if (socketPathRel
.size() >= sizeof(addr
.sun_path
))
119 throw Error(format("socket path `%1%' is too long") % socketPathRel
);
121 strcpy(addr
.sun_path
, socketPathRel
.c_str());
123 if (connect(fdSocket
, (struct sockaddr
*) &addr
, sizeof(addr
)) == -1)
124 throw SysError(format("cannot connect to daemon at `%1%'") % socketPath
);
126 if (fchdir(fdPrevDir
) == -1)
127 throw SysError("couldn't change back to previous directory");
131 RemoteStore::~RemoteStore()
142 void RemoteStore::setOptions()
144 writeInt(wopSetOptions
, to
);
146 writeInt(settings
.keepFailed
, to
);
147 writeInt(settings
.keepGoing
, to
);
148 writeInt(settings
.tryFallback
, to
);
149 writeInt(verbosity
, to
);
150 writeInt(settings
.maxBuildJobs
, to
);
151 writeInt(settings
.maxSilentTime
, to
);
152 if (GET_PROTOCOL_MINOR(daemonVersion
) >= 2)
153 writeInt(settings
.useBuildHook
, to
);
154 if (GET_PROTOCOL_MINOR(daemonVersion
) >= 4) {
155 writeInt(settings
.buildVerbosity
, to
);
156 writeInt(logType
, to
);
157 writeInt(settings
.printBuildTrace
, to
);
159 if (GET_PROTOCOL_MINOR(daemonVersion
) >= 6)
160 writeInt(settings
.buildCores
, to
);
161 if (GET_PROTOCOL_MINOR(daemonVersion
) >= 10)
162 writeInt(settings
.useSubstitutes
, to
);
164 if (GET_PROTOCOL_MINOR(daemonVersion
) >= 12) {
165 Settings::SettingsMap overrides
= settings
.getOverrides();
166 writeInt(overrides
.size(), to
);
167 foreach (Settings::SettingsMap::iterator
, i
, overrides
) {
168 writeString(i
->first
, to
);
169 writeString(i
->second
, to
);
177 bool RemoteStore::isValidPath(const Path
& path
)
180 writeInt(wopIsValidPath
, to
);
181 writeString(path
, to
);
183 unsigned int reply
= readInt(from
);
188 PathSet
RemoteStore::queryValidPaths(const PathSet
& paths
)
191 if (GET_PROTOCOL_MINOR(daemonVersion
) < 12) {
193 foreach (PathSet::const_iterator
, i
, paths
)
194 if (isValidPath(*i
)) res
.insert(*i
);
197 writeInt(wopQueryValidPaths
, to
);
198 writeStrings(paths
, to
);
200 return readStorePaths
<PathSet
>(from
);
205 PathSet
RemoteStore::queryAllValidPaths()
208 writeInt(wopQueryAllValidPaths
, to
);
210 return readStorePaths
<PathSet
>(from
);
214 PathSet
RemoteStore::querySubstitutablePaths(const PathSet
& paths
)
217 if (GET_PROTOCOL_MINOR(daemonVersion
) < 12) {
219 foreach (PathSet::const_iterator
, i
, paths
) {
220 writeInt(wopHasSubstitutes
, to
);
223 if (readInt(from
)) res
.insert(*i
);
227 writeInt(wopQuerySubstitutablePaths
, to
);
228 writeStrings(paths
, to
);
230 return readStorePaths
<PathSet
>(from
);
235 void RemoteStore::querySubstitutablePathInfos(const PathSet
& paths
,
236 SubstitutablePathInfos
& infos
)
238 if (paths
.empty()) return;
242 if (GET_PROTOCOL_MINOR(daemonVersion
) < 3) return;
244 if (GET_PROTOCOL_MINOR(daemonVersion
) < 12) {
246 foreach (PathSet::const_iterator
, i
, paths
) {
247 SubstitutablePathInfo info
;
248 writeInt(wopQuerySubstitutablePathInfo
, to
);
251 unsigned int reply
= readInt(from
);
252 if (reply
== 0) continue;
253 info
.deriver
= readString(from
);
254 if (info
.deriver
!= "") assertStorePath(info
.deriver
);
255 info
.references
= readStorePaths
<PathSet
>(from
);
256 info
.downloadSize
= readLongLong(from
);
257 info
.narSize
= GET_PROTOCOL_MINOR(daemonVersion
) >= 7 ? readLongLong(from
) : 0;
263 writeInt(wopQuerySubstitutablePathInfos
, to
);
264 writeStrings(paths
, to
);
266 unsigned int count
= readInt(from
);
267 for (unsigned int n
= 0; n
< count
; n
++) {
268 Path path
= readStorePath(from
);
269 SubstitutablePathInfo
& info(infos
[path
]);
270 info
.deriver
= readString(from
);
271 if (info
.deriver
!= "") assertStorePath(info
.deriver
);
272 info
.references
= readStorePaths
<PathSet
>(from
);
273 info
.downloadSize
= readLongLong(from
);
274 info
.narSize
= readLongLong(from
);
281 ValidPathInfo
RemoteStore::queryPathInfo(const Path
& path
)
284 writeInt(wopQueryPathInfo
, to
);
285 writeString(path
, to
);
289 info
.deriver
= readString(from
);
290 if (info
.deriver
!= "") assertStorePath(info
.deriver
);
291 info
.hash
= parseHash(htSHA256
, readString(from
));
292 info
.references
= readStorePaths
<PathSet
>(from
);
293 info
.registrationTime
= readInt(from
);
294 info
.narSize
= readLongLong(from
);
299 Hash
RemoteStore::queryPathHash(const Path
& path
)
302 writeInt(wopQueryPathHash
, to
);
303 writeString(path
, to
);
305 string hash
= readString(from
);
306 return parseHash(htSHA256
, hash
);
310 void RemoteStore::queryReferences(const Path
& path
,
311 PathSet
& references
)
314 writeInt(wopQueryReferences
, to
);
315 writeString(path
, to
);
317 PathSet references2
= readStorePaths
<PathSet
>(from
);
318 references
.insert(references2
.begin(), references2
.end());
322 void RemoteStore::queryReferrers(const Path
& path
,
326 writeInt(wopQueryReferrers
, to
);
327 writeString(path
, to
);
329 PathSet referrers2
= readStorePaths
<PathSet
>(from
);
330 referrers
.insert(referrers2
.begin(), referrers2
.end());
334 Path
RemoteStore::queryDeriver(const Path
& path
)
337 writeInt(wopQueryDeriver
, to
);
338 writeString(path
, to
);
340 Path drvPath
= readString(from
);
341 if (drvPath
!= "") assertStorePath(drvPath
);
346 PathSet
RemoteStore::queryValidDerivers(const Path
& path
)
349 writeInt(wopQueryValidDerivers
, to
);
350 writeString(path
, to
);
352 return readStorePaths
<PathSet
>(from
);
356 PathSet
RemoteStore::queryDerivationOutputs(const Path
& path
)
359 writeInt(wopQueryDerivationOutputs
, to
);
360 writeString(path
, to
);
362 return readStorePaths
<PathSet
>(from
);
366 PathSet
RemoteStore::queryDerivationOutputNames(const Path
& path
)
369 writeInt(wopQueryDerivationOutputNames
, to
);
370 writeString(path
, to
);
372 return readStrings
<PathSet
>(from
);
376 Path
RemoteStore::queryPathFromHashPart(const string
& hashPart
)
379 writeInt(wopQueryPathFromHashPart
, to
);
380 writeString(hashPart
, to
);
382 Path path
= readString(from
);
383 if (!path
.empty()) assertStorePath(path
);
388 Path
RemoteStore::addToStore(const string
& name
, const Path
& _srcPath
,
389 bool recursive
, HashType hashAlgo
, PathFilter
& filter
, bool repair
)
391 if (repair
) throw Error("repairing is not supported when building through the Nix daemon");
395 Path
srcPath(absPath(_srcPath
));
397 writeInt(wopAddToStore
, to
);
398 writeString(name
, to
);
399 /* backwards compatibility hack */
400 writeInt((hashAlgo
== htSHA256
&& recursive
) ? 0 : 1, to
);
401 writeInt(recursive
? 1 : 0, to
);
402 writeString(printHashType(hashAlgo
), to
);
407 dumpPath(srcPath
, to
, filter
);
410 } catch (SysError
& e
) {
411 /* Daemon closed while we were sending the path. Probably OOM
413 if (e
.errNo
== EPIPE
)
416 } catch (EndOfFile
& e
) { }
420 return readStorePath(from
);
424 Path
RemoteStore::addTextToStore(const string
& name
, const string
& s
,
425 const PathSet
& references
, bool repair
)
427 if (repair
) throw Error("repairing is not supported when building through the Nix daemon");
430 writeInt(wopAddTextToStore
, to
);
431 writeString(name
, to
);
433 writeStrings(references
, to
);
436 return readStorePath(from
);
440 void RemoteStore::exportPath(const Path
& path
, bool sign
,
444 writeInt(wopExportPath
, to
);
445 writeString(path
, to
);
446 writeInt(sign
? 1 : 0, to
);
447 processStderr(&sink
); /* sink receives the actual data */
452 Paths
RemoteStore::importPaths(bool requireSignature
, Source
& source
)
455 writeInt(wopImportPaths
, to
);
456 /* We ignore requireSignature, since the worker forces it to true
458 processStderr(0, &source
);
459 return readStorePaths
<Paths
>(from
);
463 void RemoteStore::buildPaths(const PathSet
& drvPaths
, BuildMode buildMode
)
465 if (buildMode
!= bmNormal
) throw Error("repairing or checking is not supported when building through the Nix daemon");
467 writeInt(wopBuildPaths
, to
);
468 if (GET_PROTOCOL_MINOR(daemonVersion
) >= 13)
469 writeStrings(drvPaths
, to
);
471 /* For backwards compatibility with old daemons, strip output
474 foreach (PathSet::const_iterator
, i
, drvPaths
)
475 drvPaths2
.insert(string(*i
, 0, i
->find('!')));
476 writeStrings(drvPaths2
, to
);
483 void RemoteStore::ensurePath(const Path
& path
)
486 writeInt(wopEnsurePath
, to
);
487 writeString(path
, to
);
493 void RemoteStore::addTempRoot(const Path
& path
)
496 writeInt(wopAddTempRoot
, to
);
497 writeString(path
, to
);
503 void RemoteStore::addIndirectRoot(const Path
& path
)
506 writeInt(wopAddIndirectRoot
, to
);
507 writeString(path
, to
);
513 void RemoteStore::syncWithGC()
516 writeInt(wopSyncWithGC
, to
);
522 Roots
RemoteStore::findRoots()
525 writeInt(wopFindRoots
, to
);
527 unsigned int count
= readInt(from
);
530 Path link
= readString(from
);
531 Path target
= readStorePath(from
);
532 result
[link
] = target
;
538 void RemoteStore::collectGarbage(const GCOptions
& options
, GCResults
& results
)
540 openConnection(false);
542 writeInt(wopCollectGarbage
, to
);
543 writeInt(options
.action
, to
);
544 writeStrings(options
.pathsToDelete
, to
);
545 writeInt(options
.ignoreLiveness
, to
);
546 writeLongLong(options
.maxFreed
, to
);
548 if (GET_PROTOCOL_MINOR(daemonVersion
) >= 5) {
549 /* removed options */
556 results
.paths
= readStrings
<PathSet
>(from
);
557 results
.bytesFreed
= readLongLong(from
);
558 readLongLong(from
); // obsolete
562 PathSet
RemoteStore::queryFailedPaths()
565 writeInt(wopQueryFailedPaths
, to
);
567 return readStorePaths
<PathSet
>(from
);
571 void RemoteStore::clearFailedPaths(const PathSet
& paths
)
574 writeInt(wopClearFailedPaths
, to
);
575 writeStrings(paths
, to
);
580 void RemoteStore::optimiseStore()
583 writeInt(wopOptimiseStore
, to
);
588 bool RemoteStore::verifyStore(bool checkContents
, bool repair
)
591 writeInt(wopVerifyStore
, to
);
592 writeInt(checkContents
, to
);
593 writeInt(repair
, to
);
595 return readInt(from
) != 0;
598 void RemoteStore::processStderr(Sink
* sink
, Source
* source
)
602 while ((msg
= readInt(from
)) == STDERR_NEXT
603 || msg
== STDERR_READ
|| msg
== STDERR_WRITE
) {
604 if (msg
== STDERR_WRITE
) {
605 string s
= readString(from
);
606 if (!sink
) throw Error("no sink");
607 (*sink
)((const unsigned char *) s
.data(), s
.size());
609 else if (msg
== STDERR_READ
) {
610 if (!source
) throw Error("no source");
611 size_t len
= readInt(from
);
612 unsigned char * buf
= new unsigned char[len
];
613 AutoDeleteArray
<unsigned char> d(buf
);
614 writeString(buf
, source
->read(buf
, len
), to
);
618 string s
= readString(from
);
622 if (msg
== STDERR_ERROR
) {
623 string error
= readString(from
);
624 unsigned int status
= GET_PROTOCOL_MINOR(daemonVersion
) >= 8 ? readInt(from
) : 1;
625 throw Error(format("%1%") % error
, status
);
627 else if (msg
!= STDERR_LAST
)
628 throw Error("protocol error processing standard error");