mirror of
https://github.com/NixOS/nix.git
synced 2025-11-25 19:51:00 +01:00
Added / Removed state functions to the Store API
This commit is contained in:
parent
53a6b9aaa5
commit
bdcce95a39
25 changed files with 624 additions and 383 deletions
|
|
@ -121,10 +121,12 @@ sub createLinks {
|
|||
sysopen (DSTFILEHANDLE, $new_dstFile, O_RDWR|O_EXCL|O_CREAT, 0755);
|
||||
printf DSTFILEHANDLE "#! @shell@ \n";
|
||||
|
||||
if($pkgRuntimeStateArgs eq "__NOARGS__")
|
||||
{ printf DSTFILEHANDLE "$nixBinDir/nix-state --run --identifier=$new_stateIdentifier $srcFile \"\$@\" \n"; }
|
||||
else
|
||||
{ printf DSTFILEHANDLE "$nixBinDir/nix-state --run --identifier=$new_stateIdentifier $srcFile \"\$@\" $pkgRuntimeStateArgs \n"; } # TODO, maybe first R.T.A. then other args ?
|
||||
if($pkgRuntimeStateArgs eq "__NOARGS__"){
|
||||
printf DSTFILEHANDLE "$nixBinDir/nix-state --run --identifier=$new_stateIdentifier $srcFile \"\$@\" \n";
|
||||
}
|
||||
else{
|
||||
printf DSTFILEHANDLE "$nixBinDir/nix-state --run --identifier=$new_stateIdentifier $srcFile \"\$@\" $pkgRuntimeStateArgs \n";
|
||||
} # TODO, maybe first R.T.A. then other args ?
|
||||
|
||||
close (DSTFILEHANDLE);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#! /bin/sh -e
|
||||
|
||||
export nixstatepath=/nixstate/nix
|
||||
export ACLOCAL_PATH=/root/.nix-profile/share/aclocal
|
||||
export nixstatepath=/nixstate2/nix
|
||||
export ACLOCAL_PATH=/home/wouterdb/.nix-profile/share/aclocal
|
||||
|
||||
if [ "$1" = "full" ]; then
|
||||
nix-env-all-pkgs.sh -i gcc
|
||||
|
|
@ -19,7 +19,8 @@ if [ "$1" = "full" ]; then
|
|||
nix-env-all-pkgs.sh -i docbook5-xsl
|
||||
nix-env-all-pkgs.sh -i bison
|
||||
nix-env-all-pkgs.sh -i gdb #optional for debugging
|
||||
nix-env-all-pkgs.sh -i e3cfsprogs
|
||||
nix-env-all-pkgs.sh -i gnupatch
|
||||
nix-env-all-pkgs.sh -i gnumake
|
||||
fi
|
||||
|
||||
if [ "$1" = "full" ] || [ "$1" = "auto" ]; then
|
||||
|
|
@ -39,8 +40,8 @@ fi
|
|||
--with-bzip2=$HOME/.nix-profile \
|
||||
--with-bdb=$HOME/.nix-profile \
|
||||
--with-docbook-xsl=$HOME/.nix-profile \
|
||||
--with-docbook-rng=/root/.nix-profile/xml/rng/docbook \
|
||||
--with-docbook-xsl=/root/.nix-profile/xml/xsl/docbook \
|
||||
--with-docbook-rng=/home/wouterdb/.nix-profile/xml/rng/docbook \
|
||||
--with-docbook-xsl=/home/wouterdb/.nix-profile/xml/xsl/docbook \
|
||||
--prefix=$nixstatepath \
|
||||
--with-store-dir=/nix/store \
|
||||
--with-store-state-dir=/nix/state \
|
||||
|
|
@ -61,9 +62,3 @@ fi
|
|||
|
||||
echo "New state nix version by wouter ..." > doc/manual/NEWS.txt
|
||||
make
|
||||
make install
|
||||
|
||||
#for i in $nixstatepath/bin/*; do
|
||||
# echo "pathing $i"
|
||||
# patchelf --set-rpath ../lib/nix/:$(patchelf --print-rpath $i) $i
|
||||
#done
|
||||
|
|
|
|||
|
|
@ -1,11 +1,5 @@
|
|||
#! /bin/sh -e
|
||||
|
||||
make
|
||||
make install
|
||||
|
||||
#export nixstatepath=/nixstate/nix
|
||||
|
||||
#for i in $nixstatepath/bin/*; do
|
||||
# echo "pathing $i"
|
||||
# patchelf --set-rpath ../lib/nix/:$(patchelf --print-rpath $i) $i
|
||||
#done
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ class Hash;
|
|||
typedef std::map<Path, PathSet> DrvRoots;
|
||||
typedef std::map<Path, Hash> DrvHashes;
|
||||
|
||||
/* Cache for calls to addToStore(); maps source paths to the store
|
||||
/* Cache for calls to addToStore(); maps source paths to the store //THIS OK ????
|
||||
paths. */
|
||||
typedef std::map<Path, Path> SrcToStore;
|
||||
|
||||
|
|
|
|||
|
|
@ -613,10 +613,15 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args)
|
|||
* We also add enableState to make it parse the drv to a state-drv
|
||||
* We also add runtimeStateArgs for the hash calc in hashDerivationModulo(...) to check if its needs to take the stateIdentiefier into account in the hash
|
||||
*/
|
||||
|
||||
//TODO CHECK DRVS ARE CREATED BY THE USER AND NOT DAEMON ???????????????????????????
|
||||
//queryCallingUsername()
|
||||
//THERE ARE 2 CALLS TO DerivationStateOutput below !!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
if(enableState && !disableState){
|
||||
if(runtimeStateArgs == ""){
|
||||
string enableStateS = bool2string("true");
|
||||
drv.stateOutputs["state"] = DerivationStateOutput("", "", "", "", stateIdentifier, enableStateS, "", "", "", runtimeStateArgs, getCallingUserName(), "", false);
|
||||
drv.stateOutputs["state"] = DerivationStateOutput("", "", "", "", stateIdentifier, enableStateS, "", "", "", runtimeStateArgs, queryCallingUsername(), "", false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -652,7 +657,7 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args)
|
|||
string enableStateS = bool2string("true");
|
||||
string createDirsBeforeInstallS = bool2string(createDirsBeforeInstall);
|
||||
drv.stateOutputs["state"] = DerivationStateOutput(stateOutPath, printHash(componentHash), outputHashAlgo, outputHash, stateIdentifier, enableStateS,
|
||||
shareType, syncState, createDirsBeforeInstallS, runtimeStateArgs, getCallingUserName(), sharedState);
|
||||
shareType, syncState, createDirsBeforeInstallS, runtimeStateArgs, queryCallingUsername(), sharedState);
|
||||
|
||||
for(vector<DerivationStateOutputDir>::iterator i = stateDirs.begin(); i != stateDirs.end(); ++i)
|
||||
drv.stateOutputDirs[(*i).path] = *(i);
|
||||
|
|
@ -694,7 +699,7 @@ static Expr prim_derivationLazy(EvalState & state, const ATermVector & args)
|
|||
makeAttrRHS(makeSelect(drvStrict, toATerm("outPath")), makeNoPos()));
|
||||
attrs.set(toATerm("drvPath"),
|
||||
makeAttrRHS(makeSelect(drvStrict, toATerm("drvPath")), makeNoPos()));
|
||||
attrs.set(toATerm("statePath"), //TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! add a state check !
|
||||
attrs.set(toATerm("statePath"),
|
||||
makeAttrRHS(makeSelect(drvStrict, toATerm("statePath")), makeNoPos()));
|
||||
|
||||
return makeAttrs(attrs);
|
||||
|
|
|
|||
|
|
@ -1079,7 +1079,7 @@ static string makeValidityRegistration(const PathSet & paths,
|
|||
for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i) {
|
||||
s += *i + "\n";
|
||||
|
||||
Path deriver = showDerivers ? queryDeriver(noTxn, *i) : "";
|
||||
Path deriver = showDerivers ? store->queryDeriver(*i) : "";
|
||||
s += deriver + "\n";
|
||||
|
||||
PathSet references;
|
||||
|
|
@ -1400,7 +1400,7 @@ void DerivationGoal::startBuilder()
|
|||
checkStatePath(drv);
|
||||
|
||||
if(drv.stateOutputs.find("state")->second.getCreateDirsBeforeInstall())
|
||||
createStateDirs(drv.stateOutputDirs, drv.stateOutputs);
|
||||
createStateDirsTxn(noTxn, drv.stateOutputDirs, drv.stateOutputs);
|
||||
}
|
||||
|
||||
/* For convenience, set an environment pointing to the top build
|
||||
|
|
@ -1640,7 +1640,7 @@ void DerivationGoal::computeClosure()
|
|||
//We create state dirs only when state is enabled and when the dirs need to be created after the installation
|
||||
if(drv.stateOutputs.size() != 0)
|
||||
if(!drv.stateOutputs.find("state")->second.getCreateDirsBeforeInstall())
|
||||
createStateDirs(drv.stateOutputDirs, drv.stateOutputs);
|
||||
createStateDirsTxn(noTxn, drv.stateOutputDirs, drv.stateOutputs);
|
||||
|
||||
/*
|
||||
for (PathSet::iterator i = allPaths.begin(); i != allPaths.end(); ++i)
|
||||
|
|
|
|||
|
|
@ -478,7 +478,7 @@ void LocalStore::collectGarbage(GCAction action, const PathSet & pathsToDelete,
|
|||
/* Note that the deriver need not be valid (e.g., if we
|
||||
previously ran the collector with `gcKeepDerivations'
|
||||
turned off). */
|
||||
Path deriver = queryDeriver(noTxn, *i);
|
||||
Path deriver = store->queryDeriver(*i);
|
||||
if (deriver != "" && store->isValidPath(deriver))
|
||||
computeFSClosure(deriver, livePaths, true, false, -1); //TODO !!!!!!!!!!!!!!!!!!!!!!!!!!! WE (MAY) ALSO NEED TO KEEP STATE
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
|
||||
#include <pwd.h>
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
|
@ -27,8 +27,9 @@ unsigned int maxBuildJobs = 1;
|
|||
bool readOnlyMode = false;
|
||||
string thisSystem = "unset";
|
||||
unsigned int maxSilentTime = 0;
|
||||
|
||||
static bool settingsRead = false;
|
||||
uid_t callingUID = 0;
|
||||
bool debugWorker = true;
|
||||
|
||||
static std::map<string, Strings> settings;
|
||||
|
||||
|
|
@ -115,5 +116,32 @@ unsigned int queryIntSetting(const string & name, unsigned int def)
|
|||
return n;
|
||||
}
|
||||
|
||||
|
||||
uid_t queryCallingUID()
|
||||
{
|
||||
/* A root user will not even bother calling the daemon, so there is no way to check
|
||||
* If the uid is not yet set...
|
||||
*/
|
||||
return callingUID;
|
||||
}
|
||||
|
||||
void setCallingUID(uid_t uid, bool reset)
|
||||
{
|
||||
if(callingUID != 0 && !reset)
|
||||
throw Error(format("The UID of the caller aleady set! at this point"));
|
||||
|
||||
callingUID = uid;
|
||||
}
|
||||
|
||||
string queryCallingUsername()
|
||||
{
|
||||
uid_t uid = queryCallingUID();
|
||||
|
||||
passwd *pwd = getpwuid(uid);
|
||||
char *pw_name = pwd->pw_name;
|
||||
|
||||
return (string)pw_name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,7 +80,16 @@ bool queryBoolSetting(const string & name, bool def);
|
|||
|
||||
unsigned int queryIntSetting(const string & name, unsigned int def);
|
||||
|
||||
|
||||
/* TODO PRIVATE: UID of the user that calls the nix-worker daemon */
|
||||
extern uid_t callingUID;
|
||||
|
||||
/* get/set the UID of the user that calls the nix-worker daemon */
|
||||
uid_t queryCallingUID();
|
||||
void setCallingUID(uid_t uid, bool reset = false);
|
||||
/* get the username based on the UID of the user that calls the nix-worker daemon */
|
||||
string queryCallingUsername();
|
||||
|
||||
extern bool debugWorker;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -256,11 +256,11 @@ LocalStore::LocalStore(bool reserveSpace)
|
|||
throw Error(format("`%1%' is corrupt") % schemaFN);
|
||||
}
|
||||
|
||||
if (curSchema > nixSchemaVersion)
|
||||
if (curSchema > nixSchemaVersion && curSchema != 4) //TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! MAJOR HACK, I SHOULD MERGE WITH THE TRUNK
|
||||
throw Error(format("current Nix store schema is version %1%, but I only support %2%")
|
||||
% curSchema % nixSchemaVersion);
|
||||
|
||||
if (curSchema < nixSchemaVersion) {
|
||||
if (curSchema < nixSchemaVersion && curSchema != 4) { //TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! MAJOR HACK, I SHOULD MERGE WITH THE TRUNK
|
||||
if (curSchema <= 1)
|
||||
upgradeStore07();
|
||||
if (curSchema == 2)
|
||||
|
|
@ -809,7 +809,7 @@ bool LocalStore::isStateDrv(const Derivation & drv)
|
|||
return nix::isStateDrvTxn(noTxn, drv);
|
||||
}
|
||||
|
||||
Path queryDeriver(const Transaction & txn, const Path & storePath)
|
||||
static Path queryDeriver(const Transaction & txn, const Path & storePath)
|
||||
{
|
||||
if (!isRealisablePath(txn, storePath))
|
||||
throw Error(format("path `%1%' is not valid") % storePath);
|
||||
|
|
@ -827,6 +827,11 @@ Path queryDeriver(const Transaction & txn, const Path & storePath)
|
|||
return "";
|
||||
}
|
||||
|
||||
Path LocalStore::queryDeriver(const Path & path)
|
||||
{
|
||||
return nix::queryDeriver(noTxn, path);
|
||||
}
|
||||
|
||||
//A '*' as argument stands for all identifiers or all users
|
||||
PathSet queryDerivers(const Transaction & txn, const Path & storePath, const string & identifier, const string & user)
|
||||
{
|
||||
|
|
@ -859,6 +864,11 @@ PathSet queryDerivers(const Transaction & txn, const Path & storePath, const str
|
|||
return filtereddata;
|
||||
}
|
||||
|
||||
PathSet LocalStore::queryDerivers(const Path & storePath, const string & identifier, const string & user)
|
||||
{
|
||||
return nix::queryDerivers(noTxn, storePath, identifier, user);
|
||||
}
|
||||
|
||||
//Wrapper around converting the drvPath to the statePath
|
||||
/*
|
||||
PathSet queryDeriversStatePath(const Transaction & txn, const Path & storePath, const string & identifier, const string & user)
|
||||
|
|
@ -1158,10 +1168,11 @@ Path LocalStore::addToStore(const Path & _srcPath, bool fixed,
|
|||
registerValidPath(txn, dstPath, h, PathSet(), PathSet(), "", -1); //TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!! CHECK (probabyly ok?)
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
|
||||
outputLock.setDeletion(true);
|
||||
}
|
||||
|
||||
|
||||
return dstPath;
|
||||
}
|
||||
|
||||
|
|
@ -1256,7 +1267,7 @@ void LocalStore::exportPath(const Path & path, bool sign,
|
|||
nix::queryXReferencesTxn(txn, path, references, true, -1); //TODO we can only now export the final revision //TODO also export the state references ???
|
||||
writeStringSet(references, hashAndWriteSink);
|
||||
|
||||
Path deriver = queryDeriver(txn, path);
|
||||
Path deriver = nix::queryDeriver(txn, path);
|
||||
writeString(deriver, hashAndWriteSink);
|
||||
|
||||
if (sign) {
|
||||
|
|
@ -1423,8 +1434,7 @@ void deleteFromStore(const Path & _path, unsigned long long & bytesFreed)
|
|||
throw PathInUse(format("cannot delete path `%1%' because it is in use by path `%2%'") % path % *i);
|
||||
invalidatePath(txn, path);
|
||||
|
||||
//TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
//Also delete/invalidate stateReferrers?????
|
||||
//TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Also delete/invalidate stateReferrers?????
|
||||
}
|
||||
txn.commit();
|
||||
|
||||
|
|
@ -1563,13 +1573,11 @@ void verifyStore(bool checkContents)
|
|||
txn.commit();
|
||||
}
|
||||
|
||||
void setStatePathsInterval(const PathSet & statePaths, const vector<int> & intervals, bool allZero)
|
||||
void setStatePathsIntervalTxn(const Transaction & txn, const PathSet & statePaths, const vector<int> & intervals, bool allZero)
|
||||
{
|
||||
if(!allZero && statePaths.size() != intervals.size()){
|
||||
throw Error("the number of statepaths and intervals must be equal");
|
||||
}
|
||||
|
||||
Transaction txn(nixDB);
|
||||
|
||||
int n=0;
|
||||
for (PathSet::iterator i = statePaths.begin(); i != statePaths.end(); ++i)
|
||||
|
|
@ -1583,13 +1591,13 @@ void setStatePathsInterval(const PathSet & statePaths, const vector<int> & inter
|
|||
nixDB.setString(txn, dbStateCounters, *i, int2String(interval));
|
||||
n++;
|
||||
}
|
||||
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
void LocalStore::setStatePathsInterval(const PathSet & statePaths, const vector<int> & intervals, bool allZero)
|
||||
{
|
||||
nix::setStatePathsInterval(statePaths, intervals, allZero);
|
||||
Transaction txn(nixDB);
|
||||
nix::setStatePathsIntervalTxn(txn, statePaths, intervals, allZero);
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
vector<int> getStatePathsIntervalTxn(const Transaction & txn, const PathSet & statePaths)
|
||||
|
|
@ -1664,7 +1672,7 @@ void LocalStore::storePathRequisites(const Path & storeOrstatePath, const bool i
|
|||
nix::storePathRequisites(storeOrstatePath, includeOutputs, paths, withComponents, withState, revision);
|
||||
}
|
||||
|
||||
void queryAllValidPaths(const Transaction & txn, PathSet & allComponentPaths, PathSet & allStatePaths)
|
||||
void queryAllValidPathsTxn(const Transaction & txn, PathSet & allComponentPaths, PathSet & allStatePaths)
|
||||
{
|
||||
Paths allComponentPaths2;
|
||||
Paths allStatePaths2;
|
||||
|
|
@ -1711,9 +1719,24 @@ bool LocalStore::queryAvailableStateRevisions(const Path & statePath, RevisionIn
|
|||
return nix::queryAvailableStateRevisionsTxn(noTxn, statePath, revisions);
|
||||
}
|
||||
|
||||
void LocalStore::commitStatePath(const Path & statePath)
|
||||
Snapshots LocalStore::commitStatePath(const Path & statePath)
|
||||
{
|
||||
nix::commitStatePathTxn(noTxn, statePath);
|
||||
Transaction txn(nixDB);
|
||||
Snapshots ss = nix::commitStatePathTxn(txn, statePath);
|
||||
txn.commit();
|
||||
return ss;
|
||||
}
|
||||
|
||||
void LocalStore::scanAndUpdateAllReferences(const Path & statePath, const bool recursive)
|
||||
{
|
||||
Transaction txn(nixDB);
|
||||
if(recursive)
|
||||
nix::scanAndUpdateAllReferencesRecusivelyTxn(txn, statePath);
|
||||
else{
|
||||
PathSet empty;
|
||||
nix::scanAndUpdateAllReferencesTxn(txn, statePath, empty, empty);
|
||||
}
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
void setSolidStateReferencesTxn(const Transaction & txn, const Path & statePath, const PathSet & paths)
|
||||
|
|
@ -1767,6 +1790,11 @@ PathSet toNonSharedPathSetTxn(const Transaction & txn, const PathSet & statePath
|
|||
return real_statePaths;
|
||||
}
|
||||
|
||||
PathSet LocalStore::toNonSharedPathSet(const PathSet & statePaths)
|
||||
{
|
||||
return toNonSharedPathSetTxn(noTxn, statePaths);
|
||||
}
|
||||
|
||||
void setStateComponentReferencesTxn(const Transaction & txn, const Path & statePath, const Strings & references, int revision, int timestamp)
|
||||
{
|
||||
nixDB.setStateReferences(txn, dbStateComponentReferences, dbStateRevisions, statePath, references, revision, timestamp);
|
||||
|
|
@ -1819,6 +1847,15 @@ PathSet getSharedWithPathSetRecTxn(const Transaction & txn, const Path & statePa
|
|||
return getSharedWithPathSetRecTxn_private(txn, statePath_ns, empty);
|
||||
}
|
||||
|
||||
|
||||
void LocalStore::revertToRevision(Path & componentPath, Path & derivationPath, Path & statePath, int revision_arg, bool recursive)
|
||||
{
|
||||
Transaction txn(nixDB);
|
||||
revertToRevisionTxn(txn, componentPath, derivationPath, statePath, revision_arg, recursive);
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
|
||||
/* Upgrade from schema 1 (Nix <= 0.7) to schema 2 (Nix >= 0.8). */
|
||||
static void upgradeStore07()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -87,6 +87,8 @@ public:
|
|||
|
||||
void collectGarbage(GCAction action, const PathSet & pathsToDelete,
|
||||
bool ignoreLiveness, PathSet & result, unsigned long long & bytesFreed);
|
||||
|
||||
/////////////////////////////
|
||||
|
||||
void setStatePathsInterval(const PathSet & statePath, const vector<int> & intervals, bool allZero = false);
|
||||
|
||||
|
|
@ -106,7 +108,17 @@ public:
|
|||
|
||||
bool queryAvailableStateRevisions(const Path & statePath, RevisionInfos & revisions);
|
||||
|
||||
void commitStatePath(const Path & statePath);
|
||||
Snapshots commitStatePath(const Path & statePath);
|
||||
|
||||
Path queryDeriver(const Path & path); //should these be in here ????
|
||||
|
||||
PathSet queryDerivers(const Path & storePath, const string & identifier, const string & user); //should these be in here ????
|
||||
|
||||
void scanAndUpdateAllReferences(const Path & statePath, const bool recursive);
|
||||
|
||||
PathSet toNonSharedPathSet(const PathSet & statePaths);
|
||||
|
||||
void revertToRevision(Path & componentPath, Path & derivationPath, Path & statePath, int revision_arg, bool recursive);
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -174,16 +186,9 @@ void setReferences(const Transaction & txn, const Path & store_or_statePath,
|
|||
void setDeriver(const Transaction & txn, const Path & path,
|
||||
const Path & deriver);
|
||||
|
||||
/* Query the deriver of a store path. Return the empty string if no
|
||||
deriver has been set. */
|
||||
Path queryDeriver(const Transaction & txn, const Path & path);
|
||||
|
||||
/* Query the derivers of a state-store path. */
|
||||
PathSet queryDerivers(const Transaction & txn, const Path & storePath, const string & identifier, const string & user);
|
||||
|
||||
/* Query the derivers of a state path. (are there more then 1 for a statepath?) */
|
||||
//PathSet queryDeriversStatePath(const Transaction & txn, const Path & storePath, const string & identifier, const string & user);
|
||||
|
||||
/* Delete a value from the nixStore directory. */
|
||||
void deleteFromStore(const Path & path, unsigned long long & bytesFreed);
|
||||
|
||||
|
|
@ -217,7 +222,7 @@ bool isStateDrvPathTxn(const Transaction & txn, const Path & drvPath);
|
|||
bool isStateDrvTxn(const Transaction & txn, const Derivation & drv);
|
||||
|
||||
//TODO can this ?????
|
||||
void queryAllValidPaths(const Transaction & txn, PathSet & allComponentPaths, PathSet & allStatePaths);
|
||||
void queryAllValidPathsTxn(const Transaction & txn, PathSet & allComponentPaths, PathSet & allStatePaths);
|
||||
bool isValidStatePathTxn(const Transaction & txn, const Path & path);
|
||||
|
||||
void queryXReferencesTxn(const Transaction & txn, const Path & path, PathSet & references, const bool component_or_state, const int revision, int timestamp = -1);
|
||||
|
|
@ -245,6 +250,10 @@ Path toNonSharedPathTxn(const Transaction & txn, const Path & statePath);
|
|||
PathSet getSharedWithPathSetRecTxn(const Transaction & txn, const Path & statePath);
|
||||
|
||||
void ensurePathTxn(const Transaction & txn, const Path & path);
|
||||
vector<int> getStatePathsIntervalTxn(const Transaction & txn, const PathSet & statePaths);
|
||||
|
||||
bool queryStateRevisionsTxn(const Transaction & txn, const Path & statePath, RevisionClosure & revisions, RevisionClosureTS & timestamps, const int revision);
|
||||
void setStatePathsIntervalTxn(const Transaction & txn, const PathSet & statePath, const vector<int> & intervals, bool allZero = false);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ RemoteStore::RemoteStore()
|
|||
{
|
||||
string remoteMode = getEnv("NIX_REMOTE");
|
||||
|
||||
debug(format("Client remoteMode: '%1%'") % remoteMode);
|
||||
if (remoteMode == "slave")
|
||||
/* Fork off a setuid worker to do the privileged work. */
|
||||
forkSlave();
|
||||
|
|
@ -280,7 +281,9 @@ Path RemoteStore::addToStore(const Path & _srcPath, bool fixed,
|
|||
writeString(hashAlgo, to);
|
||||
dumpPath(srcPath, to, filter);
|
||||
processStderr();
|
||||
Path path = readStorePath(from);
|
||||
printMsg(lvlInfo, format("REMOTESTORE: ADD TO STORE REMOTE 1"));
|
||||
Path path = readStorePath(from);
|
||||
printMsg(lvlInfo, format("REMOTESTORE: ADD TO STORE REMOTE 2"));
|
||||
return path;
|
||||
}
|
||||
|
||||
|
|
@ -294,8 +297,7 @@ Path RemoteStore::addTextToStore(const string & suffix, const string & s,
|
|||
writeStringSet(references, to);
|
||||
|
||||
processStderr();
|
||||
Path path = readStorePath(from);
|
||||
return path;
|
||||
return readStorePath(from);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -318,7 +320,7 @@ Path RemoteStore::importPath(bool requireSignature, Source & source)
|
|||
|
||||
processStderr(0, &source);
|
||||
Path path = readStorePath(from);
|
||||
return path;
|
||||
return readStorePath(from);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -487,7 +489,42 @@ bool RemoteStore::queryAvailableStateRevisions(const Path & statePath, RevisionI
|
|||
}
|
||||
|
||||
//TODO
|
||||
void RemoteStore::commitStatePath(const Path & statePath)
|
||||
Snapshots RemoteStore::commitStatePath(const Path & statePath)
|
||||
{
|
||||
Snapshots ss;
|
||||
return ss;
|
||||
}
|
||||
|
||||
void RemoteStore::scanAndUpdateAllReferences(const Path & statePath, const bool recursive)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Path RemoteStore::queryDeriver(const Path & path)
|
||||
{
|
||||
writeInt(wopQueryDeriver, to);
|
||||
writeString(path, to);
|
||||
processStderr();
|
||||
return readStorePath(from);
|
||||
}
|
||||
|
||||
PathSet RemoteStore::queryDerivers(const Path & storePath, const string & identifier, const string & user)
|
||||
{
|
||||
writeInt(wopQueryDerivers, to);
|
||||
writeString(storePath, to);
|
||||
writeString(identifier, to);
|
||||
writeString(user, to);
|
||||
processStderr();
|
||||
return readStorePaths(from); //TODO is this ok ??
|
||||
}
|
||||
|
||||
PathSet RemoteStore::toNonSharedPathSet(const PathSet & statePaths)
|
||||
{
|
||||
PathSet p;
|
||||
return p;
|
||||
}
|
||||
|
||||
void RemoteStore::revertToRevision(Path & componentPath, Path & derivationPath, Path & statePath, int revision_arg, bool recursive)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,7 +94,17 @@ public:
|
|||
|
||||
bool queryAvailableStateRevisions(const Path & statePath, RevisionInfos & revisions);
|
||||
|
||||
void commitStatePath(const Path & statePath);
|
||||
Snapshots commitStatePath(const Path & statePath);
|
||||
|
||||
Path queryDeriver(const Path & path);
|
||||
|
||||
PathSet queryDerivers(const Path & storePath, const string & identifier, const string & user);
|
||||
|
||||
void scanAndUpdateAllReferences(const Path & statePath, const bool recursive);
|
||||
|
||||
PathSet toNonSharedPathSet(const PathSet & statePaths);
|
||||
|
||||
void revertToRevision(Path & componentPath, Path & derivationPath, Path & statePath, int revision_arg, bool recursive);
|
||||
|
||||
private:
|
||||
AutoCloseFD fdSocket;
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ Path makeStatePath(const string & componentHash, const string & suffix, const st
|
|||
string suffix_stateIdentifier = stateIdentifier;
|
||||
suffix_stateIdentifier = "-" + suffix_stateIdentifier;
|
||||
|
||||
string username = getCallingUserName(); //Can and Should NOT be faked
|
||||
string username = queryCallingUsername(); //Should NOT be fake-able
|
||||
|
||||
/* e.g., "source:sha256:1abc...:/nix/store:foo.tar.gz" */
|
||||
string s = ":sha256:" + componentHash + ":"
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ public:
|
|||
/* Checks whether a path is valid. */
|
||||
virtual bool isValidPath(const Path & path) = 0;
|
||||
|
||||
/* TODO */
|
||||
/* Checks whether a state-path is valid. */
|
||||
virtual bool isValidStatePath(const Path & path) = 0;
|
||||
|
||||
/* TODO */
|
||||
|
|
@ -207,7 +207,7 @@ public:
|
|||
/* TODO */
|
||||
virtual vector<int> getStatePathsInterval(const PathSet & statePaths) = 0;
|
||||
|
||||
/* TODO */
|
||||
/* Checks whether a path is a component path that has a statePath. */
|
||||
virtual bool isStateComponent(const Path & path) = 0;
|
||||
|
||||
/* TODO */
|
||||
|
|
@ -229,7 +229,19 @@ public:
|
|||
virtual bool queryAvailableStateRevisions(const Path & statePath, RevisionInfos & revisions) = 0;
|
||||
|
||||
/* TODO */
|
||||
virtual void commitStatePath(const Path & statePath) = 0;
|
||||
virtual Snapshots commitStatePath(const Path & statePath) = 0;
|
||||
|
||||
/* Query the deriver of a store path. Return the empty string if
|
||||
no deriver has been set. */
|
||||
virtual Path queryDeriver(const Path & path) = 0;
|
||||
|
||||
virtual PathSet queryDerivers(const Path & storePath, const string & identifier, const string & user) = 0;
|
||||
|
||||
virtual void scanAndUpdateAllReferences(const Path & statePath, const bool recursive) = 0;
|
||||
|
||||
virtual PathSet toNonSharedPathSet(const PathSet & statePaths) = 0;
|
||||
|
||||
virtual void revertToRevision(Path & componentPath, Path & derivationPath, Path & statePath, int revision_arg, bool recursive) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -15,10 +15,11 @@
|
|||
#include "misc.hh"
|
||||
#include "archive.hh"
|
||||
#include "snapshot.hh"
|
||||
#include "references.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
||||
/*
|
||||
void updatedStateDerivation(Path storePath)
|
||||
{
|
||||
//We dont remove the old .svn folders
|
||||
|
|
@ -26,8 +27,9 @@ void updatedStateDerivation(Path storePath)
|
|||
|
||||
printMsg(lvlTalkative, format("Resetting state drv settings"));
|
||||
}
|
||||
*/
|
||||
|
||||
void createStateDirs(const DerivationStateOutputDirs & stateOutputDirs, const DerivationStateOutputs & stateOutputs)
|
||||
void createStateDirsTxn(const Transaction & txn, const DerivationStateOutputDirs & stateOutputDirs, const DerivationStateOutputs & stateOutputs)
|
||||
{
|
||||
Path statePath = stateOutputs.find("state")->second.statepath;
|
||||
string stateDir = statePath;
|
||||
|
|
@ -64,9 +66,138 @@ void createStateDirs(const DerivationStateOutputDirs & stateOutputDirs, const De
|
|||
|
||||
//Initialize the counters for the statePaths that have an interval to 0
|
||||
vector<int> empty;
|
||||
store->setStatePathsInterval(intervalPaths, empty, true);
|
||||
setStatePathsIntervalTxn(txn, intervalPaths, empty, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Input: store (or statePath?)
|
||||
* Returns all the drv's of the statePaths (in)directly referenced.
|
||||
*/
|
||||
//TODO TXN
|
||||
PathSet getAllStateDerivationsRecursivelyTxn(const Transaction & txn, const Path & storePath, const int revision)
|
||||
{
|
||||
//Get recursively all state paths
|
||||
PathSet statePaths;
|
||||
storePathRequisitesTxn(noTxn, storePath, false, statePaths, false, true, revision);
|
||||
|
||||
//Find the matching drv with the statePath
|
||||
PathSet derivations;
|
||||
for (PathSet::iterator i = statePaths.begin(); i != statePaths.end(); ++i)
|
||||
derivations.insert(queryStatePathDrvTxn(txn,*i));
|
||||
|
||||
return derivations;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void revertToRevisionTxn(const Transaction & txn, Path & componentPath, Path & derivationPath, Path & statePath, int revision_arg, bool recursive)
|
||||
{
|
||||
|
||||
PathSet statePaths;
|
||||
if(recursive)
|
||||
PathSet statePaths = getAllStateDerivationsRecursivelyTxn(txn, componentPath, revision_arg); //get dependecies (if neccecary | recusively) of all state components that need to be updated
|
||||
else
|
||||
statePaths.insert(derivationPath); //Insert direct state path
|
||||
|
||||
//get a new timestamp for the references update
|
||||
int newTimestamp = getTimeStamp();
|
||||
|
||||
//Get the revisions recursively to also roll them back
|
||||
RevisionClosure getRivisions;
|
||||
RevisionClosureTS getTimestamps;
|
||||
queryStateRevisionsTxn(txn, statePath, getRivisions, getTimestamps, revision_arg);
|
||||
|
||||
//Revert each statePath in the list
|
||||
for (RevisionClosure::iterator i = getRivisions.begin(); i != getRivisions.end(); ++i){
|
||||
Path statePath = (*i).first;
|
||||
Snapshots revisioned_paths = (*i).second;
|
||||
int timestamp = getTimestamps[statePath];
|
||||
|
||||
//get its derivation-state-items
|
||||
Derivation statePath_drv = derivationFromPathTxn(txn, queryStatePathDrvTxn(noTxn, statePath));
|
||||
DerivationStateOutputDirs stateOutputDirs = statePath_drv.stateOutputDirs;
|
||||
|
||||
//TODO Sort snapshots??? eg first restore root, then the subdirs??
|
||||
|
||||
for (Snapshots::iterator j = revisioned_paths.begin(); j != revisioned_paths.end(); ++j){
|
||||
Path revertPathOrFile = (*j).first;
|
||||
unsigned int epoch = (*j).second;
|
||||
|
||||
//printMsg(lvlError, format("MAYBE '%1%'") % revertPathOrFile);
|
||||
|
||||
//Look up the type from the drv with for the current snapshotted path
|
||||
Path statePath_postfix = revertPathOrFile.substr(nixStoreState.length() + 1, revertPathOrFile.length() - nixStoreState.length());
|
||||
statePath_postfix = statePath_postfix.substr(statePath_postfix.find_first_of("/") + 1, statePath_postfix.length());
|
||||
if(statePath_postfix == "")
|
||||
statePath_postfix = "/";
|
||||
string type = stateOutputDirs.at(statePath_postfix).type;
|
||||
if(type == "none")
|
||||
continue;
|
||||
|
||||
//Now that were still here, we need to copy the state from the previous version back
|
||||
Strings p_args;
|
||||
p_args.push_back("-c"); //we use the shell to execute the cp command becuase the shell expands the '*'
|
||||
string cpcommand = "cp";
|
||||
if(revertPathOrFile.substr(revertPathOrFile.length() -1 , revertPathOrFile.length()) == "/"){ //is dir
|
||||
string revert_to_path = revertPathOrFile.substr(0, revertPathOrFile.length() -1) + "@" + unsignedInt2String(epoch);
|
||||
cpcommand += " -R " + revert_to_path + "/*";
|
||||
|
||||
//clean all contents of the folder first (so were sure the path is clean)
|
||||
if(pathExists(revertPathOrFile))
|
||||
deletePath(revertPathOrFile);
|
||||
|
||||
if(epoch == 0) //Path was deleted so were done
|
||||
continue;
|
||||
else //If path was not deleted in the previous version, we need to make sure it exists or cp will fail
|
||||
ensureDirExists(revertPathOrFile);
|
||||
|
||||
//If the the dir has not contents then a cp ..../* will error since * cannot be expanded. So in this case were done and dont have to revert.
|
||||
Strings p2_args;
|
||||
p2_args.push_back("-A");
|
||||
p2_args.push_back(revert_to_path + "/");
|
||||
string output = runProgram("ls", true, p2_args);
|
||||
if(output == "")
|
||||
continue;
|
||||
}
|
||||
else{ //is file
|
||||
cpcommand += " " + (revertPathOrFile + "@" + unsignedInt2String(epoch));
|
||||
|
||||
if(epoch == 0){
|
||||
//delete file
|
||||
if(FileExist(revertPathOrFile))
|
||||
deletePath(revertPathOrFile); //we only delete if the cp doesnt overwrite it below
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
//Revert
|
||||
printMsg(lvlError, format("Reverting '%1%@%2%'") % revertPathOrFile % unsignedInt2String(epoch));
|
||||
printMsg(lvlError, format("Command: '%1%'") % cpcommand);
|
||||
cpcommand += " " + revertPathOrFile;
|
||||
p_args.push_back(cpcommand);
|
||||
runProgram_AndPrintOutput("sh", true, p_args, "sh-cp");
|
||||
}
|
||||
|
||||
|
||||
//*** Now also revert state references to the specific revision (the revision is already converted to a timestamp here)
|
||||
|
||||
//Query the references of the old revision (already converted to a timestamp)
|
||||
PathSet state_references;
|
||||
queryXReferencesTxn(txn, statePath, state_references, true, -1, timestamp);
|
||||
PathSet state_stateReferences;
|
||||
queryXReferencesTxn(txn, statePath, state_stateReferences, false, -1, timestamp);
|
||||
|
||||
//Now set these old references as the new references at the new (just created) Timestamp
|
||||
setStateComponentReferencesTxn(txn, statePath, Strings(state_references.begin(), state_references.end()), -1, newTimestamp);
|
||||
setStateStateReferencesTxn(txn, statePath, Strings(state_stateReferences.begin(), state_stateReferences.end()), -1, newTimestamp);
|
||||
|
||||
printMsg(lvlError, format("Reverted state of '%1%' to revision '%2%'") % statePath % revision_arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//TODO maybe add user ID ?
|
||||
Snapshots commitStatePathTxn(const Transaction & txn, const Path & statePath)
|
||||
{
|
||||
if(!isValidStatePathTxn(txn, statePath))
|
||||
|
|
@ -91,7 +222,7 @@ Snapshots commitStatePathTxn(const Transaction & txn, const Path & statePath)
|
|||
intervalPaths.insert(fullstatedir);
|
||||
}
|
||||
}
|
||||
vector<int> intervals = store->getStatePathsInterval(intervalPaths); //TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! txn
|
||||
vector<int> intervals = getStatePathsIntervalTxn(txn, intervalPaths);
|
||||
|
||||
Snapshots revisions_list;
|
||||
|
||||
|
|
@ -142,4 +273,109 @@ Snapshots commitStatePathTxn(const Transaction & txn, const Path & statePath)
|
|||
//setStatePathsIntervalTxn(txn, intervalPaths, intervals); //TODO!!!!!!!!!!!!!!!!!!!!!!!!!!!!! uncomment
|
||||
}
|
||||
|
||||
//TODO include this call in the validate function
|
||||
//TODO ONLY CALL THIS FUNCTION ON A NON-SHARED STATE PATH!!!!!!!!!!!
|
||||
void scanAndUpdateAllReferencesTxn(const Transaction & txn, const Path & statePath
|
||||
, PathSet & newFoundComponentReferences, PathSet & newFoundStateReferences) //only for recursion
|
||||
{
|
||||
//Check if is a state Path
|
||||
if(! isValidStatePathTxn(txn, statePath))
|
||||
throw Error(format("This path '%1%' is not a state path") % statePath);
|
||||
|
||||
//printMsg(lvlError, format("scanAndUpdateAllReferencesTxn: '%1%' - %2%") % statePath % revision);
|
||||
|
||||
//TODO check if path is not a shared path !
|
||||
//TODO
|
||||
|
||||
//get all possible state and component references
|
||||
PathSet allComponentPaths;
|
||||
PathSet allStatePaths;
|
||||
queryAllValidPathsTxn(txn, allComponentPaths, allStatePaths);
|
||||
|
||||
//Remove derivation paths
|
||||
PathSet allComponentPaths2; //without derivations
|
||||
for (PathSet::iterator i = allComponentPaths.begin(); i != allComponentPaths.end(); ++i){
|
||||
string path = *i;
|
||||
if(path.substr(path.length() - 4,path.length()) != drvExtension) //TODO HACK: we should have a typed table or a seperate table .... drvExtension == ".drv"
|
||||
allComponentPaths2.insert(path);
|
||||
}
|
||||
|
||||
//TODO maybe only scan in the changeset (patch) for new references? (this will be difficult and depending on the underlying versioning system)
|
||||
|
||||
//Scan in for (new) component and state references
|
||||
PathSet state_references = scanForReferences(statePath, allComponentPaths2);
|
||||
PathSet state_stateReferences = scanForStateReferences(statePath, allStatePaths);
|
||||
|
||||
//Retrieve old references
|
||||
PathSet old_references;
|
||||
PathSet old_state_references;
|
||||
queryXReferencesTxn(txn, statePath, old_references, true, -1); //get the latsest references
|
||||
queryXReferencesTxn(txn, statePath, old_state_references, false, -1);
|
||||
|
||||
//Check for added and removed paths
|
||||
PathSet diff_references_removed;
|
||||
PathSet diff_references_added;
|
||||
pathSets_difference(state_references, old_references, diff_references_removed, diff_references_added);
|
||||
PathSet diff_state_references_removed;
|
||||
PathSet diff_state_references_added;
|
||||
pathSets_difference(state_stateReferences, old_state_references, diff_state_references_removed, diff_state_references_added);
|
||||
|
||||
//Set PathSet's for the caller of this function
|
||||
newFoundComponentReferences = diff_references_added;
|
||||
newFoundStateReferences = diff_state_references_added;
|
||||
|
||||
//Print error, but we could also throw an error.
|
||||
if(diff_references_added.size() != 0)
|
||||
for (PathSet::iterator i = diff_references_added.begin(); i != diff_references_added.end(); ++i)
|
||||
printMsg(lvlError, format("Added component reference found!: '%1%' in state path '%2%'") % (*i) % statePath);
|
||||
if(diff_references_removed.size() != 0)
|
||||
for (PathSet::iterator i = diff_references_removed.begin(); i != diff_references_removed.end(); ++i)
|
||||
printMsg(lvlError, format("Removed component reference found!: '%1%' in state path '%2%'") % (*i) % statePath);
|
||||
if(diff_state_references_added.size() != 0)
|
||||
for (PathSet::iterator i = diff_state_references_added.begin(); i != diff_state_references_added.end(); ++i)
|
||||
printMsg(lvlError, format("Added state reference found!: '%1%' in state path '%2%'") % (*i) % statePath);
|
||||
if(diff_state_references_removed.size() != 0)
|
||||
for (PathSet::iterator i = diff_state_references_removed.begin(); i != diff_state_references_removed.end(); ++i)
|
||||
printMsg(lvlError, format("Removed state reference found!: '%1%' in state path '%2%'") % (*i) % statePath);
|
||||
|
||||
//We always set the referernces so we know they were scanned (maybe the same) at a certain time
|
||||
printMsg(lvlError, format("Updating new references for statepath: '%1%'") % statePath);
|
||||
Path drvPath = queryStatePathDrvTxn(txn, statePath);
|
||||
registerValidPath(txn,
|
||||
statePath,
|
||||
Hash(), //emtpy hash
|
||||
state_references,
|
||||
state_stateReferences,
|
||||
drvPath,
|
||||
-1); //Set at a new timestamp
|
||||
}
|
||||
|
||||
void scanAndUpdateAllReferencesRecusivelyTxn(const Transaction & txn, const Path & statePath)
|
||||
{
|
||||
if(! isValidStatePathTxn(txn, statePath))
|
||||
throw Error(format("This path '%1%' is not a state path") % statePath);
|
||||
|
||||
//get all state current state references recursively
|
||||
PathSet statePaths;
|
||||
storePathRequisitesTxn(txn, statePath, false, statePaths, false, true, -1); //Get all current state dependencies
|
||||
|
||||
//Add own statePath (may already be in there, but its a set, so no doubles)
|
||||
statePaths.insert(statePath);
|
||||
|
||||
//We dont need to sort since the db does that
|
||||
//call scanForAllReferences again on all statePaths
|
||||
for (PathSet::iterator i = statePaths.begin(); i != statePaths.end(); ++i){
|
||||
|
||||
//Scan, update, call recursively
|
||||
PathSet newFoundComponentReferences;
|
||||
PathSet newFoundStateReferences;
|
||||
scanAndUpdateAllReferencesTxn(txn, *i, newFoundComponentReferences, newFoundStateReferences);
|
||||
|
||||
//Call the function recursively again on all newly found references //TODO test if this works
|
||||
PathSet allNewReferences = pathSets_union(newFoundComponentReferences, newFoundStateReferences);
|
||||
for (PathSet::iterator j = allNewReferences.begin(); j != allNewReferences.end(); ++j)
|
||||
scanAndUpdateAllReferencesRecusivelyTxn(txn, *j);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
namespace nix {
|
||||
|
||||
/* Create a state directory. */
|
||||
void createStateDirs(const DerivationStateOutputDirs & stateOutputDirs, const DerivationStateOutputs & stateOutputs);
|
||||
void createStateDirsTxn(const Transaction & txn, const DerivationStateOutputDirs & stateOutputDirs, const DerivationStateOutputs & stateOutputs);
|
||||
|
||||
/* TODO */
|
||||
Snapshots commitStatePathTxn(const Transaction & txn, const Path & statePath);
|
||||
|
|
@ -19,6 +19,14 @@ Snapshots commitStatePathTxn(const Transaction & txn, const Path & statePath);
|
|||
/* TODO */
|
||||
//int readRevisionNumber(Path statePath);
|
||||
|
||||
|
||||
void scanAndUpdateAllReferencesTxn(const Transaction & txn, const Path & statePath
|
||||
, PathSet & newFoundComponentReferences, PathSet & newFoundStateReferences);
|
||||
|
||||
void scanAndUpdateAllReferencesRecusivelyTxn(const Transaction & txn, const Path & statePath);
|
||||
|
||||
void revertToRevisionTxn(const Transaction & txn, Path & componentPath, Path & derivationPath, Path & statePath, int revision_arg, bool recursive);
|
||||
|
||||
}
|
||||
|
||||
#endif /* !__STORESTATE_H */
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ typedef enum {
|
|||
wopCollectGarbage,
|
||||
wopExportPath,
|
||||
wopImportPath,
|
||||
wopQueryDeriver,
|
||||
wopQueryDerivers,
|
||||
} WorkerOp;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -370,8 +370,9 @@ void writeStringToFile(const Path & path, const string & s)
|
|||
|
||||
|
||||
LogType logType = ltPretty;
|
||||
Verbosity verbosity = lvlInfo;
|
||||
//Verbosity verbosity = lvlInfo;
|
||||
//Verbosity verbosity = lvlDebug;
|
||||
Verbosity verbosity = lvlVomit;
|
||||
|
||||
static int nestingLevel = 0;
|
||||
|
||||
|
|
@ -1176,20 +1177,9 @@ bool IsDirectory(const string FileName)
|
|||
return ((my_stat.st_mode & S_IFDIR) != 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
string getCallingUserName()
|
||||
{
|
||||
//TODO Make this work on WINDOWS: Untested!
|
||||
/*
|
||||
#include <windows.h>
|
||||
char acUserName[100];
|
||||
DWORD nUserName = sizeof(acUserName);
|
||||
if (GetUserName(acUserName, &nUserName))
|
||||
cout << "User name is " << acUserName << "." << endl;
|
||||
else
|
||||
cerr << "Failed to lookup user name, error code " << GetLastError() << "." << endl;
|
||||
*/
|
||||
|
||||
//Linux
|
||||
Strings empty;
|
||||
string username = runProgram("whoami", true, empty); //the username of the user that is trying to build the component
|
||||
|
|
@ -1200,6 +1190,7 @@ string getCallingUserName()
|
|||
|
||||
return username;
|
||||
}
|
||||
*/
|
||||
|
||||
//merges two PathSets into one, removing doubles (union)
|
||||
PathSet pathSets_union(const PathSet & paths1, const PathSet & paths2)
|
||||
|
|
|
|||
|
|
@ -310,7 +310,7 @@ void runProgram_AndPrintOutput(Path program, bool searchPath, const Strings & ar
|
|||
|
||||
int getTimeStamp();
|
||||
|
||||
string getCallingUserName();
|
||||
//string getCallingUserName();
|
||||
|
||||
/* TODO */
|
||||
PathSet pathSets_union(const PathSet & paths1, const PathSet & paths2);
|
||||
|
|
|
|||
|
|
@ -563,7 +563,7 @@ static void installDerivations(Globals & globals,
|
|||
|
||||
string oldStatePath;
|
||||
//query old state path
|
||||
PathSet derivers = queryDerivers(noTxn, i->queryOutPath(globals.state), newStateIdentifier, getCallingUserName());
|
||||
PathSet derivers = store->queryDerivers(i->queryOutPath(globals.state), newStateIdentifier, int2String(geteuid())); //TODO Check if username if ok
|
||||
if(derivers.size() != 1)
|
||||
throw Error(format("Internal Error: There is not exactly one deriver with state_identifier '%1%' for path '%2%'")
|
||||
% newStateIdentifier % i->queryOutPath(globals.state));
|
||||
|
|
|
|||
|
|
@ -11,4 +11,4 @@ nix-state.o: help.txt.hh
|
|||
|
||||
AM_CXXFLAGS = \
|
||||
-I$(srcdir)/.. ${bdb_include} $(aterm_include) -I$(srcdir)/../libutil \
|
||||
-I$(srcdir)/../libstore -I$(srcdir)/../libmain
|
||||
-I$(srcdir)/../libstore -I$(srcdir)/../libmain -I$(srcdir)/../libext3cow
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include "references.hh"
|
||||
#include "store-state.hh"
|
||||
#include "config.h"
|
||||
#include "snapshot.hh"
|
||||
|
||||
using namespace nix;
|
||||
using std::cin;
|
||||
|
|
@ -67,9 +68,9 @@ Derivation getDerivation(const string & fullPath, const Strings & program_args,
|
|||
//printMsg(lvlError, format("'%1%' - '%2%' - '%3%' - '%4%' - '%5%'") % componentPath % state_identifier % binary % username % program_args);
|
||||
|
||||
if(isStateComponent)
|
||||
derivers = queryDerivers(noTxn, componentPath, state_identifier, username);
|
||||
derivers = store->queryDerivers(componentPath, state_identifier, username);
|
||||
else
|
||||
derivers.insert(queryDeriver(noTxn, componentPath));
|
||||
derivers.insert(store->queryDeriver(componentPath));
|
||||
|
||||
if(getDerivers == true)
|
||||
return Derivation();
|
||||
|
|
@ -162,24 +163,23 @@ static void opShowStatePath(Strings opFlags, Strings opArgs)
|
|||
printMsg(lvlError, format("%1%") % statePath);
|
||||
}
|
||||
|
||||
/*
|
||||
* Input: store (or statePath?)
|
||||
* Returns all the drv's of the statePaths (in)directly referenced.
|
||||
*/
|
||||
PathSet getAllStateDerivationsRecursively(const Path & storePath, const int revision)
|
||||
|
||||
static void revertToRevision(Strings opFlags, Strings opArgs)
|
||||
{
|
||||
//Get recursively all state paths
|
||||
PathSet statePaths;
|
||||
store->storePathRequisites(storePath, false, statePaths, false, true, revision);
|
||||
|
||||
//Find the matching drv with the statePath
|
||||
PathSet derivations;
|
||||
for (PathSet::iterator i = statePaths.begin(); i != statePaths.end(); ++i)
|
||||
derivations.insert(store->queryStatePathDrv(*i));
|
||||
|
||||
return derivations;
|
||||
Path componentPath;
|
||||
Path statePath;
|
||||
string binary;
|
||||
string derivationPath;
|
||||
bool isStateComponent;
|
||||
Strings program_args;
|
||||
Derivation drv = getDerivation_andCheckArgs(opFlags, opArgs, componentPath, statePath, binary, derivationPath, isStateComponent, program_args);
|
||||
|
||||
bool recursive = revert_recursively;
|
||||
|
||||
store->revertToRevision(componentPath, derivationPath, statePath, revision_arg, recursive);
|
||||
}
|
||||
|
||||
|
||||
static void queryAvailableStateRevisions(Strings opFlags, Strings opArgs)
|
||||
{
|
||||
Path statePath;
|
||||
|
|
@ -196,7 +196,9 @@ static void queryAvailableStateRevisions(Strings opFlags, Strings opArgs)
|
|||
}
|
||||
|
||||
//Unshare if neccacary
|
||||
Path nonSharedStatePath = toNonSharedPathTxn(noTxn, statePath);
|
||||
PathSet nonSharedPaths;
|
||||
nonSharedPaths.insert(statePath);
|
||||
Path nonSharedStatePath = *((store->toNonSharedPathSet(nonSharedPaths)).begin()); //TODO CHECK IF THIS WORKS !!!!!!!!
|
||||
if(nonSharedStatePath != statePath){
|
||||
printMsg(lvlError, format("The statePath is shared with this path %1%") % nonSharedStatePath);
|
||||
statePath = nonSharedStatePath;
|
||||
|
|
@ -204,8 +206,7 @@ static void queryAvailableStateRevisions(Strings opFlags, Strings opArgs)
|
|||
|
||||
RevisionInfos revisions;
|
||||
bool notEmpty = store->queryAvailableStateRevisions(statePath, revisions);
|
||||
|
||||
|
||||
|
||||
if(!notEmpty){
|
||||
printMsg(lvlError, format("No revisions yet for: %1%") % statePath);
|
||||
return;
|
||||
|
|
@ -240,227 +241,6 @@ static void queryAvailableStateRevisions(Strings opFlags, Strings opArgs)
|
|||
}
|
||||
}
|
||||
|
||||
static void revertToRevision(Strings opFlags, Strings opArgs)
|
||||
{
|
||||
Path componentPath;
|
||||
Path statePath;
|
||||
string binary;
|
||||
string derivationPath;
|
||||
bool isStateComponent;
|
||||
Strings program_args;
|
||||
Derivation drv = getDerivation_andCheckArgs(opFlags, opArgs, componentPath, statePath, binary, derivationPath, isStateComponent, program_args);
|
||||
|
||||
bool recursive = revert_recursively;
|
||||
|
||||
//TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! add TXN here ???????????
|
||||
|
||||
PathSet statePaths;
|
||||
if(recursive)
|
||||
PathSet statePaths = getAllStateDerivationsRecursively(componentPath, revision_arg); //get dependecies (if neccecary | recusively) of all state components that need to be updated
|
||||
else
|
||||
statePaths.insert(derivationPath); //Insert direct state path
|
||||
|
||||
//get a new timestamp for the references update
|
||||
int newTimestamp = getTimeStamp();
|
||||
|
||||
//Get the revisions recursively to also roll them back
|
||||
RevisionClosure getRivisions;
|
||||
RevisionClosureTS getTimestamps;
|
||||
bool b = store->queryStateRevisions(statePath, getRivisions, getTimestamps, revision_arg);
|
||||
|
||||
//Revert each statePath in the list
|
||||
for (RevisionClosure::iterator i = getRivisions.begin(); i != getRivisions.end(); ++i){
|
||||
Path statePath = (*i).first;
|
||||
Snapshots revisioned_paths = (*i).second;
|
||||
int timestamp = getTimestamps[statePath];
|
||||
|
||||
//get its derivation-state-items
|
||||
Derivation statePath_drv = derivationFromPathTxn(noTxn, queryStatePathDrvTxn(noTxn, statePath));
|
||||
DerivationStateOutputDirs stateOutputDirs = statePath_drv.stateOutputDirs;
|
||||
|
||||
//TODO Sort snapshots??? eg first restore root, then the subdirs??
|
||||
|
||||
for (Snapshots::iterator j = revisioned_paths.begin(); j != revisioned_paths.end(); ++j){
|
||||
Path revertPathOrFile = (*j).first;
|
||||
unsigned int epoch = (*j).second;
|
||||
|
||||
//printMsg(lvlError, format("MAYBE '%1%'") % revertPathOrFile);
|
||||
|
||||
//Look up the type from the drv with for the current snapshotted path
|
||||
Path statePath_postfix = revertPathOrFile.substr(nixStoreState.length() + 1, revertPathOrFile.length() - nixStoreState.length());
|
||||
statePath_postfix = statePath_postfix.substr(statePath_postfix.find_first_of("/") + 1, statePath_postfix.length());
|
||||
if(statePath_postfix == "")
|
||||
statePath_postfix = "/";
|
||||
string type = stateOutputDirs.at(statePath_postfix).type;
|
||||
if(type == "none")
|
||||
continue;
|
||||
|
||||
//Now that were still here, we need to copy the state from the previous version back
|
||||
Strings p_args;
|
||||
p_args.push_back("-c"); //we use the shell to execute the cp command becuase the shell expands the '*'
|
||||
string cpcommand = "cp";
|
||||
if(revertPathOrFile.substr(revertPathOrFile.length() -1 , revertPathOrFile.length()) == "/"){ //is dir
|
||||
string revert_to_path = revertPathOrFile.substr(0, revertPathOrFile.length() -1) + "@" + unsignedInt2String(epoch);
|
||||
cpcommand += " -R " + revert_to_path + "/*";
|
||||
|
||||
//clean all contents of the folder first (so were sure the path is clean)
|
||||
if(pathExists(revertPathOrFile))
|
||||
deletePath(revertPathOrFile);
|
||||
|
||||
if(epoch == 0) //Path was deleted so were done
|
||||
continue;
|
||||
else //If path was not deleted in the previous version, we need to make sure it exists or cp will fail
|
||||
ensureDirExists(revertPathOrFile);
|
||||
|
||||
//If the the dir has not contents then a cp ..../* will error since * cannot be expanded. So in this case were done and dont have to revert.
|
||||
Strings p2_args;
|
||||
p2_args.push_back("-A");
|
||||
p2_args.push_back(revert_to_path + "/");
|
||||
string output = runProgram("ls", true, p2_args);
|
||||
if(output == "")
|
||||
continue;
|
||||
}
|
||||
else{ //is file
|
||||
cpcommand += " " + (revertPathOrFile + "@" + unsignedInt2String(epoch));
|
||||
|
||||
if(epoch == 0){
|
||||
//delete file
|
||||
if(FileExist(revertPathOrFile))
|
||||
deletePath(revertPathOrFile); //we only delete if the cp doesnt overwrite it below
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
//Revert
|
||||
printMsg(lvlError, format("Reverting '%1%@%2%'") % revertPathOrFile % unsignedInt2String(epoch));
|
||||
printMsg(lvlError, format("Command: '%1%'") % cpcommand);
|
||||
cpcommand += " " + revertPathOrFile;
|
||||
p_args.push_back(cpcommand);
|
||||
runProgram_AndPrintOutput("sh", true, p_args, "sh-cp");
|
||||
}
|
||||
|
||||
|
||||
//*** Now also revert state references to the specific revision (the revision is already converted to a timestamp here)
|
||||
|
||||
//Query the references of the old revision (already converted to a timestamp)
|
||||
PathSet state_references;
|
||||
queryXReferencesTxn(noTxn, statePath, state_references, true, -1, timestamp);
|
||||
PathSet state_stateReferences;
|
||||
queryXReferencesTxn(noTxn, statePath, state_stateReferences, false, -1, timestamp);
|
||||
|
||||
//Now set these old references as the new references at the new (just created) Timestamp
|
||||
setStateComponentReferencesTxn(noTxn, statePath, Strings(state_references.begin(), state_references.end()), -1, newTimestamp);
|
||||
setStateStateReferencesTxn(noTxn, statePath, Strings(state_stateReferences.begin(), state_stateReferences.end()), -1, newTimestamp);
|
||||
|
||||
printMsg(lvlError, format("Reverted state of '%1%' to revision '%2%'") % statePath % revision_arg);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO include this call in the validate function
|
||||
//TODO ONLY CALL THIS FUNCTION ON A NON-SHARED STATE PATH!!!!!!!!!!!
|
||||
void scanAndUpdateAllReferencesTxn(const Transaction & txn, const Path & statePath
|
||||
, PathSet & newFoundComponentReferences, PathSet & newFoundStateReferences) //only for recursion
|
||||
{
|
||||
//Check if is a state Path
|
||||
if(! isValidStatePathTxn(txn, statePath))
|
||||
throw Error(format("This path '%1%' is not a state path") % statePath);
|
||||
|
||||
//printMsg(lvlError, format("scanAndUpdateAllReferencesTxn: '%1%' - %2%") % statePath % revision);
|
||||
|
||||
//TODO check if path is not a shared path !
|
||||
//TODO
|
||||
|
||||
//get all possible state and component references
|
||||
PathSet allComponentPaths;
|
||||
PathSet allStatePaths;
|
||||
queryAllValidPaths(txn, allComponentPaths, allStatePaths);
|
||||
|
||||
//Remove derivation paths
|
||||
PathSet allComponentPaths2; //without derivations
|
||||
for (PathSet::iterator i = allComponentPaths.begin(); i != allComponentPaths.end(); ++i){
|
||||
string path = *i;
|
||||
if(path.substr(path.length() - 4,path.length()) != drvExtension) //TODO HACK: we should have a typed table or a seperate table .... drvExtension == ".drv"
|
||||
allComponentPaths2.insert(path);
|
||||
}
|
||||
|
||||
//TODO maybe only scan in the changeset (patch) for new references? (this will be difficult and depending on the underlying versioning system)
|
||||
|
||||
//Scan in for (new) component and state references
|
||||
PathSet state_references = scanForReferences(statePath, allComponentPaths2);
|
||||
PathSet state_stateReferences = scanForStateReferences(statePath, allStatePaths);
|
||||
|
||||
//Retrieve old references
|
||||
PathSet old_references;
|
||||
PathSet old_state_references;
|
||||
queryXReferencesTxn(txn, statePath, old_references, true, -1); //get the latsest references
|
||||
queryXReferencesTxn(txn, statePath, old_state_references, false, -1);
|
||||
|
||||
//Check for added and removed paths
|
||||
PathSet diff_references_removed;
|
||||
PathSet diff_references_added;
|
||||
pathSets_difference(state_references, old_references, diff_references_removed, diff_references_added);
|
||||
PathSet diff_state_references_removed;
|
||||
PathSet diff_state_references_added;
|
||||
pathSets_difference(state_stateReferences, old_state_references, diff_state_references_removed, diff_state_references_added);
|
||||
|
||||
//Set PathSet's for the caller of this function
|
||||
newFoundComponentReferences = diff_references_added;
|
||||
newFoundStateReferences = diff_state_references_added;
|
||||
|
||||
//Print error, but we could also throw an error.
|
||||
if(diff_references_added.size() != 0)
|
||||
for (PathSet::iterator i = diff_references_added.begin(); i != diff_references_added.end(); ++i)
|
||||
printMsg(lvlError, format("Added component reference found!: '%1%' in state path '%2%'") % (*i) % statePath);
|
||||
if(diff_references_removed.size() != 0)
|
||||
for (PathSet::iterator i = diff_references_removed.begin(); i != diff_references_removed.end(); ++i)
|
||||
printMsg(lvlError, format("Removed component reference found!: '%1%' in state path '%2%'") % (*i) % statePath);
|
||||
if(diff_state_references_added.size() != 0)
|
||||
for (PathSet::iterator i = diff_state_references_added.begin(); i != diff_state_references_added.end(); ++i)
|
||||
printMsg(lvlError, format("Added state reference found!: '%1%' in state path '%2%'") % (*i) % statePath);
|
||||
if(diff_state_references_removed.size() != 0)
|
||||
for (PathSet::iterator i = diff_state_references_removed.begin(); i != diff_state_references_removed.end(); ++i)
|
||||
printMsg(lvlError, format("Removed state reference found!: '%1%' in state path '%2%'") % (*i) % statePath);
|
||||
|
||||
//We always set the referernces so we know they were scanned (maybe the same) at a certain time
|
||||
printMsg(lvlError, format("Updating new references for statepath: '%1%'") % statePath);
|
||||
Path drvPath = queryStatePathDrvTxn(txn, statePath);
|
||||
registerValidPath(txn,
|
||||
statePath,
|
||||
Hash(), //emtpy hash
|
||||
state_references,
|
||||
state_stateReferences,
|
||||
drvPath,
|
||||
-1); //Set at a new timestamp
|
||||
}
|
||||
|
||||
void scanAndUpdateAllReferencesRecusivelyTxn(const Transaction & txn, const Path & statePath)
|
||||
{
|
||||
if(! isValidStatePathTxn(txn, statePath))
|
||||
throw Error(format("This path '%1%' is not a state path") % statePath);
|
||||
|
||||
//get all state current state references recursively
|
||||
PathSet statePaths;
|
||||
store->storePathRequisites(statePath, false, statePaths, false, true, -1); //Get all current state dependencies
|
||||
|
||||
//Add own statePath (may already be in there, but its a set, so no doubles)
|
||||
statePaths.insert(statePath);
|
||||
|
||||
//We dont need to sort since the db does that
|
||||
//call scanForAllReferences again on all statePaths
|
||||
for (PathSet::iterator i = statePaths.begin(); i != statePaths.end(); ++i){
|
||||
|
||||
//Scan, update, call recursively
|
||||
PathSet newFoundComponentReferences;
|
||||
PathSet newFoundStateReferences;
|
||||
scanAndUpdateAllReferencesTxn(txn, *i, newFoundComponentReferences, newFoundStateReferences);
|
||||
|
||||
//Call the function recursively again on all newly found references //TODO test if this works
|
||||
PathSet allNewReferences = pathSets_union(newFoundComponentReferences, newFoundStateReferences);
|
||||
for (PathSet::iterator j = allNewReferences.begin(); j != allNewReferences.end(); ++j)
|
||||
scanAndUpdateAllReferencesRecusivelyTxn(txn, *j);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void opRunComponent(Strings opFlags, Strings opArgs)
|
||||
|
|
@ -482,9 +262,7 @@ static void opRunComponent(Strings opFlags, Strings opArgs)
|
|||
//add locks ... ?
|
||||
//svn lock ... ?
|
||||
|
||||
//TODO
|
||||
Transaction txn;
|
||||
//createStoreTransaction(txn);
|
||||
|
||||
|
||||
//******************* Run ****************************
|
||||
|
||||
|
|
@ -506,10 +284,16 @@ static void opRunComponent(Strings opFlags, Strings opArgs)
|
|||
printMsg(lvlError, format("Command: '%1%'") % (root_componentPath + root_binary + root_args));
|
||||
executeShellCommand(root_componentPath + root_binary + root_args);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
|
||||
//TODO
|
||||
Transaction txn;
|
||||
//createStoreTransaction(txn);
|
||||
|
||||
//******************* Scan for new references if neccecary
|
||||
if(scanforReferences)
|
||||
scanAndUpdateAllReferencesRecusivelyTxn(txn, root_statePath);
|
||||
store->scanAndUpdateAllReferences(root_statePath, true); //TODO make recursive a paramter?
|
||||
|
||||
//get all current (maybe updated by the scan) dependecies (if neccecary | recusively) of all state components that need to be updated
|
||||
PathSet statePaths;
|
||||
|
|
@ -519,17 +303,17 @@ static void opRunComponent(Strings opFlags, Strings opArgs)
|
|||
//Start transaction TODO
|
||||
|
||||
//Replace all shared paths in the set for their real paths
|
||||
statePaths = toNonSharedPathSetTxn(noTxn, statePaths);
|
||||
statePaths = store->toNonSharedPathSet(statePaths);
|
||||
|
||||
//******************* With everything in place, we call the commit script on all statePaths (in)directly referenced **********************
|
||||
|
||||
//Commit all statePaths
|
||||
RevisionClosure rivisionMapping;
|
||||
for (PathSet::iterator i = statePaths.begin(); i != statePaths.end(); ++i) //TODO first commit own state path?
|
||||
rivisionMapping[*i] = commitStatePathTxn(txn, *i);
|
||||
rivisionMapping[*i] = store->commitStatePath(*i);
|
||||
|
||||
//Save new revisions
|
||||
setStateRevisionsTxn(txn, rivisionMapping, root_statePath, comment);
|
||||
store->setStateRevisions(rivisionMapping, root_statePath, comment); //TODO how about the txn?
|
||||
|
||||
//Commit transaction
|
||||
//txn.commit();
|
||||
|
|
@ -576,7 +360,7 @@ void run(Strings args)
|
|||
store = openStore();
|
||||
printMsg(lvlError, format("1: %1%") % bool2string( store->isStateComponent("/nix/store/7xkw5fkz5yw7dpx0pc6l12bh9a56135c-hellostateworld-1.0") ) );
|
||||
printMsg(lvlError, format("2: %1%") % bool2string( store->isStateComponent("/nix/store/05441jm8xmsidqm43ivk0micckf0mr2m-nvidiaDrivers") ) );
|
||||
printMsg(lvlError, format("3: %1%") % bool2string( store->isStateDrvPath("/nix/store/2hpx60ibdfv2pslg4rjvp177frijamvi-hellostateworld-1.0.drv") ) );
|
||||
printMsg(lvlError, format("3: %1%") % bool2string( isState Drv Path("/nix/store/2hpx60ibdfv2pslg4rjvp177frijamvi-hellostateworld-1.0.drv") ) );
|
||||
|
||||
store = openStore();
|
||||
Path p = store->queryStatePathDrv("/nix/state/6g6kfgimz8szznlshf13s29fn01zp99d-hellohardcodedstateworld-1.0-test2");
|
||||
|
|
@ -684,7 +468,7 @@ void run(Strings args)
|
|||
// /nix/state/6l93ff3bn1mk61jbdd34diafmb4aq7c6-hellohardcodedstateworld-1.0-
|
||||
// /nix/state/x8k4xiv8m4zmx26gmb0pyymmd6671fyy-hellohardcodedstateworld-1.0-
|
||||
|
||||
PathSet p = getSharedWithPathSetRecTxn(noTxn, "/nix/state/6l93ff3bn1mk61jbdd34diafmb4aq7c6-hellohardcodedstateworld-1.0-");
|
||||
PathSet p = store->getSharedWithPathSetRec("/nix/state/6l93ff3bn1mk61jbdd34diafmb4aq7c6-hellohardcodedstateworld-1.0-");
|
||||
for (PathSet::iterator j = p.begin(); j != p.end(); ++j)
|
||||
printMsg(lvlError, format("P: '%1%'") % *j );
|
||||
return;
|
||||
|
|
@ -767,8 +551,9 @@ void run(Strings args)
|
|||
throw UsageError("only one operation may be specified");
|
||||
}
|
||||
|
||||
//If no username given: take the username of the caller
|
||||
if(username == "")
|
||||
username = getCallingUserName();
|
||||
username = int2String(geteuid());
|
||||
|
||||
if (!op) throw UsageError("no operation specified");
|
||||
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ static Path fixStoreOrStatePath(Path path)
|
|||
static Path useDeriver(Path path)
|
||||
{
|
||||
if (!isDerivation(path)) {
|
||||
path = queryDeriver(noTxn, path);
|
||||
path = store->queryDeriver(path);
|
||||
if (path == "")
|
||||
throw Error(format("deriver of path `%1%' is not known") % path);
|
||||
}
|
||||
|
|
@ -331,7 +331,7 @@ static void opQuery(Strings opFlags, Strings opArgs)
|
|||
for (Strings::iterator i = opArgs.begin();
|
||||
i != opArgs.end(); ++i)
|
||||
{
|
||||
Path deriver = queryDeriver(noTxn, fixPath(*i));
|
||||
Path deriver = store->queryDeriver(fixPath(*i));
|
||||
cout << format("%1%\n") %
|
||||
(deriver == "" ? "unknown-deriver" : deriver);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ static void tunnelStderr(const unsigned char * buf, size_t count)
|
|||
process handling the connection. Otherwise we could screw up
|
||||
the protocol. It's up to the parent to redirect stderr and
|
||||
send it to the client somehow (e.g., as in build.cc). */
|
||||
if (canSendStderr && myPid == getpid()) {
|
||||
if (canSendStderr && myPid == getpid() && (!debugWorker)) { //TODO debugWorker commit
|
||||
try {
|
||||
writeInt(STDERR_NEXT, to);
|
||||
writeString(string((char *) buf, count), to);
|
||||
|
|
@ -53,8 +53,10 @@ static void tunnelStderr(const unsigned char * buf, size_t count)
|
|||
canSendStderr = false;
|
||||
throw;
|
||||
}
|
||||
} else
|
||||
} else{
|
||||
//printMsg(lvlInfo, format("nix-worker: debug mode"));
|
||||
writeFull(STDERR_FILENO, buf, count);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -317,24 +319,50 @@ static void performOp(Source & from, Sink & to, unsigned int op)
|
|||
writeStringSet(paths, to);
|
||||
break;
|
||||
}
|
||||
|
||||
case wopQueryDeriver: {
|
||||
Path path = readStorePath(from);
|
||||
startWork();
|
||||
Path deriver = store->queryDeriver(path);
|
||||
stopWork();
|
||||
writeString(deriver, to);
|
||||
break;
|
||||
}
|
||||
|
||||
case wopQueryDerivers: {
|
||||
Path path = readStorePath(from);
|
||||
string identifier = readString(from);
|
||||
string user = readString(from);
|
||||
startWork();
|
||||
PathSet derivers = store->queryDerivers(path, identifier, user);
|
||||
stopWork();
|
||||
writeStringSet(derivers, to);
|
||||
break;
|
||||
}
|
||||
|
||||
case wopAddToStore: {
|
||||
/* !!! uberquick hack */
|
||||
string baseName = readString(from);
|
||||
bool fixed = readInt(from) == 1;
|
||||
bool recursive = readInt(from) == 1;
|
||||
string hashAlgo = readString(from);
|
||||
|
||||
|
||||
printMsg(lvlInfo, format("NIXWORKER: WOP 1"));
|
||||
|
||||
/* !!! uberquick hack */
|
||||
Path tmp = createTempDir();
|
||||
AutoDelete delTmp(tmp);
|
||||
Path tmp2 = tmp + "/" + baseName;
|
||||
restorePath(tmp2, from);
|
||||
|
||||
printMsg(lvlInfo, format("NIXWORKER: WOP 2"));
|
||||
|
||||
startWork();
|
||||
Path path = store->addToStore(tmp2, fixed, recursive, hashAlgo);
|
||||
stopWork();
|
||||
|
||||
|
||||
printMsg(lvlInfo, format("NIXWORKER: WOP 3 '%1%'") % path);
|
||||
writeString(path, to);
|
||||
printMsg(lvlInfo, format("NIXWORKER: WOP 4"));
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -468,7 +496,8 @@ static void processConnection()
|
|||
|
||||
/* Exchange the greeting. */
|
||||
unsigned int magic = readInt(from);
|
||||
if (magic != WORKER_MAGIC_1) throw Error("protocol mismatch");
|
||||
if (magic != WORKER_MAGIC_1)
|
||||
throw Error("protocol mismatch");
|
||||
verbosity = (Verbosity) readInt(from);
|
||||
writeInt(WORKER_MAGIC_2, to);
|
||||
|
||||
|
|
@ -506,7 +535,9 @@ static void processConnection()
|
|||
opCount++;
|
||||
|
||||
try {
|
||||
printMsg(lvlInfo, format("Processing op '%1%'") % op);
|
||||
performOp(from, to, op);
|
||||
printMsg(lvlInfo, format("Processed op '%1%'") % op);
|
||||
} catch (Error & e) {
|
||||
stopWork(false, e.msg());
|
||||
}
|
||||
|
|
@ -535,6 +566,20 @@ static void setSigChldAction(bool autoReap)
|
|||
throw SysError("setting SIGCHLD handler");
|
||||
}
|
||||
|
||||
/* Returns the user ID of the one connecting to the socket though
|
||||
* SCM_CREDENTIALS. This uid is checked by the kernel and cannot be faked :)
|
||||
*/
|
||||
uid_t getpeereuid(int sd)
|
||||
{
|
||||
struct ucred cred;
|
||||
int len = sizeof (cred);
|
||||
socklen_t len2 = (socklen_t)len;
|
||||
|
||||
if ( getsockopt(sd, SOL_SOCKET, SO_PEERCRED, &cred, &len2) )
|
||||
throw SysError("Cannot get SCM_CREDENTIALS for socket");
|
||||
|
||||
return cred.uid;
|
||||
}
|
||||
|
||||
static void daemonLoop()
|
||||
{
|
||||
|
|
@ -542,6 +587,7 @@ static void daemonLoop()
|
|||
zombies. */
|
||||
setSigChldAction(true);
|
||||
|
||||
|
||||
/* Create and bind to a Unix domain socket. */
|
||||
AutoCloseFD fdSocket = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (fdSocket == -1)
|
||||
|
|
@ -575,7 +621,8 @@ static void daemonLoop()
|
|||
/* Important: the server process *cannot* open the
|
||||
Berkeley DB environment, because it doesn't like forks
|
||||
very much. */
|
||||
assert(!store);
|
||||
if(!debugWorker)
|
||||
assert(!store);
|
||||
|
||||
/* Accept a connection. */
|
||||
struct sockaddr_un remoteAddr;
|
||||
|
|
@ -585,42 +632,76 @@ static void daemonLoop()
|
|||
(struct sockaddr *) &remoteAddr, &remoteAddrLen);
|
||||
checkInterrupt();
|
||||
if (remote == -1)
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
else
|
||||
throw SysError("accepting connection");
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
else
|
||||
throw SysError("accepting connection");
|
||||
|
||||
printMsg(lvlInfo, format("accepted connection %1%") % remote);
|
||||
uid_t caller_uid = getpeereuid(remote);
|
||||
|
||||
/* Fork a child to handle the connection. */
|
||||
pid_t child;
|
||||
child = fork();
|
||||
|
||||
switch (child) {
|
||||
|
||||
case -1:
|
||||
throw SysError("unable to fork");
|
||||
|
||||
case 0:
|
||||
try { /* child */
|
||||
|
||||
/* Background the worker. */
|
||||
if (setsid() == -1)
|
||||
throw SysError(format("creating a new session"));
|
||||
|
||||
/* Restore normal handling of SIGCHLD. */
|
||||
setSigChldAction(false);
|
||||
|
||||
/* Handle the connection. */
|
||||
from.fd = remote;
|
||||
to.fd = remote;
|
||||
processConnection();
|
||||
|
||||
} catch (std::exception & e) {
|
||||
std::cerr << format("child error: %1%\n") % e.what();
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
printMsg(lvlInfo, format("accepted connection '%1%'")
|
||||
% remote);
|
||||
|
||||
if(!debugWorker)
|
||||
{
|
||||
|
||||
/* Fork a child to handle the connection. */
|
||||
pid_t child;
|
||||
child = fork();
|
||||
|
||||
switch (child) {
|
||||
|
||||
case -1:
|
||||
throw SysError("unable to fork");
|
||||
|
||||
case 0:
|
||||
try { /* child */
|
||||
|
||||
/* We set the user id of the caller in the fork */
|
||||
setCallingUID(caller_uid);
|
||||
printMsg(lvlInfo, format("Fork for connection '%1%' created for userid: '%2%' with username: '%3%'")
|
||||
% remote % queryCallingUID() % queryCallingUsername());
|
||||
|
||||
/* Background the worker. */
|
||||
if (setsid() == -1)
|
||||
throw SysError(format("creating a new session"));
|
||||
|
||||
/* Restore normal handling of SIGCHLD. */
|
||||
setSigChldAction(false);
|
||||
|
||||
/* Handle the connection. */
|
||||
from.fd = remote;
|
||||
to.fd = remote;
|
||||
processConnection();
|
||||
|
||||
} catch (std::exception & e) {
|
||||
std::cerr << format("child error: %1%\n") % e.what();
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printMsg(lvlInfo, format("Nix-worker: debug mode: we can only process 1 job at the time"));
|
||||
|
||||
/* We RESET the user id of the caller cause we have no fork */
|
||||
setCallingUID(caller_uid, true);
|
||||
printMsg(lvlInfo, format("Debug connection '%1%' created for userid: '%2%' with username: '%3%'")
|
||||
% remote % queryCallingUID() % queryCallingUsername());
|
||||
|
||||
/* Background the worker. */
|
||||
//if (setsid() == -1)
|
||||
// throw SysError(format("creating a new session"));
|
||||
|
||||
/* Restore normal handling of SIGCHLD. */
|
||||
//setSigChldAction(false);
|
||||
|
||||
/* Handle the connection. */
|
||||
from.fd = remote;
|
||||
to.fd = remote;
|
||||
processConnection();
|
||||
|
||||
}
|
||||
|
||||
} catch (Interrupted & e) {
|
||||
throw;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue