* The environment variable NIX_ROOT can now be set to execute Nix in a
chroot() environment. * A operation `--validpath' to register path validity. Useful for bootstrapping in a pure Nix environment. * Safety checks: ensure that files involved in store operations are in the store.
This commit is contained in:
		
							parent
							
								
									6f5a5ea5ea
								
							
						
					
					
						commit
						76c0e85929
					
				
					 4 changed files with 70 additions and 12 deletions
				
			
		|  | @ -22,6 +22,13 @@ void sigintHandler(int signo) | ||||||
|    processor. */ |    processor. */ | ||||||
| static void initAndRun(int argc, char * * argv) | static void initAndRun(int argc, char * * argv) | ||||||
| { | { | ||||||
|  |     char * root = getenv("NIX_ROOT"); | ||||||
|  | 
 | ||||||
|  |     if (root) { | ||||||
|  |         if (chroot(root) != 0) | ||||||
|  |             throw SysError(format("changing root to `%1%'") % root); | ||||||
|  |     } | ||||||
|  |      | ||||||
|     /* Setup Nix paths. */ |     /* Setup Nix paths. */ | ||||||
|     nixStore = NIX_STORE_DIR; |     nixStore = NIX_STORE_DIR; | ||||||
|     nixDataDir = NIX_DATA_DIR; |     nixDataDir = NIX_DATA_DIR; | ||||||
|  |  | ||||||
|  | @ -157,6 +157,22 @@ void copyPath(const Path & src, const Path & dst) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | static bool isInStore(const Path & path) | ||||||
|  | { | ||||||
|  |     return path[0] == '/' | ||||||
|  |         && Path(path, 0, nixStore.size()) == nixStore | ||||||
|  |         && path.size() > nixStore.size() + 1 | ||||||
|  |         && path[nixStore.size()] == '/'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static void assertStorePath(const Path & path) | ||||||
|  | { | ||||||
|  |     if (!isInStore(path)) | ||||||
|  |         throw Error(format("path `%1%' is not in the Nix store") % path); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| static bool isValidPathTxn(const Path & path, const Transaction & txn) | static bool isValidPathTxn(const Path & path, const Transaction & txn) | ||||||
| { | { | ||||||
|     string s; |     string s; | ||||||
|  | @ -182,6 +198,9 @@ static bool isUsablePathTxn(const Path & path, const Transaction & txn) | ||||||
| void registerSuccessor(const Transaction & txn, | void registerSuccessor(const Transaction & txn, | ||||||
|     const Path & srcPath, const Path & sucPath) |     const Path & srcPath, const Path & sucPath) | ||||||
| { | { | ||||||
|  |     assertStorePath(srcPath); | ||||||
|  |     assertStorePath(sucPath); | ||||||
|  |      | ||||||
|     if (!isUsablePathTxn(sucPath, txn))	throw Error( |     if (!isUsablePathTxn(sucPath, txn))	throw Error( | ||||||
| 	format("path `%1%' cannot be a successor, since it is not usable") | 	format("path `%1%' cannot be a successor, since it is not usable") | ||||||
| 	% sucPath); | 	% sucPath); | ||||||
|  | @ -223,6 +242,9 @@ Paths queryPredecessors(const Path & sucPath) | ||||||
| 
 | 
 | ||||||
| void registerSubstitute(const Path & srcPath, const Path & subPath) | void registerSubstitute(const Path & srcPath, const Path & subPath) | ||||||
| { | { | ||||||
|  |     assertStorePath(srcPath); | ||||||
|  |     assertStorePath(subPath); | ||||||
|  |      | ||||||
|     if (!isValidPathTxn(subPath, noTxn)) throw Error( |     if (!isValidPathTxn(subPath, noTxn)) throw Error( | ||||||
| 	format("path `%1%' cannot be a substitute, since it is not valid") | 	format("path `%1%' cannot be a substitute, since it is not valid") | ||||||
| 	% subPath); | 	% subPath); | ||||||
|  | @ -262,6 +284,7 @@ Paths querySubstitutes(const Path & srcPath) | ||||||
| void registerValidPath(const Transaction & txn, const Path & _path) | void registerValidPath(const Transaction & txn, const Path & _path) | ||||||
| { | { | ||||||
|     Path path(canonPath(_path)); |     Path path(canonPath(_path)); | ||||||
|  |     assertStorePath(path); | ||||||
|     debug(format("registering path `%1%'") % path); |     debug(format("registering path `%1%'") % path); | ||||||
|     nixDB.setString(txn, dbValidPaths, path, ""); |     nixDB.setString(txn, dbValidPaths, path, ""); | ||||||
| } | } | ||||||
|  | @ -312,13 +335,6 @@ static void invalidatePath(const Path & path, Transaction & txn) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static bool isInPrefix(const string & path, const string & _prefix) |  | ||||||
| { |  | ||||||
|     string prefix = canonPath(_prefix + "/"); |  | ||||||
|     return string(path, 0, prefix.size()) == prefix; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| Path addToStore(const Path & _srcPath) | Path addToStore(const Path & _srcPath) | ||||||
| { | { | ||||||
|     Path srcPath(absPath(_srcPath)); |     Path srcPath(absPath(_srcPath)); | ||||||
|  | @ -355,6 +371,8 @@ Path addToStore(const Path & _srcPath) | ||||||
| 
 | 
 | ||||||
| void addTextToStore(const Path & dstPath, const string & s) | void addTextToStore(const Path & dstPath, const string & s) | ||||||
| { | { | ||||||
|  |     assertStorePath(dstPath); | ||||||
|  |      | ||||||
|     if (!isValidPath(dstPath)) { |     if (!isValidPath(dstPath)) { | ||||||
| 
 | 
 | ||||||
|         PathSet lockPaths; |         PathSet lockPaths; | ||||||
|  | @ -378,8 +396,7 @@ void deleteFromStore(const Path & _path) | ||||||
| { | { | ||||||
|     Path path(canonPath(_path)); |     Path path(canonPath(_path)); | ||||||
| 
 | 
 | ||||||
|     if (!isInPrefix(path, nixStore)) |     assertStorePath(path); | ||||||
|         throw Error(format("path `%1%' is not in the store") % path); |  | ||||||
| 
 | 
 | ||||||
|     Transaction txn(nixDB); |     Transaction txn(nixDB); | ||||||
|     invalidatePath(path, txn); |     invalidatePath(path, txn); | ||||||
|  | @ -402,6 +419,9 @@ void verifyStore() | ||||||
|         if (!pathExists(path)) { |         if (!pathExists(path)) { | ||||||
|             printMsg(lvlError, format("path `%1%' disappeared") % path); |             printMsg(lvlError, format("path `%1%' disappeared") % path); | ||||||
|             invalidatePath(path, txn); |             invalidatePath(path, txn); | ||||||
|  |         } else if (!isInStore(path)) { | ||||||
|  |             printMsg(lvlError, format("path `%1%' is not in the Nix store") % path); | ||||||
|  |             invalidatePath(path, txn); | ||||||
|         } else |         } else | ||||||
|             validPaths.insert(path); |             validPaths.insert(path); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -9,8 +9,10 @@ Operations: | ||||||
|   --add / -A: copy a path to the Nix store |   --add / -A: copy a path to the Nix store | ||||||
|   --query / -q: query information |   --query / -q: query information | ||||||
| 
 | 
 | ||||||
|   --successor: register a successor expression |   --successor: register a successor expression (dangerous!) | ||||||
|   --substitute: register a substitute expression |   --substitute: register a substitute expression (dangerous!) | ||||||
|  |   --validpath: register path validity (dangerous!) | ||||||
|  |   --isvalid: check path validity | ||||||
| 
 | 
 | ||||||
|   --dump: dump a path as a Nix archive |   --dump: dump a path as a Nix archive | ||||||
|   --restore: restore a path from a Nix archive |   --restore: restore a path from a Nix archive | ||||||
|  |  | ||||||
|  | @ -185,6 +185,30 @@ static void opSubstitute(Strings opFlags, Strings opArgs) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | static void opValidPath(Strings opFlags, Strings opArgs) | ||||||
|  | { | ||||||
|  |     if (!opFlags.empty()) throw UsageError("unknown flag"); | ||||||
|  |      | ||||||
|  |     Transaction txn; | ||||||
|  |     createStoreTransaction(txn); | ||||||
|  |     for (Strings::iterator i = opArgs.begin(); | ||||||
|  |          i != opArgs.end(); ++i) | ||||||
|  |         registerValidPath(txn, *i); | ||||||
|  |     txn.commit(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static void opIsValid(Strings opFlags, Strings opArgs) | ||||||
|  | { | ||||||
|  |     if (!opFlags.empty()) throw UsageError("unknown flag"); | ||||||
|  | 
 | ||||||
|  |     for (Strings::iterator i = opArgs.begin(); | ||||||
|  |          i != opArgs.end(); ++i) | ||||||
|  |         if (!isValidPath(*i)) | ||||||
|  |             throw Error(format("path `%1%' is not valid") % *i); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| /* A sink that writes dump output to stdout. */ | /* A sink that writes dump output to stdout. */ | ||||||
| struct StdoutSink : DumpSink | struct StdoutSink : DumpSink | ||||||
| { | { | ||||||
|  | @ -273,6 +297,10 @@ void run(Strings args) | ||||||
|             op = opSuccessor; |             op = opSuccessor; | ||||||
|         else if (arg == "--substitute") |         else if (arg == "--substitute") | ||||||
|             op = opSubstitute; |             op = opSubstitute; | ||||||
|  |         else if (arg == "--validpath") | ||||||
|  |             op = opValidPath; | ||||||
|  |         else if (arg == "--isvalid") | ||||||
|  |             op = opIsValid; | ||||||
|         else if (arg == "--dump") |         else if (arg == "--dump") | ||||||
|             op = opDump; |             op = opDump; | ||||||
|         else if (arg == "--restore") |         else if (arg == "--restore") | ||||||
|  | @ -292,6 +320,7 @@ void run(Strings args) | ||||||
| 
 | 
 | ||||||
|     if (!op) throw UsageError("no operation specified"); |     if (!op) throw UsageError("no operation specified"); | ||||||
| 
 | 
 | ||||||
|  |     if (op != opDump && op != opRestore) /* !!! hack */ | ||||||
|         openDB(); |         openDB(); | ||||||
| 
 | 
 | ||||||
|     op(opFlags, opArgs); |     op(opFlags, opArgs); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue