2 #include "local-store.hh"
5 #include "pathlocks.hh"
6 #include "worker-protocol.hh"
7 #include "derivations.hh"
14 #include <sys/types.h>
26 #if HAVE_UNSHARE && HAVE_STATVFS && HAVE_SYS_MOUNT_H
28 #include <sys/statvfs.h>
29 #include <sys/mount.h>
32 #include <sys/ioctl.h>
41 void checkStoreNotSymlink()
43 if (getEnv("NIX_IGNORE_SYMLINK_STORE") == "1") return;
44 Path path
= settings
.nixStore
;
47 if (lstat(path
.c_str(), &st
))
48 throw SysError(format("getting status of `%1%'") % path
);
49 if (S_ISLNK(st
.st_mode
))
51 "the path `%1%' is a symlink; "
52 "this is not allowed for the store and its parent directories")
59 LocalStore::LocalStore(bool reserveSpace
)
60 : didSetSubstituterEnv(false)
62 schemaPath
= settings
.nixDBPath
+ "/schema";
64 if (settings
.readOnlyMode
) {
69 /* Create missing state directories if they don't already exist. */
70 createDirs(settings
.nixStore
);
72 createDirs(linksDir
= settings
.nixStore
+ "/.links");
73 Path profilesDir
= settings
.nixStateDir
+ "/profiles";
74 createDirs(profilesDir
);
75 createDirs(settings
.nixStateDir
+ "/temproots");
76 createDirs(settings
.nixDBPath
);
77 Path gcRootsDir
= settings
.nixStateDir
+ "/gcroots";
78 if (!pathExists(gcRootsDir
)) {
79 createDirs(gcRootsDir
);
80 createSymlink(profilesDir
, gcRootsDir
+ "/profiles");
83 /* Optionally, create directories and set permissions for a
84 multi-user install. */
85 if (getuid() == 0 && settings
.buildUsersGroup
!= "") {
87 Path perUserDir
= profilesDir
+ "/per-user";
88 createDirs(perUserDir
);
89 if (chmod(perUserDir
.c_str(), 0755) == -1)
90 throw SysError(format("could not set permissions on '%1%' to 755")
95 struct group
* gr
= getgrnam(settings
.buildUsersGroup
.c_str());
97 throw Error(format("the group `%1%' specified in `build-users-group' does not exist")
98 % settings
.buildUsersGroup
);
101 if (stat(settings
.nixStore
.c_str(), &st
))
102 throw SysError(format("getting attributes of path '%1%'") % settings
.nixStore
);
104 if (st
.st_uid
!= 0 || st
.st_gid
!= gr
->gr_gid
|| (st
.st_mode
& ~S_IFMT
) != perm
) {
105 if (chown(settings
.nixStore
.c_str(), 0, gr
->gr_gid
) == -1)
106 throw SysError(format("changing ownership of path '%1%'") % settings
.nixStore
);
107 if (chmod(settings
.nixStore
.c_str(), perm
) == -1)
108 throw SysError(format("changing permissions on path '%1%'") % settings
.nixStore
);
113 checkStoreNotSymlink();
115 /* We can't open a SQLite database if the disk is full. Since
116 this prevents the garbage collector from running when it's most
117 needed, we reserve some dummy space that we can free just
118 before doing a garbage collection. */
120 Path reservedPath
= settings
.nixDBPath
+ "/reserved";
123 if (stat(reservedPath
.c_str(), &st
) == -1 ||
124 st
.st_size
!= settings
.reservedSize
)
126 AutoCloseFD fd
= open(reservedPath
.c_str(), O_WRONLY
| O_CREAT
, 0600);
128 #if HAVE_POSIX_FALLOCATE
129 res
= posix_fallocate(fd
, 0, settings
.reservedSize
);
132 writeFull(fd
, string(settings
.reservedSize
, 'X'));
133 ftruncate(fd
, settings
.reservedSize
);
138 deletePath(reservedPath
);
139 } catch (SysError
& e
) { /* don't care about errors */
142 /* Acquire the big fat lock in shared mode to make sure that no
143 schema upgrade is in progress. */
145 Path globalLockPath
= settings
.nixDBPath
+ "/big-lock";
146 globalLock
= openLockFile(globalLockPath
.c_str(), true);
147 } catch (SysError
& e
) {
148 if (e
.errNo
!= EACCES
) throw;
149 settings
.readOnlyMode
= true;
154 if (!lockFile(globalLock
, ltRead
, false)) {
155 printMsg(lvlError
, "waiting for the big store lock...");
156 lockFile(globalLock
, ltRead
, true);
159 /* Check the current database schema and if necessary do an
161 int curSchema
= getSchema();
162 if (curSchema
> nixSchemaVersion
)
163 throw Error(format("current store schema is version %1%, but I only support %2%")
164 % curSchema
% nixSchemaVersion
);
166 else if (curSchema
== 0) { /* new store */
167 curSchema
= nixSchemaVersion
;
169 writeFile(schemaPath
, (format("%1%") % nixSchemaVersion
).str());
172 else if (curSchema
< nixSchemaVersion
) {
173 /* Guix always used version 7 of the schema. */
175 format("Your store database uses an implausibly old schema, version %1%.")
183 LocalStore::~LocalStore()
186 if (runningSubstituter
) {
187 RunningSubstituter
&i
= *runningSubstituter
;
201 if (fdTempRoots
!= -1) {
203 unlink(fnTempRoots
.c_str());
211 int LocalStore::getSchema()
214 if (pathExists(schemaPath
)) {
215 string s
= readFile(schemaPath
);
216 if (!string2Int(s
, curSchema
))
217 throw Error(format("`%1%' is corrupt") % schemaPath
);
223 void LocalStore::openDB(bool create
)
225 if (access(settings
.nixDBPath
.c_str(), R_OK
| W_OK
))
226 throw SysError(format("store database directory `%1%' is not writable") % settings
.nixDBPath
);
228 /* Open the store database. */
229 string dbPath
= settings
.nixDBPath
+ "/db.sqlite";
230 if (sqlite3_open_v2(dbPath
.c_str(), &db
.db
,
231 SQLITE_OPEN_READWRITE
| (create
? SQLITE_OPEN_CREATE
: 0), 0) != SQLITE_OK
)
232 throw Error(format("cannot open store database `%1%'") % dbPath
);
234 if (sqlite3_busy_timeout(db
, 60 * 60 * 1000) != SQLITE_OK
)
235 throwSQLiteError(db
, "setting timeout");
237 if (sqlite3_exec(db
, "pragma foreign_keys = 1;", 0, 0, 0) != SQLITE_OK
)
238 throwSQLiteError(db
, "enabling foreign keys");
240 /* !!! check whether sqlite has been built with foreign key
243 /* Whether SQLite should fsync(). "Normal" synchronous mode
244 should be safe enough. If the user asks for it, don't sync at
245 all. This can cause database corruption if the system
247 string syncMode
= settings
.fsyncMetadata
? "normal" : "off";
248 if (sqlite3_exec(db
, ("pragma synchronous = " + syncMode
+ ";").c_str(), 0, 0, 0) != SQLITE_OK
)
249 throwSQLiteError(db
, "setting synchronous mode");
251 /* Set the SQLite journal mode. WAL mode is fastest, so it's the
253 string mode
= settings
.useSQLiteWAL
? "wal" : "truncate";
257 stmt
.create(db
, "pragma main.journal_mode;");
258 if (sqlite3_step(stmt
) != SQLITE_ROW
)
259 throwSQLiteError(db
, "querying journal mode");
260 prevMode
= string((const char *) sqlite3_column_text(stmt
, 0));
262 if (prevMode
!= mode
&&
263 sqlite3_exec(db
, ("pragma main.journal_mode = " + mode
+ ";").c_str(), 0, 0, 0) != SQLITE_OK
)
264 throwSQLiteError(db
, "setting journal mode");
266 /* Increase the auto-checkpoint interval to 40000 pages. This
267 seems enough to ensure that instantiating the NixOS system
268 derivation is done in a single fsync(). */
269 if (mode
== "wal" && sqlite3_exec(db
, "pragma wal_autocheckpoint = 40000;", 0, 0, 0) != SQLITE_OK
)
270 throwSQLiteError(db
, "setting autocheckpoint interval");
272 /* Initialise the database schema, if necessary. */
274 const char * schema
=
275 #include "schema.sql.hh"
277 if (sqlite3_exec(db
, (const char *) schema
, 0, 0, 0) != SQLITE_OK
)
278 throwSQLiteError(db
, "initialising database schema");
281 /* Prepare SQL statements. */
282 stmtRegisterValidPath
.create(db
,
283 "insert into ValidPaths (path, hash, registrationTime, deriver, narSize) values (?, ?, ?, ?, ?);");
284 stmtUpdatePathInfo
.create(db
,
285 "update ValidPaths set narSize = ?, hash = ? where path = ?;");
286 stmtAddReference
.create(db
,
287 "insert or replace into Refs (referrer, reference) values (?, ?);");
288 stmtQueryPathInfo
.create(db
,
289 "select id, hash, registrationTime, deriver, narSize from ValidPaths where path = ?;");
290 stmtQueryReferences
.create(db
,
291 "select path from Refs join ValidPaths on reference = id where referrer = ?;");
292 stmtQueryReferrers
.create(db
,
293 "select path from Refs join ValidPaths on referrer = id where reference = (select id from ValidPaths where path = ?);");
294 stmtInvalidatePath
.create(db
,
295 "delete from ValidPaths where path = ?;");
296 stmtRegisterFailedPath
.create(db
,
297 "insert or ignore into FailedPaths (path, time) values (?, ?);");
298 stmtHasPathFailed
.create(db
,
299 "select time from FailedPaths where path = ?;");
300 stmtQueryFailedPaths
.create(db
,
301 "select path from FailedPaths;");
302 // If the path is a derivation, then clear its outputs.
303 stmtClearFailedPath
.create(db
,
304 "delete from FailedPaths where ?1 = '*' or path = ?1 "
305 "or path in (select d.path from DerivationOutputs d join ValidPaths v on d.drv = v.id where v.path = ?1);");
306 stmtAddDerivationOutput
.create(db
,
307 "insert or replace into DerivationOutputs (drv, id, path) values (?, ?, ?);");
308 stmtQueryValidDerivers
.create(db
,
309 "select v.id, v.path from DerivationOutputs d join ValidPaths v on d.drv = v.id where d.path = ?;");
310 stmtQueryDerivationOutputs
.create(db
,
311 "select id, path from DerivationOutputs where drv = ?;");
312 // Use "path >= ?" with limit 1 rather than "path like '?%'" to
313 // ensure efficient lookup.
314 stmtQueryPathFromHashPart
.create(db
,
315 "select path from ValidPaths where path >= ? limit 1;");
316 stmtQueryValidPaths
.create(db
, "select path from ValidPaths");
320 /* To improve purity, users may want to make the store a read-only
321 bind mount. So make the store writable for this process. */
322 void LocalStore::makeStoreWritable()
324 #if HAVE_UNSHARE && HAVE_STATVFS && HAVE_SYS_MOUNT_H && defined(MS_BIND) && defined(MS_REMOUNT)
325 if (getuid() != 0) return;
326 /* Check if /nix/store is on a read-only mount. */
328 if (statvfs(settings
.nixStore
.c_str(), &stat
) != 0)
329 throw SysError("getting info about the store mount point");
331 if (stat
.f_flag
& ST_RDONLY
) {
332 if (unshare(CLONE_NEWNS
) == -1)
333 throw SysError("setting up a private mount namespace");
335 if (mount(0, settings
.nixStore
.c_str(), "none", MS_REMOUNT
| MS_BIND
, 0) == -1)
336 throw SysError(format("remounting %1% writable") % settings
.nixStore
);
342 const time_t mtimeStore
= 1; /* 1 second into the epoch */
345 static void canonicaliseTimestampAndPermissions(const Path
& path
, const struct stat
& st
)
347 if (!S_ISLNK(st
.st_mode
)) {
349 /* Mask out all type related bits. */
350 mode_t mode
= st
.st_mode
& ~S_IFMT
;
352 if (mode
!= 0444 && mode
!= 0555) {
353 mode
= (st
.st_mode
& S_IFMT
)
355 | (st
.st_mode
& S_IXUSR
? 0111 : 0);
356 if (chmod(path
.c_str(), mode
) == -1)
357 throw SysError(format("changing mode of `%1%' to %2$o") % path
% mode
);
362 if (st
.st_mtime
!= mtimeStore
) {
363 struct timeval times
[2];
364 times
[0].tv_sec
= st
.st_atime
;
365 times
[0].tv_usec
= 0;
366 times
[1].tv_sec
= mtimeStore
;
367 times
[1].tv_usec
= 0;
369 if (lutimes(path
.c_str(), times
) == -1)
370 if (errno
!= ENOSYS
||
371 (!S_ISLNK(st
.st_mode
) && utimes(path
.c_str(), times
) == -1))
373 if (!S_ISLNK(st
.st_mode
) && utimes(path
.c_str(), times
) == -1)
375 throw SysError(format("changing modification time of `%1%'") % path
);
380 void canonicaliseTimestampAndPermissions(const Path
& path
)
383 if (lstat(path
.c_str(), &st
))
384 throw SysError(format("getting attributes of path `%1%'") % path
);
385 canonicaliseTimestampAndPermissions(path
, st
);
389 static void canonicalisePathMetaData_(const Path
& path
, uid_t fromUid
, InodesSeen
& inodesSeen
)
394 if (lstat(path
.c_str(), &st
))
395 throw SysError(format("getting attributes of path `%1%'") % path
);
397 /* Really make sure that the path is of a supported type. */
398 if (!(S_ISREG(st
.st_mode
) || S_ISDIR(st
.st_mode
) || S_ISLNK(st
.st_mode
)))
399 throw Error(format("file ‘%1%’ has an unsupported type") % path
);
401 /* Fail if the file is not owned by the build user. This prevents
402 us from messing up the ownership/permissions of files
403 hard-linked into the output (e.g. "ln /etc/shadow $out/foo").
404 However, ignore files that we chown'ed ourselves previously to
405 ensure that we don't fail on hard links within the same build
406 (i.e. "touch $out/foo; ln $out/foo $out/bar"). */
407 if (fromUid
!= (uid_t
) -1 && st
.st_uid
!= fromUid
) {
408 assert(!S_ISDIR(st
.st_mode
));
409 if (inodesSeen
.find(Inode(st
.st_dev
, st
.st_ino
)) == inodesSeen
.end())
410 throw BuildError(format("invalid ownership on file `%1%'") % path
);
411 mode_t mode
= st
.st_mode
& ~S_IFMT
;
412 assert(S_ISLNK(st
.st_mode
) || (st
.st_uid
== geteuid() && (mode
== 0444 || mode
== 0555) && st
.st_mtime
== mtimeStore
));
416 inodesSeen
.insert(Inode(st
.st_dev
, st
.st_ino
));
418 canonicaliseTimestampAndPermissions(path
, st
);
420 /* Change ownership to the current uid. If it's a symlink, use
421 lchown if available, otherwise don't bother. Wrong ownership
422 of a symlink doesn't matter, since the owning user can't change
423 the symlink and can't delete it because the directory is not
424 writable. The only exception is top-level paths in the
425 store (since that directory is group-writable for the build
426 users group); we check for this case below. */
427 if (st
.st_uid
!= geteuid()) {
429 if (lchown(path
.c_str(), geteuid(), getegid()) == -1)
431 if (!S_ISLNK(st
.st_mode
) &&
432 chown(path
.c_str(), geteuid(), getegid()) == -1)
434 throw SysError(format("changing owner of `%1%' to %2%")
438 if (S_ISDIR(st
.st_mode
)) {
439 DirEntries entries
= readDirectory(path
);
440 for (auto & i
: entries
)
441 canonicalisePathMetaData_(path
+ "/" + i
.name
, fromUid
, inodesSeen
);
446 void canonicalisePathMetaData(const Path
& path
, uid_t fromUid
, InodesSeen
& inodesSeen
)
448 canonicalisePathMetaData_(path
, fromUid
, inodesSeen
);
450 /* On platforms that don't have lchown(), the top-level path can't
451 be a symlink, since we can't change its ownership. */
453 if (lstat(path
.c_str(), &st
))
454 throw SysError(format("getting attributes of path `%1%'") % path
);
456 if (st
.st_uid
!= geteuid()) {
457 assert(S_ISLNK(st
.st_mode
));
458 throw Error(format("wrong ownership of top-level store path `%1%'") % path
);
463 void canonicalisePathMetaData(const Path
& path
, uid_t fromUid
)
465 InodesSeen inodesSeen
;
466 canonicalisePathMetaData(path
, fromUid
, inodesSeen
);
470 void LocalStore::checkDerivationOutputs(const Path
& drvPath
, const Derivation
& drv
)
472 string drvName
= storePathToName(drvPath
);
473 assert(isDerivation(drvName
));
474 drvName
= string(drvName
, 0, drvName
.size() - drvExtension
.size());
476 if (isFixedOutputDrv(drv
)) {
477 DerivationOutputs::const_iterator out
= drv
.outputs
.find("out");
478 if (out
== drv
.outputs
.end())
479 throw Error(format("derivation `%1%' does not have an output named `out'") % drvPath
);
481 bool recursive
; HashType ht
; Hash h
;
482 out
->second
.parseHashInfo(recursive
, ht
, h
);
483 Path outPath
= makeFixedOutputPath(recursive
, ht
, h
, drvName
);
485 StringPairs::const_iterator j
= drv
.env
.find("out");
486 if (out
->second
.path
!= outPath
|| j
== drv
.env
.end() || j
->second
!= outPath
)
487 throw Error(format("derivation `%1%' has incorrect output `%2%', should be `%3%'")
488 % drvPath
% out
->second
.path
% outPath
);
492 Derivation
drvCopy(drv
);
493 foreach (DerivationOutputs::iterator
, i
, drvCopy
.outputs
) {
495 drvCopy
.env
[i
->first
] = "";
498 Hash h
= hashDerivationModulo(*this, drvCopy
);
500 foreach (DerivationOutputs::const_iterator
, i
, drv
.outputs
) {
501 Path outPath
= makeOutputPath(i
->first
, h
, drvName
);
502 StringPairs::const_iterator j
= drv
.env
.find(i
->first
);
503 if (i
->second
.path
!= outPath
|| j
== drv
.env
.end() || j
->second
!= outPath
)
504 throw Error(format("derivation `%1%' has incorrect output `%2%', should be `%3%'")
505 % drvPath
% i
->second
.path
% outPath
);
511 uint64_t LocalStore::addValidPath(const ValidPathInfo
& info
, bool checkOutputs
)
513 stmtRegisterValidPath
.use()
515 ("sha256:" + printHash(info
.hash
))
516 (info
.registrationTime
== 0 ? time(0) : info
.registrationTime
)
517 (info
.deriver
, info
.deriver
!= "")
518 (info
.narSize
, info
.narSize
!= 0)
520 uint64_t id
= sqlite3_last_insert_rowid(db
);
522 /* If this is a derivation, then store the derivation outputs in
523 the database. This is useful for the garbage collector: it can
524 efficiently query whether a path is an output of some
526 if (isDerivation(info
.path
)) {
527 Derivation drv
= readDerivation(info
.path
);
529 /* Verify that the output paths in the derivation are correct
530 (i.e., follow the scheme for computing output paths from
531 derivations). Note that if this throws an error, then the
532 DB transaction is rolled back, so the path validity
533 registration above is undone. */
534 if (checkOutputs
) checkDerivationOutputs(info
.path
, drv
);
536 for (auto & i
: drv
.outputs
) {
537 stmtAddDerivationOutput
.use()
549 void LocalStore::addReference(uint64_t referrer
, uint64_t reference
)
551 stmtAddReference
.use()(referrer
)(reference
).exec();
555 void LocalStore::registerFailedPath(const Path
& path
)
557 retrySQLite
<void>([&]() {
558 stmtRegisterFailedPath
.use()(path
)(time(0)).step();
563 bool LocalStore::hasPathFailed(const Path
& path
)
565 return retrySQLite
<bool>([&]() {
566 return stmtHasPathFailed
.use()(path
).next();
571 PathSet
LocalStore::queryFailedPaths()
573 return retrySQLite
<PathSet
>([&]() {
574 auto useQueryFailedPaths(stmtQueryFailedPaths
.use());
577 while (useQueryFailedPaths
.next())
578 res
.insert(useQueryFailedPaths
.getStr(0));
585 void LocalStore::clearFailedPaths(const PathSet
& paths
)
587 retrySQLite
<void>([&]() {
590 for (auto & path
: paths
)
591 stmtClearFailedPath
.use()(path
).exec();
598 Hash
parseHashField(const Path
& path
, const string
& s
)
600 string::size_type colon
= s
.find(':');
601 if (colon
== string::npos
)
602 throw Error(format("corrupt hash `%1%' in valid-path entry for `%2%'")
604 HashType ht
= parseHashType(string(s
, 0, colon
));
606 throw Error(format("unknown hash type `%1%' in valid-path entry for `%2%'")
607 % string(s
, 0, colon
) % path
);
608 return parseHash(ht
, string(s
, colon
+ 1));
612 ValidPathInfo
LocalStore::queryPathInfo(const Path
& path
)
617 assertStorePath(path
);
619 return retrySQLite
<ValidPathInfo
>([&]() {
621 /* Get the path info. */
622 auto useQueryPathInfo(stmtQueryPathInfo
.use()(path
));
624 if (!useQueryPathInfo
.next())
625 throw Error(format("path `%1%' is not valid") % path
);
627 info
.id
= useQueryPathInfo
.getInt(0);
629 info
.hash
= parseHashField(path
, useQueryPathInfo
.getStr(1));
631 info
.registrationTime
= useQueryPathInfo
.getInt(2);
633 auto s
= (const char *) sqlite3_column_text(stmtQueryPathInfo
, 3);
634 if (s
) info
.deriver
= s
;
636 /* Note that narSize = NULL yields 0. */
637 info
.narSize
= useQueryPathInfo
.getInt(4);
639 /* Get the references. */
640 auto useQueryReferences(stmtQueryReferences
.use()(info
.id
));
642 while (useQueryReferences
.next())
643 info
.references
.insert(useQueryReferences
.getStr(0));
650 /* Update path info in the database. Currently only updates the
652 void LocalStore::updatePathInfo(const ValidPathInfo
& info
)
654 stmtUpdatePathInfo
.use()
655 (info
.narSize
, info
.narSize
!= 0)
656 ("sha256:" + printHash(info
.hash
))
662 uint64_t LocalStore::queryValidPathId(const Path
& path
)
664 auto use(stmtQueryPathInfo
.use()(path
));
666 throw Error(format("path ‘%1%’ is not valid") % path
);
667 return use
.getInt(0);
671 bool LocalStore::isValidPath_(const Path
& path
)
673 return stmtQueryPathInfo
.use()(path
).next();
677 bool LocalStore::isValidPath(const Path
& path
)
679 return retrySQLite
<bool>([&]() {
680 return isValidPath_(path
);
685 PathSet
LocalStore::queryValidPaths(const PathSet
& paths
)
687 return retrySQLite
<PathSet
>([&]() {
689 foreach (PathSet::const_iterator
, i
, paths
)
690 if (isValidPath_(*i
)) res
.insert(*i
);
696 PathSet
LocalStore::queryAllValidPaths()
698 return retrySQLite
<PathSet
>([&]() {
699 auto use(stmtQueryValidPaths
.use());
701 while (use
.next()) res
.insert(use
.getStr(0));
707 void LocalStore::queryReferences(const Path
& path
,
708 PathSet
& references
)
710 ValidPathInfo info
= queryPathInfo(path
);
711 references
.insert(info
.references
.begin(), info
.references
.end());
715 void LocalStore::queryReferrers_(const Path
& path
, PathSet
& referrers
)
717 auto useQueryReferrers(stmtQueryReferrers
.use()(path
));
719 while (useQueryReferrers
.next())
720 referrers
.insert(useQueryReferrers
.getStr(0));
724 void LocalStore::queryReferrers(const Path
& path
, PathSet
& referrers
)
726 assertStorePath(path
);
727 return retrySQLite
<void>([&]() {
728 queryReferrers_(path
, referrers
);
733 Path
LocalStore::queryDeriver(const Path
& path
)
735 return queryPathInfo(path
).deriver
;
739 PathSet
LocalStore::queryValidDerivers(const Path
& path
)
741 assertStorePath(path
);
743 return retrySQLite
<PathSet
>([&]() {
744 auto useQueryValidDerivers(stmtQueryValidDerivers
.use()(path
));
747 while (useQueryValidDerivers
.next())
748 derivers
.insert(useQueryValidDerivers
.getStr(1));
755 PathSet
LocalStore::queryDerivationOutputs(const Path
& path
)
757 return retrySQLite
<PathSet
>([&]() {
758 auto useQueryDerivationOutputs(stmtQueryDerivationOutputs
.use()(queryValidPathId(path
)));
761 while (useQueryDerivationOutputs
.next())
762 outputs
.insert(useQueryDerivationOutputs
.getStr(1));
769 StringSet
LocalStore::queryDerivationOutputNames(const Path
& path
)
771 return retrySQLite
<StringSet
>([&]() {
772 auto useQueryDerivationOutputs(stmtQueryDerivationOutputs
.use()(queryValidPathId(path
)));
774 StringSet outputNames
;
775 while (useQueryDerivationOutputs
.next())
776 outputNames
.insert(useQueryDerivationOutputs
.getStr(0));
783 Path
LocalStore::queryPathFromHashPart(const string
& hashPart
)
785 if (hashPart
.size() != 32) throw Error("invalid hash part");
787 Path prefix
= settings
.nixStore
+ "/" + hashPart
;
789 return retrySQLite
<Path
>([&]() -> Path
{
790 auto useQueryPathFromHashPart(stmtQueryPathFromHashPart
.use()(prefix
));
792 if (!useQueryPathFromHashPart
.next()) return "";
794 const char * s
= (const char *) sqlite3_column_text(stmtQueryPathFromHashPart
, 0);
795 return s
&& prefix
.compare(0, prefix
.size(), s
, prefix
.size()) == 0 ? s
: "";
800 void LocalStore::setSubstituterEnv()
802 if (didSetSubstituterEnv
) return;
804 /* Pass configuration options (including those overridden with
805 --option) to substituters. */
806 setenv("_NIX_OPTIONS", settings
.pack().c_str(), 1);
808 didSetSubstituterEnv
= true;
812 void LocalStore::startSubstituter(RunningSubstituter
& run
)
814 if (run
.disabled
|| run
.pid
!= -1) return;
816 debug(format("starting substituter program `%1% substitute'")
817 % settings
.guixProgram
);
819 Pipe toPipe
, fromPipe
, errorPipe
;
827 run
.pid
= startProcess([&]() {
828 if (dup2(toPipe
.readSide
, STDIN_FILENO
) == -1)
829 throw SysError("dupping stdin");
830 if (dup2(fromPipe
.writeSide
, STDOUT_FILENO
) == -1)
831 throw SysError("dupping stdout");
832 if (dup2(errorPipe
.writeSide
, STDERR_FILENO
) == -1)
833 throw SysError("dupping stderr");
834 execl(settings
.guixProgram
.c_str(), "guix", "substitute", "--query", NULL
);
835 throw SysError(format("executing `%1%'") % settings
.guixProgram
);
838 run
.to
= toPipe
.writeSide
.borrow();
839 run
.from
= run
.fromBuf
.fd
= fromPipe
.readSide
.borrow();
840 run
.error
= errorPipe
.readSide
.borrow();
842 toPipe
.readSide
.close();
843 fromPipe
.writeSide
.close();
844 errorPipe
.writeSide
.close();
846 /* The substituter may exit right away if it's disabled in any way
847 (e.g. copy-from-other-stores.pl will exit if no other stores
850 getLineFromSubstituter(run
);
851 } catch (EndOfFile
& e
) {
856 if (run
.pid
.wait(true) != 0) throw;
861 /* Read a line from the substituter's stdout, while also processing
863 string
LocalStore::getLineFromSubstituter(RunningSubstituter
& run
)
867 /* We might have stdout data left over from the last time. */
868 if (run
.fromBuf
.hasData()) goto haveData
;
875 FD_SET(run
.from
, &fds
);
876 FD_SET(run
.error
, &fds
);
878 /* Wait for data to appear on the substituter's stdout or
880 if (select(run
.from
> run
.error
? run
.from
+ 1 : run
.error
+ 1, &fds
, 0, 0, 0) == -1) {
881 if (errno
== EINTR
) continue;
882 throw SysError("waiting for input from the substituter");
885 /* Completely drain stderr before dealing with stdout. */
886 if (FD_ISSET(run
.error
, &fds
)) {
888 ssize_t n
= read(run
.error
, (unsigned char *) buf
, sizeof(buf
));
890 if (errno
== EINTR
) continue;
891 throw SysError("reading from substituter's stderr");
893 if (n
== 0) throw EndOfFile(format("`%1% substitute' died unexpectedly")
894 % settings
.guixProgram
);
897 while (((p
= err
.find('\n')) != string::npos
)
898 || ((p
= err
.find('\r')) != string::npos
)) {
899 string
thing(err
, 0, p
+ 1);
900 writeToStderr("substitute: " + thing
);
901 err
= string(err
, p
+ 1);
905 /* Read from stdout until we get a newline or the buffer is empty. */
906 else if (run
.fromBuf
.hasData() || FD_ISSET(run
.from
, &fds
)) {
912 if (!err
.empty()) printMsg(lvlError
, "substitute: " + err
);
916 } while (run
.fromBuf
.hasData());
922 template<class T
> T
LocalStore::getIntLineFromSubstituter(RunningSubstituter
& run
)
924 string s
= getLineFromSubstituter(run
);
926 if (!string2Int(s
, res
)) throw Error("integer expected from stream");
931 PathSet
LocalStore::querySubstitutablePaths(const PathSet
& paths
)
935 if (!settings
.useSubstitutes
|| paths
.empty()) return res
;
937 if (!runningSubstituter
) {
938 std::unique_ptr
<RunningSubstituter
>fresh(new RunningSubstituter
);
939 runningSubstituter
.swap(fresh
);
942 RunningSubstituter
& run
= *runningSubstituter
;
943 startSubstituter(run
);
947 foreach (PathSet::const_iterator
, j
, paths
)
948 if (res
.find(*j
) == res
.end()) { s
+= *j
; s
+= " "; }
949 writeLine(run
.to
, s
);
951 /* FIXME: we only read stderr when an error occurs, so
952 substituters should only write (short) messages to
953 stderr when they fail. I.e. they shouldn't write debug
955 Path path
= getLineFromSubstituter(run
);
956 if (path
== "") break;
965 void LocalStore::querySubstitutablePathInfos(PathSet
& paths
, SubstitutablePathInfos
& infos
)
967 if (!settings
.useSubstitutes
) return;
969 if (!runningSubstituter
) {
970 std::unique_ptr
<RunningSubstituter
>fresh(new RunningSubstituter
);
971 runningSubstituter
.swap(fresh
);
974 RunningSubstituter
& run
= *runningSubstituter
;
975 startSubstituter(run
);
976 if (run
.disabled
) return;
979 foreach (PathSet::const_iterator
, i
, paths
)
980 if (infos
.find(*i
) == infos
.end()) { s
+= *i
; s
+= " "; }
981 writeLine(run
.to
, s
);
984 Path path
= getLineFromSubstituter(run
);
985 if (path
== "") break;
986 if (paths
.find(path
) == paths
.end())
987 throw Error(format("got unexpected path `%1%' from substituter") % path
);
989 SubstitutablePathInfo
& info(infos
[path
]);
990 info
.deriver
= getLineFromSubstituter(run
);
991 if (info
.deriver
!= "") assertStorePath(info
.deriver
);
992 int nrRefs
= getIntLineFromSubstituter
<int>(run
);
994 Path p
= getLineFromSubstituter(run
);
996 info
.references
.insert(p
);
998 info
.downloadSize
= getIntLineFromSubstituter
<long long>(run
);
999 info
.narSize
= getIntLineFromSubstituter
<long long>(run
);
1004 void LocalStore::querySubstitutablePathInfos(const PathSet
& paths
,
1005 SubstitutablePathInfos
& infos
)
1007 if (!paths
.empty()) {
1008 PathSet todo
= paths
;
1009 querySubstitutablePathInfos(todo
, infos
);
1014 Hash
LocalStore::queryPathHash(const Path
& path
)
1016 return queryPathInfo(path
).hash
;
1020 void LocalStore::registerValidPath(const ValidPathInfo
& info
)
1022 ValidPathInfos infos
;
1023 infos
.push_back(info
);
1024 registerValidPaths(infos
);
1028 void LocalStore::registerValidPaths(const ValidPathInfos
& infos
)
1030 /* SQLite will fsync by default, but the new valid paths may not be fsync-ed.
1031 * So some may want to fsync them before registering the validity, at the
1032 * expense of some speed of the path registering operation. */
1033 if (settings
.syncBeforeRegistering
) sync();
1035 return retrySQLite
<void>([&]() {
1039 foreach (ValidPathInfos::const_iterator
, i
, infos
) {
1040 assert(i
->hash
.type
== htSHA256
);
1041 if (isValidPath_(i
->path
))
1044 addValidPath(*i
, false);
1045 paths
.insert(i
->path
);
1048 for (auto & i
: infos
) {
1049 auto referrer
= queryValidPathId(i
.path
);
1050 for (auto & j
: i
.references
)
1051 addReference(referrer
, queryValidPathId(j
));
1054 /* Check that the derivation outputs are correct. We can't do
1055 this in addValidPath() above, because the references might
1056 not be valid yet. */
1057 foreach (ValidPathInfos::const_iterator
, i
, infos
)
1058 if (isDerivation(i
->path
)) {
1059 // FIXME: inefficient; we already loaded the
1060 // derivation in addValidPath().
1061 Derivation drv
= readDerivation(i
->path
);
1062 checkDerivationOutputs(i
->path
, drv
);
1065 /* Do a topological sort of the paths. This will throw an
1066 error if a cycle is detected and roll back the
1067 transaction. Cycles can only occur when a derivation
1068 has multiple outputs. */
1069 topoSortPaths(*this, paths
);
1076 /* Invalidate a path. The caller is responsible for checking that
1077 there are no referrers. */
1078 void LocalStore::invalidatePath(const Path
& path
)
1080 debug(format("invalidating path `%1%'") % path
);
1082 drvHashes
.erase(path
);
1084 stmtInvalidatePath
.use()(path
).exec();
1086 /* Note that the foreign key constraints on the Refs table take
1087 care of deleting the references entries for `path'. */
1091 Path
LocalStore::addToStoreFromDump(const string
& dump
, const string
& name
,
1092 bool recursive
, HashType hashAlgo
, bool repair
)
1094 Hash h
= hashString(hashAlgo
, dump
);
1096 Path dstPath
= makeFixedOutputPath(recursive
, hashAlgo
, h
, name
);
1098 addTempRoot(dstPath
);
1100 if (repair
|| !isValidPath(dstPath
)) {
1102 /* The first check above is an optimisation to prevent
1103 unnecessary lock acquisition. */
1105 PathLocks
outputLock(singleton
<PathSet
, Path
>(dstPath
));
1107 if (repair
|| !isValidPath(dstPath
)) {
1109 if (pathExists(dstPath
)) deletePath(dstPath
);
1112 StringSource
source(dump
);
1113 restorePath(dstPath
, source
);
1115 writeFile(dstPath
, dump
);
1117 canonicalisePathMetaData(dstPath
, -1);
1119 /* Register the SHA-256 hash of the NAR serialisation of
1120 the path in the database. We may just have computed it
1121 above (if called with recursive == true and hashAlgo ==
1122 sha256); otherwise, compute it here. */
1125 hash
.first
= hashAlgo
== htSHA256
? h
: hashString(htSHA256
, dump
);
1126 hash
.second
= dump
.size();
1128 hash
= hashPath(htSHA256
, dstPath
);
1130 optimisePath(dstPath
); // FIXME: combine with hashPath()
1133 info
.path
= dstPath
;
1134 info
.hash
= hash
.first
;
1135 info
.narSize
= hash
.second
;
1136 registerValidPath(info
);
1139 outputLock
.setDeletion(true);
1146 Path
LocalStore::addToStore(const string
& name
, const Path
& _srcPath
,
1147 bool recursive
, HashType hashAlgo
, PathFilter
& filter
, bool repair
)
1149 Path
srcPath(absPath(_srcPath
));
1150 debug(format("adding `%1%' to the store") % srcPath
);
1152 /* Read the whole path into memory. This is not a very scalable
1153 method for very large paths, but `copyPath' is mainly used for
1157 dumpPath(srcPath
, sink
, filter
);
1159 sink
.s
= readFile(srcPath
);
1161 return addToStoreFromDump(sink
.s
, name
, recursive
, hashAlgo
, repair
);
1165 Path
LocalStore::addTextToStore(const string
& name
, const string
& s
,
1166 const PathSet
& references
, bool repair
)
1168 Path dstPath
= computeStorePathForText(name
, s
, references
);
1170 addTempRoot(dstPath
);
1172 if (repair
|| !isValidPath(dstPath
)) {
1174 PathLocks
outputLock(singleton
<PathSet
, Path
>(dstPath
));
1176 if (repair
|| !isValidPath(dstPath
)) {
1178 if (pathExists(dstPath
)) deletePath(dstPath
);
1180 writeFile(dstPath
, s
);
1182 canonicalisePathMetaData(dstPath
, -1);
1184 HashResult hash
= hashPath(htSHA256
, dstPath
);
1186 optimisePath(dstPath
);
1189 info
.path
= dstPath
;
1190 info
.hash
= hash
.first
;
1191 info
.narSize
= hash
.second
;
1192 info
.references
= references
;
1193 registerValidPath(info
);
1196 outputLock
.setDeletion(true);
1203 struct HashAndWriteSink
: Sink
1207 HashAndWriteSink(Sink
& writeSink
) : writeSink(writeSink
), hashSink(htSHA256
)
1210 virtual void operator () (const unsigned char * data
, size_t len
)
1212 writeSink(data
, len
);
1213 hashSink(data
, len
);
1217 return hashSink
.currentHash().first
;
1222 #define EXPORT_MAGIC 0x4558494e
1225 static void checkSecrecy(const Path
& path
)
1228 if (stat(path
.c_str(), &st
))
1229 throw SysError(format("getting status of `%1%'") % path
);
1230 if ((st
.st_mode
& (S_IRWXG
| S_IRWXO
)) != 0)
1231 throw Error(format("file `%1%' should be secret (inaccessible to everybody else)!") % path
);
1235 /* Return the authentication agent, a "guix authenticate" process started
1237 static std::shared_ptr
<Agent
> authenticationAgent()
1239 static std::shared_ptr
<Agent
> agent
;
1242 Strings args
= { "authenticate" };
1243 agent
= std::make_shared
<Agent
>(settings
.guixProgram
, args
);
1249 /* Read an integer and the byte that immediately follows it from FD. Return
1251 static int readInteger(int fd
)
1257 ssize_t rd
= read(fd
, &ch
, 1);
1260 throw SysError("reading an integer");
1262 throw EndOfFile("unexpected EOF reading an integer");
1275 /* Read from FD a reply coming from 'guix authenticate'. The reply has the
1276 form "CODE LEN:STR". CODE is an integer, where zero indicates success.
1277 LEN specifies the length in bytes of the string that immediately
1279 static std::string
readAuthenticateReply(int fd
)
1281 int code
= readInteger(fd
);
1282 int len
= readInteger(fd
);
1286 readFull(fd
, (unsigned char *) &str
[0], len
);
1294 /* Sign HASH with the key stored in file SECRETKEY. Return the signature as a
1295 string, or raise an exception upon error. */
1296 static std::string
signHash(const string
&secretKey
, const Hash
&hash
)
1298 auto agent
= authenticationAgent();
1299 auto hexHash
= printHash(hash
);
1301 writeLine(agent
->toAgent
.writeSide
,
1302 (format("sign %1%:%2% %3%:%4%")
1303 % secretKey
.size() % secretKey
1304 % hexHash
.size() % hexHash
).str());
1306 return readAuthenticateReply(agent
->fromAgent
.readSide
);
1309 /* Verify SIGNATURE and return the base16-encoded hash over which it was
1311 static std::string
verifySignature(const string
&signature
)
1313 auto agent
= authenticationAgent();
1315 writeLine(agent
->toAgent
.writeSide
,
1316 (format("verify %1%:%2%")
1317 % signature
.size() % signature
).str());
1319 return readAuthenticateReply(agent
->fromAgent
.readSide
);
1322 void LocalStore::exportPath(const Path
& path
, bool sign
,
1325 assertStorePath(path
);
1327 printMsg(lvlInfo
, format("exporting path `%1%'") % path
);
1329 if (!isValidPath(path
))
1330 throw Error(format("path `%1%' is not valid") % path
);
1332 HashAndWriteSink
hashAndWriteSink(sink
);
1334 dumpPath(path
, hashAndWriteSink
);
1336 /* Refuse to export paths that have changed. This prevents
1337 filesystem corruption from spreading to other machines.
1338 Don't complain if the stored hash is zero (unknown). */
1339 Hash hash
= hashAndWriteSink
.currentHash();
1340 Hash storedHash
= queryPathHash(path
);
1341 if (hash
!= storedHash
&& storedHash
!= Hash(storedHash
.type
))
1342 throw Error(format("hash of path `%1%' has changed from `%2%' to `%3%'!") % path
1343 % printHash(storedHash
) % printHash(hash
));
1345 writeInt(EXPORT_MAGIC
, hashAndWriteSink
);
1347 writeString(path
, hashAndWriteSink
);
1350 queryReferences(path
, references
);
1351 writeStrings(references
, hashAndWriteSink
);
1353 Path deriver
= queryDeriver(path
);
1354 writeString(deriver
, hashAndWriteSink
);
1357 Hash hash
= hashAndWriteSink
.currentHash();
1359 writeInt(1, hashAndWriteSink
);
1361 Path secretKey
= settings
.nixConfDir
+ "/signing-key.sec";
1362 checkSecrecy(secretKey
);
1364 string signature
= signHash(secretKey
, hash
);
1366 writeString(signature
, hashAndWriteSink
);
1369 writeInt(0, hashAndWriteSink
);
1373 struct HashAndReadSource
: Source
1375 Source
& readSource
;
1378 HashAndReadSource(Source
& readSource
) : readSource(readSource
), hashSink(htSHA256
)
1382 size_t read(unsigned char * data
, size_t len
)
1384 size_t n
= readSource
.read(data
, len
);
1385 if (hashing
) hashSink(data
, n
);
1391 /* Create a temporary directory in the store that won't be
1392 garbage-collected. */
1393 Path
LocalStore::createTempDirInStore()
1397 /* There is a slight possibility that `tmpDir' gets deleted by
1398 the GC between createTempDir() and addTempRoot(), so repeat
1399 until `tmpDir' exists. */
1400 tmpDir
= createTempDir(settings
.nixStore
);
1401 addTempRoot(tmpDir
);
1402 } while (!pathExists(tmpDir
));
1407 Path
LocalStore::importPath(bool requireSignature
, Source
& source
)
1409 HashAndReadSource
hashAndReadSource(source
);
1411 /* We don't yet know what store path this archive contains (the
1412 store path follows the archive data proper), and besides, we
1413 don't know yet whether the signature is valid. */
1414 Path tmpDir
= createTempDirInStore();
1415 AutoDelete
delTmp(tmpDir
);
1416 Path unpacked
= tmpDir
+ "/unpacked";
1418 restorePath(unpacked
, hashAndReadSource
);
1420 unsigned int magic
= readInt(hashAndReadSource
);
1421 if (magic
!= EXPORT_MAGIC
)
1422 throw Error("normalized archive cannot be imported; wrong format");
1424 Path dstPath
= readStorePath(hashAndReadSource
);
1426 PathSet references
= readStorePaths
<PathSet
>(hashAndReadSource
);
1428 Path deriver
= readString(hashAndReadSource
);
1429 if (deriver
!= "") assertStorePath(deriver
);
1431 Hash hash
= hashAndReadSource
.hashSink
.finish().first
;
1432 hashAndReadSource
.hashing
= false;
1434 bool haveSignature
= readInt(hashAndReadSource
) == 1;
1436 if (requireSignature
&& !haveSignature
)
1437 throw Error(format("imported archive of `%1%' lacks a signature") % dstPath
);
1439 if (haveSignature
) {
1440 string signature
= readString(hashAndReadSource
);
1442 if (requireSignature
) {
1443 string hash2
= verifySignature(signature
);
1445 /* Note: runProgram() throws an exception if the signature
1448 if (printHash(hash
) != hash2
)
1450 "signed hash doesn't match actual contents of imported "
1451 "archive; archive could be corrupt, or someone is trying "
1452 "to import a Trojan horse");
1456 /* Do the actual import. */
1458 /* !!! way too much code duplication with addTextToStore() etc. */
1459 addTempRoot(dstPath
);
1461 if (!isValidPath(dstPath
)) {
1463 PathLocks outputLock
;
1465 /* Lock the output path. But don't lock if we're being called
1466 from a build hook (whose parent process already acquired a
1467 lock on this path). */
1468 Strings locksHeld
= tokenizeString
<Strings
>(getEnv("NIX_HELD_LOCKS"));
1469 if (find(locksHeld
.begin(), locksHeld
.end(), dstPath
) == locksHeld
.end())
1470 outputLock
.lockPaths(singleton
<PathSet
, Path
>(dstPath
));
1472 if (!isValidPath(dstPath
)) {
1474 if (pathExists(dstPath
)) deletePath(dstPath
);
1476 if (rename(unpacked
.c_str(), dstPath
.c_str()) == -1)
1477 throw SysError(format("cannot move `%1%' to `%2%'")
1478 % unpacked
% dstPath
);
1480 canonicalisePathMetaData(dstPath
, -1);
1482 /* !!! if we were clever, we could prevent the hashPath()
1484 HashResult hash
= hashPath(htSHA256
, dstPath
);
1486 optimisePath(dstPath
); // FIXME: combine with hashPath()
1489 info
.path
= dstPath
;
1490 info
.hash
= hash
.first
;
1491 info
.narSize
= hash
.second
;
1492 info
.references
= references
;
1493 info
.deriver
= deriver
!= "" && isValidPath(deriver
) ? deriver
: "";
1494 registerValidPath(info
);
1497 outputLock
.setDeletion(true);
1504 Paths
LocalStore::importPaths(bool requireSignature
, Source
& source
)
1508 unsigned long long n
= readLongLong(source
);
1510 if (n
!= 1) throw Error("input doesn't look like something created by `nix-store --export'");
1511 res
.push_back(importPath(requireSignature
, source
));
1517 void LocalStore::invalidatePathChecked(const Path
& path
)
1519 assertStorePath(path
);
1521 retrySQLite
<void>([&]() {
1524 if (isValidPath_(path
)) {
1525 PathSet referrers
; queryReferrers_(path
, referrers
);
1526 referrers
.erase(path
); /* ignore self-references */
1527 if (!referrers
.empty())
1528 throw PathInUse(format("cannot delete path `%1%' because it is in use by %2%")
1529 % path
% showPaths(referrers
));
1530 invalidatePath(path
);
1538 bool LocalStore::verifyStore(bool checkContents
, bool repair
)
1540 printMsg(lvlError
, format("reading the store..."));
1542 bool errors
= false;
1544 /* Acquire the global GC lock to prevent a garbage collection. */
1545 AutoCloseFD fdGCLock
= openGCLock(ltWrite
);
1548 for (auto & i
: readDirectory(settings
.nixStore
)) store
.insert(i
.name
);
1550 /* Check whether all valid paths actually exist. */
1551 printMsg(lvlInfo
, "checking path existence...");
1553 PathSet validPaths2
= queryAllValidPaths(), validPaths
, done
;
1555 foreach (PathSet::iterator
, i
, validPaths2
)
1556 verifyPath(*i
, store
, done
, validPaths
, repair
, errors
);
1558 /* Release the GC lock so that checking content hashes (which can
1559 take ages) doesn't block the GC or builds. */
1562 /* Optionally, check the content hashes (slow). */
1563 if (checkContents
) {
1564 printMsg(lvlInfo
, "checking hashes...");
1566 Hash
nullHash(htSHA256
);
1568 foreach (PathSet::iterator
, i
, validPaths
) {
1570 ValidPathInfo info
= queryPathInfo(*i
);
1572 /* Check the content hash (optionally - slow). */
1573 printMsg(lvlTalkative
, format("checking contents of `%1%'") % *i
);
1574 HashResult current
= hashPath(info
.hash
.type
, *i
);
1576 if (info
.hash
!= nullHash
&& info
.hash
!= current
.first
) {
1577 printMsg(lvlError
, format("path `%1%' was modified! "
1578 "expected hash `%2%', got `%3%'")
1579 % *i
% printHash(info
.hash
) % printHash(current
.first
));
1580 if (repair
) repairPath(*i
); else errors
= true;
1583 bool update
= false;
1585 /* Fill in missing hashes. */
1586 if (info
.hash
== nullHash
) {
1587 printMsg(lvlError
, format("fixing missing hash on `%1%'") % *i
);
1588 info
.hash
= current
.first
;
1592 /* Fill in missing narSize fields (from old stores). */
1593 if (info
.narSize
== 0) {
1594 printMsg(lvlError
, format("updating size field on `%1%' to %2%") % *i
% current
.second
);
1595 info
.narSize
= current
.second
;
1599 if (update
) updatePathInfo(info
);
1603 } catch (Error
& e
) {
1604 /* It's possible that the path got GC'ed, so ignore
1605 errors on invalid paths. */
1606 if (isValidPath(*i
))
1607 printMsg(lvlError
, format("error: %1%") % e
.msg());
1609 printMsg(lvlError
, format("warning: %1%") % e
.msg());
1619 void LocalStore::verifyPath(const Path
& path
, const PathSet
& store
,
1620 PathSet
& done
, PathSet
& validPaths
, bool repair
, bool & errors
)
1624 if (done
.find(path
) != done
.end()) return;
1627 if (!isStorePath(path
)) {
1628 printMsg(lvlError
, format("path `%1%' is not in the store") % path
);
1629 invalidatePath(path
);
1633 if (store
.find(baseNameOf(path
)) == store
.end()) {
1634 /* Check any referrers first. If we can invalidate them
1635 first, then we can invalidate this path as well. */
1636 bool canInvalidate
= true;
1637 PathSet referrers
; queryReferrers(path
, referrers
);
1638 foreach (PathSet::iterator
, i
, referrers
)
1640 verifyPath(*i
, store
, done
, validPaths
, repair
, errors
);
1641 if (validPaths
.find(*i
) != validPaths
.end())
1642 canInvalidate
= false;
1645 if (canInvalidate
) {
1646 printMsg(lvlError
, format("path `%1%' disappeared, removing from database...") % path
);
1647 invalidatePath(path
);
1649 printMsg(lvlError
, format("path `%1%' disappeared, but it still has valid referrers!") % path
);
1653 } catch (Error
& e
) {
1654 printMsg(lvlError
, format("warning: %1%") % e
.msg());
1663 validPaths
.insert(path
);
1667 bool LocalStore::pathContentsGood(const Path
& path
)
1669 std::map
<Path
, bool>::iterator i
= pathContentsGoodCache
.find(path
);
1670 if (i
!= pathContentsGoodCache
.end()) return i
->second
;
1671 printMsg(lvlInfo
, format("checking path `%1%'...") % path
);
1672 ValidPathInfo info
= queryPathInfo(path
);
1674 if (!pathExists(path
))
1677 HashResult current
= hashPath(info
.hash
.type
, path
);
1678 Hash
nullHash(htSHA256
);
1679 res
= info
.hash
== nullHash
|| info
.hash
== current
.first
;
1681 pathContentsGoodCache
[path
] = res
;
1682 if (!res
) printMsg(lvlError
, format("path `%1%' is corrupted or missing!") % path
);
1687 void LocalStore::markContentsGood(const Path
& path
)
1689 pathContentsGoodCache
[path
] = true;
1693 void LocalStore::vacuumDB()
1695 if (sqlite3_exec(db
, "vacuum;", 0, 0, 0) != SQLITE_OK
)
1696 throwSQLiteError(db
, "vacuuming SQLite database");
1700 void LocalStore::createUser(const std::string
& userName
, uid_t userId
)
1702 auto dir
= settings
.nixStateDir
+ "/profiles/per-user/" + userName
;
1705 if (chmod(dir
.c_str(), 0755) == -1)
1706 throw SysError(format("changing permissions of directory '%s'") % dir
);
1707 if (chown(dir
.c_str(), userId
, -1) == -1)
1708 throw SysError(format("changing owner of directory '%s'") % dir
);