diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index b6d4a55d2..c32f440d2 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -351,12 +351,10 @@ static Hash hashDerivationModulo(EvalState & state, Derivation drv) drv.stateOutputs.clear(); drv.stateOutputDirs.clear(); drv.env["statepath"] = ""; - printMsg(lvlError, format("YES RUNTIME")); } else{ //Has NO runtime parameters --> Clear state parameters selectively drvso.clearAllRuntimeParamters(); drv.stateOutputDirs.clear(); - printMsg(lvlError, format("NO RUNTIME")); } } @@ -603,17 +601,14 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args) if(enableState && !disableState){ if(runtimeStateParamters == ""){ string enableStateS = bool2string("true"); - drv.stateOutputs["state"] = DerivationStateOutput("", "", "", stateIdentifier, enableStateS, "", "", "", runtimeStateParamters, false); + drv.stateOutputs["state"] = DerivationStateOutput("", "", "", "", stateIdentifier, enableStateS, "", "", "", runtimeStateParamters, "", false); } } /* Use the masked derivation expression to compute the output path. */ - - //TODO CLEANUP - Hash h = hashDerivationModulo(state, drv); - //printMsg(lvlError, format("USES: `%1%'") % printHash(h)); - Path outPath = makeStorePath("output:out", h, drvName); + Hash componentHash = hashDerivationModulo(state, drv); + Path outPath = makeStorePath("output:out", componentHash, drvName); /* Construct the final derivation store expression. */ drv.env["out"] = outPath; @@ -623,16 +618,18 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args) //only add state when we have to to keep compitibilty with the 'old' format. //We add state when it's enbaled by the keywords, and not excplicitly disabled by the user if(enableState && !disableState){ - /* Add the state path based on the outPath */ - string callingUser = "wouterdb"; //TODO: Change into variable - string componentHash = outPath; //hash of the component path - Hash statehash = hashString(htSHA256, callingUser + componentHash); //hash of the state path - Path stateOutPath = makeStatePath("stateOutput:statepath", statehash, drvName, stateIdentifier); //State path + /* Add the state path based on the outPath + * + * NOTE: we do not include the username into the hash calculation of the statepath yet, multiple different users can use the same dervation + * but need different state paths. Thats why we keep a 'dummy' value e.g. global hash for everyone, and later at build time recalculate the real state path + */ + Path stateOutPath = makeStatePath(printHash(componentHash), drvName, stateIdentifier); //State path drv.env["statepath"] = stateOutPath; string enableStateS = bool2string("true"); string createDirsBeforeInstallS = bool2string(createDirsBeforeInstall); - drv.stateOutputs["state"] = DerivationStateOutput(stateOutPath, outputHashAlgo, outputHash, stateIdentifier, enableStateS, shareState, syncState, createDirsBeforeInstallS, runtimeStateParamters); + string username = getCallingUserName(); + drv.stateOutputs["state"] = DerivationStateOutput(stateOutPath, printHash(componentHash), outputHashAlgo, outputHash, stateIdentifier, enableStateS, shareState, syncState, createDirsBeforeInstallS, runtimeStateParamters, username); for(vector::iterator i = stateDirs.begin(); i != stateDirs.end(); ++i) drv.stateOutputDirs[(*i).path] = *(i); @@ -646,14 +643,14 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args) /* Write updated (no need to rebuild) state derivations to the database, so they can be updated at build time */ if(enableState && !disableState){ if(store->isValidPath(outPath)){ //Only add when the path is already valid - Path deriver = queryDeriver(noTxn, outPath); //query the deriver + Path deriver = queryDeriver(noTxn, outPath); //query the deriver if(deriver != drvPath){ store->addUpdatedStateDerivation(drvPath, outPath); } } - //TODO Also add when path is not already valid, which drv does it take at build time, the latest ... guess so .. so we dont need to add? + //TODO Also add when path is not already valid, which drv does it take at build time, the latest ... guess so .. so we dont need to add? } - + /* Optimisation, but required in read-only mode! because in that case we don't actually write store expressions, so we can't diff --git a/src/libstore/build.cc b/src/libstore/build.cc index 848d8d552..dec9dad5e 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -1371,9 +1371,9 @@ void DerivationGoal::startBuilder() env["NIX_STORE"] = nixStore; /* Add all bindings specified in the derivation. */ - for (StringPairs::iterator i = drv.env.begin(); - i != drv.env.end(); ++i) - env[i->first] = i->second; + for (StringPairs::iterator i = drv.env.begin(); i != drv.env.end(); ++i){ + env[i->first] = i->second; + } /* Create a temporary directory where the build will take place. */ @@ -1382,9 +1382,14 @@ void DerivationGoal::startBuilder() /* Create the state directory where the component can store it's state files place */ //TODO MOVEEEEEEEEEEE //We only create state dirs when state is enabled and when the dirs need to be created before the installation - if(drv.stateOutputs.size() != 0) + if(drv.stateOutputs.size() != 0){ + + /* we check the recalculated state path at build time with the correct user for securiyt */ + checkStatePath(drv); + if(drv.stateOutputs.find("state")->second.getCreateDirsBeforeInstall()) createStateDirs(drv.stateOutputDirs, drv.stateOutputs, drv.env); + } /* For convenience, set an environment pointing to the top build directory. */ diff --git a/src/libstore/derivations-ast.def b/src/libstore/derivations-ast.def index d6f260094..9173383fb 100644 --- a/src/libstore/derivations-ast.def +++ b/src/libstore/derivations-ast.def @@ -6,7 +6,7 @@ Derive | ATermList ATermList ATermList ATermList ATermList string string ATermLi | string string | ATerm | EnvBinding | | string ATermList | ATerm | DerivationInput | | string string string string | ATerm | DerivationOutput | -| string string string string string string string string string string | ATerm | DerivationStateOutput | +| string string string string string string string string string string string string | ATerm | DerivationStateOutput | | string string string | ATerm | DerivationStateOutputDir | #We use DeriveWithOutState to create derivations that dont use state, and thus dont have the stateDerivationStateOutput and DerivationStateOutputDir in their derivation diff --git a/src/libstore/derivations.cc b/src/libstore/derivations.cc index a23352d92..160756c78 100644 --- a/src/libstore/derivations.cc +++ b/src/libstore/derivations.cc @@ -92,11 +92,12 @@ Derivation parseDerivation(ATerm t) if(withState){ //parse state part for (ATermIterator i(stateOuts); i; ++i) { - ATerm id, statepath, hashAlgo, hash, stateIdentifier, enabled, shared, synchronization, createDirsBeforeInstall, runtimeStateParamters; - if (!matchDerivationStateOutput(*i, id, statepath, hashAlgo, hash, stateIdentifier, enabled, shared, synchronization, createDirsBeforeInstall, runtimeStateParamters)) + ATerm id, statepath, componentHash, hashAlgo, hash, stateIdentifier, enabled, shared, synchronization, createDirsBeforeInstall, runtimeStateParamters, username; + if (!matchDerivationStateOutput(*i, id, statepath, componentHash, hashAlgo, hash, stateIdentifier, enabled, shared, synchronization, createDirsBeforeInstall, runtimeStateParamters, username)) throwBadDrv(t); DerivationStateOutput stateOut; stateOut.statepath = aterm2String(statepath); + stateOut.componentHash = aterm2String(componentHash); //checkPath(stateOut.path); //should we check the statpath .... ??? stateOut.hashAlgo = aterm2String(hashAlgo); stateOut.hash = aterm2String(hash); @@ -106,6 +107,7 @@ Derivation parseDerivation(ATerm t) stateOut.synchronization = aterm2String(synchronization); stateOut.createDirsBeforeInstall = aterm2String(createDirsBeforeInstall); stateOut.runtimeStateParamters = aterm2String(runtimeStateParamters); + stateOut.username = aterm2String(username); drv.stateOutputs[aterm2String(id)] = stateOut; } } @@ -182,6 +184,7 @@ ATerm unparseDerivation(const Derivation & drv) makeDerivationStateOutput( toATerm(i->first), toATerm(i->second.statepath), + toATerm(i->second.componentHash), toATerm(i->second.hashAlgo), toATerm(i->second.hash), toATerm(i->second.stateIdentifier), @@ -189,7 +192,8 @@ ATerm unparseDerivation(const Derivation & drv) toATerm(i->second.shared), toATerm(i->second.synchronization), toATerm(i->second.createDirsBeforeInstall), - toATerm(i->second.runtimeStateParamters) + toATerm(i->second.runtimeStateParamters), + toATerm(i->second.username) )); } diff --git a/src/libstore/derivations.hh b/src/libstore/derivations.hh index 7cbee8938..9ffb39b1b 100644 --- a/src/libstore/derivations.hh +++ b/src/libstore/derivations.hh @@ -37,6 +37,7 @@ struct DerivationOutput struct DerivationStateOutput { Path statepath; + string componentHash; string hashAlgo; string hash; string stateIdentifier; //the identifier @@ -50,17 +51,21 @@ struct DerivationStateOutput string createDirsBeforeInstall; //if true: creates state dirs before installation string runtimeStateParamters; //if not empty: these are the runtime parameters where state can be found (you can use $statepath here) + string username; + DerivationStateOutput() { } - DerivationStateOutput(Path statepath, string hashAlgo, string hash, string stateIdentifier, string enabled, string shared, string synchronization, string createDirsBeforeInstall, string runtimeStateParamters, bool check=true) + DerivationStateOutput(Path statepath, string componentHash, string hashAlgo, string hash, string stateIdentifier, string enabled, string shared, string synchronization, string createDirsBeforeInstall, string runtimeStateParamters, string username, bool check=true) { if(check){ if(shared != "none" && shared != "full" && shared != "group") throw Error(format("shared '%1%' is not a correct type") % shared); if(synchronization != "none" && synchronization != "exclusive-lock" && synchronization != "recursive-exclusive-lock") throw Error(format("synchronization '%1%' is not a correct type") % synchronization); + if(username == "") + throw Error(format("Username cannot be empty")); } //TODO @@ -68,6 +73,7 @@ struct DerivationStateOutput //commitBinaries this->statepath = statepath; + this->componentHash = componentHash; this->hashAlgo = hashAlgo; this->hash = hash; this->stateIdentifier = stateIdentifier; @@ -76,6 +82,7 @@ struct DerivationStateOutput this->synchronization = synchronization; this->createDirsBeforeInstall = createDirsBeforeInstall; this->runtimeStateParamters = runtimeStateParamters; + this->username = username; } bool getEnabled(){ @@ -91,14 +98,16 @@ struct DerivationStateOutput */ void clearAllRuntimeParamters(){ this->statepath = ""; + this->componentHash = ""; //this->hashAlgo; //Clear this one? //this->hash; //Clear this one? - //this->stateIdentifier; + //this->stateIdentifier; //Changes the statepath directly this->enabled = ""; this->shared = ""; this->synchronization = ""; this->createDirsBeforeInstall = ""; this->runtimeStateParamters = ""; + //this->username; //Changes the statepath directly } }; diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index 4c0109e1c..8e3762914 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -421,6 +421,7 @@ Path queryDeriver(const Transaction & txn, const Path & storePath) if (!isRealisablePath(txn, storePath)) throw Error(format("path `%1%' is not valid") % storePath); Path deriver; + if (nixDB.queryString(txn, dbDerivers, storePath, deriver)) return deriver; else diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc index 50a586dd0..14e8b5170 100644 --- a/src/libstore/store-api.cc +++ b/src/libstore/store-api.cc @@ -79,24 +79,44 @@ Path makeStorePath(const string & type, const Hash & hash, const string & suffix + "-" + suffix; } -Path makeStatePath(const string & type, const Hash & hash, const string & suffix, const string & stateIdentifier) +Path makeStatePath(const string & componentHash, const string & suffix, const string & stateIdentifier) { string suffix_stateIdentifier = stateIdentifier; if(suffix_stateIdentifier != "") suffix_stateIdentifier = "-" + suffix_stateIdentifier; + string username = getCallingUserName(); //Can and Should NOT be faked + /* e.g., "source:sha256:1abc...:/nix/store:foo.tar.gz" */ - string s = type + ":sha256:" + printHash(hash) + ":" - + nixStoreState + ":" + suffix + ":" + stateIdentifier; + string s = ":sha256:" + componentHash + ":" + + nixStoreState + ":" + suffix + ":" + stateIdentifier + ":" + username; checkStoreName(suffix); checkStoreName(stateIdentifier); - return nixStoreState + "/" - + printHash32(compressHash(hashString(htSHA256, s), 20)) - + "-" + suffix + suffix_stateIdentifier; + return nixStoreState + "/" + + printHash32(compressHash(hashString(htSHA256, s), 20)) + + "-" + suffix + suffix_stateIdentifier; } +void checkStatePath(const Derivation & drv) +{ + Path drvPath = drv.stateOutputs.find("state")->second.statepath; + + string componentHash = drv.stateOutputs.find("state")->second.componentHash; + string suffix = drv.env.find("name")->second; + string stateIdentifier = drv.stateOutputs.find("state")->second.stateIdentifier; + Path calculatedPath = makeStatePath(componentHash, suffix, stateIdentifier); + + printMsg(lvlError, format("CHECK: %1% %2%") % drvPath % calculatedPath); + + + if(drvPath != calculatedPath) + Error(format("The statepath from the Derivation does not match the recalculated statepath, are u trying to spoof the statepath?")); +} + + + Path makeStateReposPath(const string & type, const Path statePath, const string subfolder, const string & suffix, const string & stateIdentifier) { //This is a little trick: we could use the same hash as the statepath, but we change it so the repository also gets a unique scannable hash diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index af63e5194..bab7e65de 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -228,8 +228,11 @@ Path makeStorePath(const string & type, Path makeFixedOutputPath(bool recursive, string hashAlgo, Hash hash, string name); -/* Constructs a unique store state path name. */ -Path makeStatePath(const string & type, const Hash & hash, const string & suffix, const string & stateIdentifier); +/* TODO ... */ +Path makeStatePath(const string & componentHash, const string & suffix, const string & stateIdentifier); + +/* TODO ... */ +void checkStatePath(const Derivation & drv); /* Constructs a unique store state repos path name. */ Path makeStateReposPath(const string & type, const Path statePath, const string subfolder, const string & suffix, const string & stateIdentifier); diff --git a/src/libutil/util.cc b/src/libutil/util.cc index e8f12e7a3..f340cec31 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -1013,7 +1013,7 @@ string trim(const string & s) { //executes a shell command and captures and prints the output. -//TODO , check if we can integrate with runProgram +//TODO , check if we can replace!!! with runProgram like this: string a = runProgram("whoami", true, s); void executeAndPrintShellCommand(const string & command, const string & commandName) { @@ -1092,5 +1092,30 @@ bool IsDirectory(const string FileName) return ((my_stat.st_mode & S_IFDIR) != 0); } + +string getCallingUserName() +{ + //TODO Make this work on WINDOWS + /* + #include + 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 + //TODO Can and Should NOT be faked, so this is clearly unsafe ... :( + //Remove the \n + int pos = username.find("\n",0); + username.erase(pos,1); + + //return "root3"; + return username; +} } diff --git a/src/libutil/util.hh b/src/libutil/util.hh index 68e1e798a..db5922706 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -300,6 +300,7 @@ bool FileExist(const string FileName); bool IsDirectory(const string FileName); +string getCallingUserName(); } diff --git a/src/nix-state/nix-state b/src/nix-state/nix-state index 3db47ec03..fc7d0d7c2 100755 --- a/src/nix-state/nix-state +++ b/src/nix-state/nix-state @@ -18,7 +18,7 @@ sed_quote_subst='s/\([\\`\\"$\\\\]\)/\\\1/g' # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH -relink_command="(cd /root/dev/nix-state/src/nix-state; { test -z \"\${LIBRARY_PATH+set}\" || unset LIBRARY_PATH || { LIBRARY_PATH=; export LIBRARY_PATH; }; }; { test -z \"\${COMPILER_PATH+set}\" || unset COMPILER_PATH || { COMPILER_PATH=; export COMPILER_PATH; }; }; { test -z \"\${GCC_EXEC_PREFIX+set}\" || unset GCC_EXEC_PREFIX || { GCC_EXEC_PREFIX=; export GCC_EXEC_PREFIX; }; }; { test -z \"\${LD_RUN_PATH+set}\" || unset LD_RUN_PATH || { LD_RUN_PATH=; export LD_RUN_PATH; }; }; { test -z \"\${LD_LIBRARY_PATH+set}\" || unset LD_LIBRARY_PATH || { LD_LIBRARY_PATH=; export LD_LIBRARY_PATH; }; }; PATH=\"/root/bin:/nix/var/nix/profiles/per-user/root/profile/bin:/nix/var/nix/profiles/per-user/root/profile/sbin:/nix/var/nix/profiles/default/bin:/nix/var/nix/profiles/default/sbin:/var/setuid-wrappers:/var/run/current-system/sw/bin:/var/run/current-system/sw/sbin:/home/share/bin:/home/share/bin\"; export PATH; g++ -I./.. -I/root/.nix-profile/include -I/root/.nix-profile/include -I./../libutil -I./../libstore -I./../libmain -D_FILE_OFFSET_BITS=64 -g -O2 -o \$progdir/\$file nix-state.o ../libmain/.libs/libmain.so -L/tmp/nix-14177-0/build/i686-pc-linux-gnu/libstdc++-v3/src -L/tmp/nix-14177-0/build/i686-pc-linux-gnu/libstdc++-v3/src/.libs ../libstore/.libs/libstore.so /root/dev/nix-state/src/libutil/.libs/libutil.so ../libutil/.libs/libutil.so /root/dev/nix-state/src/boost/format/.libs/libformat.so ../boost/format/.libs/libformat.so /nix/store/kpqz9a4clx96538rr0zmsy3v40iqd88g-gcc-4.1.1/lib/libstdc++.so -L/root/.nix-profile/lib -ldb_cxx /nix/store/pkmzbb613wa8cwngx8jjb5jaic8yhyzs-aterm-2.4.2-fixes/lib/libATerm -lpthread -Wl,--rpath -Wl,/root/dev/nix-state/src/libmain/.libs -Wl,--rpath -Wl,/root/dev/nix-state/src/libstore/.libs -Wl,--rpath -Wl,/root/dev/nix-state/src/libutil/.libs -Wl,--rpath -Wl,/root/dev/nix-state/src/boost/format/.libs -Wl,--rpath -Wl,/nix/store/kpqz9a4clx96538rr0zmsy3v40iqd88g-gcc-4.1.1/lib -Wl,--rpath -Wl,/nix/store/pkmzbb613wa8cwngx8jjb5jaic8yhyzs-aterm-2.4.2-fixes/lib -Wl,--rpath -Wl,/nixstate/nix/lib/nix -Wl,--rpath -Wl,/nix/store/kpqz9a4clx96538rr0zmsy3v40iqd88g-gcc-4.1.1/lib -Wl,--rpath -Wl,/nix/store/pkmzbb613wa8cwngx8jjb5jaic8yhyzs-aterm-2.4.2-fixes/lib)" +relink_command="(cd /root/dev/nix-state/src/nix-state; { test -z \"\${LIBRARY_PATH+set}\" || unset LIBRARY_PATH || { LIBRARY_PATH=; export LIBRARY_PATH; }; }; { test -z \"\${COMPILER_PATH+set}\" || unset COMPILER_PATH || { COMPILER_PATH=; export COMPILER_PATH; }; }; { test -z \"\${GCC_EXEC_PREFIX+set}\" || unset GCC_EXEC_PREFIX || { GCC_EXEC_PREFIX=; export GCC_EXEC_PREFIX; }; }; { test -z \"\${LD_RUN_PATH+set}\" || unset LD_RUN_PATH || { LD_RUN_PATH=; export LD_RUN_PATH; }; }; { test -z \"\${LD_LIBRARY_PATH+set}\" || unset LD_LIBRARY_PATH || { LD_LIBRARY_PATH=; export LD_LIBRARY_PATH; }; }; PATH=\"/root/bin:/nix/var/nix/profiles/per-user/root/profile/bin:/nix/var/nix/profiles/per-user/root/profile/sbin:/nix/var/nix/profiles/default/bin:/nix/var/nix/profiles/default/sbin:/var/setuid-wrappers:/var/run/current-system/sw/bin:/var/run/current-system/sw/sbin:/home/share/bin:/home/share/bin:/home/share/bin\"; export PATH; g++ -I./.. -I/root/.nix-profile/include -I/root/.nix-profile/include -I./../libutil -I./../libstore -I./../libmain -D_FILE_OFFSET_BITS=64 -g -O2 -o \$progdir/\$file nix-state.o ../libmain/.libs/libmain.so -L/tmp/nix-14177-0/build/i686-pc-linux-gnu/libstdc++-v3/src -L/tmp/nix-14177-0/build/i686-pc-linux-gnu/libstdc++-v3/src/.libs ../libstore/.libs/libstore.so /root/dev/nix-state/src/libutil/.libs/libutil.so ../libutil/.libs/libutil.so /root/dev/nix-state/src/boost/format/.libs/libformat.so ../boost/format/.libs/libformat.so /nix/store/kpqz9a4clx96538rr0zmsy3v40iqd88g-gcc-4.1.1/lib/libstdc++.so -L/root/.nix-profile/lib -ldb_cxx /nix/store/pkmzbb613wa8cwngx8jjb5jaic8yhyzs-aterm-2.4.2-fixes/lib/libATerm -lpthread -Wl,--rpath -Wl,/root/dev/nix-state/src/libmain/.libs -Wl,--rpath -Wl,/root/dev/nix-state/src/libstore/.libs -Wl,--rpath -Wl,/root/dev/nix-state/src/libutil/.libs -Wl,--rpath -Wl,/root/dev/nix-state/src/boost/format/.libs -Wl,--rpath -Wl,/nix/store/kpqz9a4clx96538rr0zmsy3v40iqd88g-gcc-4.1.1/lib -Wl,--rpath -Wl,/nix/store/pkmzbb613wa8cwngx8jjb5jaic8yhyzs-aterm-2.4.2-fixes/lib -Wl,--rpath -Wl,/nixstate/nix/lib/nix -Wl,--rpath -Wl,/nix/store/kpqz9a4clx96538rr0zmsy3v40iqd88g-gcc-4.1.1/lib -Wl,--rpath -Wl,/nix/store/pkmzbb613wa8cwngx8jjb5jaic8yhyzs-aterm-2.4.2-fixes/lib)" # This environment variable determines our operation mode. if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then diff --git a/src/nix-state/nix-state.cc b/src/nix-state/nix-state.cc index 63fea3093..c03787e81 100644 --- a/src/nix-state/nix-state.cc +++ b/src/nix-state/nix-state.cc @@ -171,7 +171,7 @@ static void opRunComponent(Strings opFlags, Strings opArgs) for (DerivationStateOutputDirs::const_reverse_iterator i = stateOutputDirs.rbegin(); i != stateOutputDirs.rend(); ++i){ DerivationStateOutputDir d = i->second; - string thisdir = d.path; + string thisdir = d.path; //TODO CONVERT string fullstatedir = statePath + "/" + thisdir; if(thisdir == "/") //exception for the root dir @@ -259,6 +259,13 @@ void run(Strings args) store->addUpdatedStateDerivation("/nix/store/s6wggk924jx0gcb0l29ra4g9fxa3b4pp-hellohardcodedstateworld-1.0.drv", p2); // store->updateAllStateDerivations(); return; + string a = makeStatePathFromGolbalHash("8f3b56a9a985fce54fd88c3e95a81a4b6b11fb98da12b977aee7f278c73ad3d7-hellohardcodedstateworld-1.0-test2", "kaaz"); + printMsg(lvlError, format("%1%") % a); + return; + */ + printMsg(lvlError, format("Result: \"%1%\"") % getCallingUserName()); + return; + /* test */ for (Strings::iterator i = args.begin(); i != args.end(); ) { @@ -291,7 +298,7 @@ void run(Strings args) --delete state? - -- + --user=... */