Move the default profiles to the user’s home
Rather than using `/nix/var/nix/{profiles,gcroots}/per-user/`, put the user profiles and gcroots under `$XDG_DATA_DIR/nix/{profiles,gcroots}`. This means that the daemon no longer needs to manage these paths itself (they are fully handled client-side). In particular, it doesn’t have to `chown` them anymore (removing one need for root). This does change the layout of the gc-roots created by nix-env, and is likely to break some stuff, so I’m not sure how to properly handle that.
This commit is contained in:
parent
deb35c84b3
commit
a5919f4754
|
@ -1517,7 +1517,7 @@ void LocalDerivationGoal::startDaemon()
|
||||||
try {
|
try {
|
||||||
daemon::processConnection(store, from, to,
|
daemon::processConnection(store, from, to,
|
||||||
daemon::NotTrusted, daemon::Recursive,
|
daemon::NotTrusted, daemon::Recursive,
|
||||||
[&](Store & store) { store.createUser("nobody", 65535); });
|
[&](Store & store) {});
|
||||||
debug("terminated daemon connection");
|
debug("terminated daemon connection");
|
||||||
} catch (SysError &) {
|
} catch (SysError &) {
|
||||||
ignoreException();
|
ignoreException();
|
||||||
|
|
|
@ -201,8 +201,6 @@ LocalStore::LocalStore(const Params & params)
|
||||||
throw SysError("could not set permissions on '%s' to 755", perUserDir);
|
throw SysError("could not set permissions on '%s' to 755", perUserDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
createUser(getUserName(), getuid());
|
|
||||||
|
|
||||||
/* Optionally, create directories and set permissions for a
|
/* Optionally, create directories and set permissions for a
|
||||||
multi-user install. */
|
multi-user install. */
|
||||||
if (getuid() == 0 && settings.buildUsersGroup != "") {
|
if (getuid() == 0 && settings.buildUsersGroup != "") {
|
||||||
|
@ -1824,20 +1822,6 @@ void LocalStore::signPathInfo(ValidPathInfo & info)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void LocalStore::createUser(const std::string & userName, uid_t userId)
|
|
||||||
{
|
|
||||||
for (auto & dir : {
|
|
||||||
fmt("%s/profiles/per-user/%s", stateDir, userName),
|
|
||||||
fmt("%s/gcroots/per-user/%s", stateDir, userName)
|
|
||||||
}) {
|
|
||||||
createDirs(dir);
|
|
||||||
if (chmod(dir.c_str(), 0755) == -1)
|
|
||||||
throw SysError("changing permissions of directory '%s'", dir);
|
|
||||||
if (chown(dir.c_str(), userId, getgid()) == -1)
|
|
||||||
throw SysError("changing owner of directory '%s'", dir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<std::pair<int64_t, Realisation>> LocalStore::queryRealisationCore_(
|
std::optional<std::pair<int64_t, Realisation>> LocalStore::queryRealisationCore_(
|
||||||
LocalStore::State & state,
|
LocalStore::State & state,
|
||||||
const DrvOutput & id)
|
const DrvOutput & id)
|
||||||
|
|
|
@ -281,8 +281,6 @@ private:
|
||||||
void signPathInfo(ValidPathInfo & info);
|
void signPathInfo(ValidPathInfo & info);
|
||||||
void signRealisation(Realisation &);
|
void signRealisation(Realisation &);
|
||||||
|
|
||||||
void createUser(const std::string & userName, uid_t userId) override;
|
|
||||||
|
|
||||||
// XXX: Make a generic `Store` method
|
// XXX: Make a generic `Store` method
|
||||||
FixedOutputHash hashCAPath(
|
FixedOutputHash hashCAPath(
|
||||||
const FileIngestionMethod & method,
|
const FileIngestionMethod & method,
|
||||||
|
|
|
@ -280,16 +280,30 @@ std::string optimisticLockProfile(const Path & profile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Path profilesDir()
|
||||||
|
{
|
||||||
|
auto profileRoot = getDataDir() + "/nix/profiles";
|
||||||
|
createDirs(profileRoot);
|
||||||
|
return profileRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Path getDefaultProfile()
|
Path getDefaultProfile()
|
||||||
{
|
{
|
||||||
Path profileLink = getHome() + "/.nix-profile";
|
Path profileLink = getHome() + "/.nix-profile";
|
||||||
try {
|
try {
|
||||||
if (!pathExists(profileLink)) {
|
// Migrate from the “old-style” profiles stored under `/nix/var`:
|
||||||
replaceSymlink(
|
// If the link exists and points to the old location, rewrite it to the
|
||||||
getuid() == 0
|
// new one (otherwise keep-it as-it-is as it might have been
|
||||||
|
// intentionnally changed, in which case we shouldn’t touch it)
|
||||||
|
auto legacyProfile = getuid() == 0
|
||||||
? settings.nixStateDir + "/profiles/default"
|
? settings.nixStateDir + "/profiles/default"
|
||||||
: fmt("%s/profiles/per-user/%s/profile", settings.nixStateDir, getUserName()),
|
: fmt("%s/profiles/per-user/%s/profile", settings.nixStateDir, getUserName());
|
||||||
profileLink);
|
if (!pathExists(profileLink) ||
|
||||||
|
(isLink(profileLink) &&
|
||||||
|
readLink(profileLink) == legacyProfile)
|
||||||
|
) {
|
||||||
|
replaceSymlink(profilesDir() + "/profile", profileLink);
|
||||||
}
|
}
|
||||||
return absPath(readLink(profileLink), dirOf(profileLink));
|
return absPath(readLink(profileLink), dirOf(profileLink));
|
||||||
} catch (Error &) {
|
} catch (Error &) {
|
||||||
|
|
|
@ -68,6 +68,10 @@ void lockProfile(PathLocks & lock, const Path & profile);
|
||||||
rebuilt. */
|
rebuilt. */
|
||||||
std::string optimisticLockProfile(const Path & profile);
|
std::string optimisticLockProfile(const Path & profile);
|
||||||
|
|
||||||
|
/* Creates and returns the path to a directory suitable for storing the user’s
|
||||||
|
profiles. */
|
||||||
|
Path profilesDir();
|
||||||
|
|
||||||
/* Resolve ~/.nix-profile. If ~/.nix-profile doesn't exist yet, create
|
/* Resolve ~/.nix-profile. If ~/.nix-profile doesn't exist yet, create
|
||||||
it. */
|
it. */
|
||||||
Path getDefaultProfile();
|
Path getDefaultProfile();
|
||||||
|
|
|
@ -657,9 +657,6 @@ public:
|
||||||
return toRealPath(printStorePath(storePath));
|
return toRealPath(printStorePath(storePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void createUser(const std::string & userName, uid_t userId)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Synchronises the options of the client with those of the daemon
|
* Synchronises the options of the client with those of the daemon
|
||||||
* (a no-op when there’s no daemon)
|
* (a no-op when there’s no daemon)
|
||||||
|
|
|
@ -537,6 +537,16 @@ std::string getUserName()
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Path getHomeOf(uid_t userId)
|
||||||
|
{
|
||||||
|
std::vector<char> buf(16384);
|
||||||
|
struct passwd pwbuf;
|
||||||
|
struct passwd * pw;
|
||||||
|
if (getpwuid_r(userId, &pwbuf, buf.data(), buf.size(), &pw) != 0
|
||||||
|
|| !pw || !pw->pw_dir || !pw->pw_dir[0])
|
||||||
|
throw Error("cannot determine user's home directory");
|
||||||
|
return pw->pw_dir;
|
||||||
|
}
|
||||||
|
|
||||||
Path getHome()
|
Path getHome()
|
||||||
{
|
{
|
||||||
|
@ -558,13 +568,7 @@ Path getHome()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!homeDir) {
|
if (!homeDir) {
|
||||||
std::vector<char> buf(16384);
|
homeDir = getHomeOf(geteuid());
|
||||||
struct passwd pwbuf;
|
|
||||||
struct passwd * pw;
|
|
||||||
if (getpwuid_r(geteuid(), &pwbuf, buf.data(), buf.size(), &pw) != 0
|
|
||||||
|| !pw || !pw->pw_dir || !pw->pw_dir[0])
|
|
||||||
throw Error("cannot determine user's home directory");
|
|
||||||
homeDir = pw->pw_dir;
|
|
||||||
if (unownedUserHomeDir.has_value() && unownedUserHomeDir != homeDir) {
|
if (unownedUserHomeDir.has_value() && unownedUserHomeDir != homeDir) {
|
||||||
warn("$HOME ('%s') is not owned by you, falling back to the one defined in the 'passwd' file ('%s')", *unownedUserHomeDir, *homeDir);
|
warn("$HOME ('%s') is not owned by you, falling back to the one defined in the 'passwd' file ('%s')", *unownedUserHomeDir, *homeDir);
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,6 +137,9 @@ void deletePath(const Path & path, uint64_t & bytesFreed);
|
||||||
|
|
||||||
std::string getUserName();
|
std::string getUserName();
|
||||||
|
|
||||||
|
/* Return the given user's home directory from /etc/passwd. */
|
||||||
|
Path getHomeOf(uid_t userId);
|
||||||
|
|
||||||
/* Return $HOME or the user's home directory from /etc/passwd. */
|
/* Return $HOME or the user's home directory from /etc/passwd. */
|
||||||
Path getHome();
|
Path getHome();
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
|
#include "profiles.hh"
|
||||||
#include "shared.hh"
|
#include "shared.hh"
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
#include "filetransfer.hh"
|
#include "filetransfer.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
#include "legacy.hh"
|
#include "legacy.hh"
|
||||||
#include "fetchers.hh"
|
#include "fetchers.hh"
|
||||||
|
#include "util.hh"
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
@ -166,7 +168,7 @@ static int main_nix_channel(int argc, char ** argv)
|
||||||
nixDefExpr = home + "/.nix-defexpr";
|
nixDefExpr = home + "/.nix-defexpr";
|
||||||
|
|
||||||
// Figure out the name of the channels profile.
|
// Figure out the name of the channels profile.
|
||||||
profile = fmt("%s/profiles/per-user/%s/channels", settings.nixStateDir, getUserName());
|
profile = profilesDir() + "/channels";
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
cNone,
|
cNone,
|
||||||
|
|
|
@ -248,7 +248,6 @@ static void daemonLoop()
|
||||||
querySetting("build-users-group", "") == "")
|
querySetting("build-users-group", "") == "")
|
||||||
throw Error("if you run 'nix-daemon' as root, then you MUST set 'build-users-group'!");
|
throw Error("if you run 'nix-daemon' as root, then you MUST set 'build-users-group'!");
|
||||||
#endif
|
#endif
|
||||||
store.createUser(user, peer.uid);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|
|
@ -30,7 +30,3 @@ NIX_REMOTE= nix-store --dump-db > $TEST_ROOT/d2
|
||||||
cmp $TEST_ROOT/d1 $TEST_ROOT/d2
|
cmp $TEST_ROOT/d1 $TEST_ROOT/d2
|
||||||
|
|
||||||
killDaemon
|
killDaemon
|
||||||
|
|
||||||
user=$(whoami)
|
|
||||||
[ -e $NIX_STATE_DIR/gcroots/per-user/$user ]
|
|
||||||
[ -e $NIX_STATE_DIR/profiles/per-user/$user ]
|
|
||||||
|
|
Loading…
Reference in a new issue