Pull sources into repo.

nix-user-chroot now uses local version instead of lethalman's
This commit is contained in:
Matthew Bauer 2016-06-15 16:23:19 +00:00
parent 2ce85648d9
commit 97dd6220f8
9 changed files with 285 additions and 43 deletions

View File

@ -1 +1,31 @@
import ./nix-bootstrap.nix
{nixpkgs ? import <nixpkgs> {}}:
with nixpkgs;
let
makeself = callPackage ./makeself.nix {};
makedir = callPackage ./makedir.nix {};
makebootstrap = callPackage ./makebootstrap.nix {
inherit makedir makeself;
};
nix-user-chroot = callPackage ./nix-user-chroot.nix {};
nix-bootstrap = callPackage ./nix-bootstrap.nix {
inherit nix-user-chroot;
};
in {
versionTest = makebootstrap {
name = "nix-bootstrap.sh";
target = nix-bootstrap {
name = "nix-bootstrap";
stage3 = "nix-env --version";
};
run = "/stage1.sh";
};
}

View File

@ -1,22 +0,0 @@
{ stdenv, fetchFromGitHub, nix, cacert }:
stdenv.mkDerivation {
name = "nix-bootstrap";
src = fetchFromGitHub {
owner = "matthewbauer";
repo = "nix-bootstrap";
rev = "cc882b2cb92d8de87dad9cb890ad1745b06a9787";
sha256 = "05w6xjg0cgz6a4szc7jd7v53bmy4zjrgph5xkgyj73g62jyq7ajf";
};
propagatedBuildInputs = [ nix cacert ];
installPhase = ''
mkdir -p $out/
substitute install-nix-from-closure.sh $out/install \
--subst-var-by nix .${nix} \
--subst-var-by cacert .${cacert}
chmod +x $out/install
'';
}

View File

@ -1,13 +1,4 @@
{nixpkgs ? import <nixpkgs> {}}:
with nixpkgs;
let
makeself = callPackage ./makeself.nix {};
makedir = callPackage ./makedir.nix {};
in
{makeself, makedir}:
{ name, target, run }:
makeself {

View File

@ -11,7 +11,7 @@
storePaths=$(${perl}/bin/perl ${pathsFromGraph} ./closure)
printRegistration=1 ${perl}/bin/perl ${pathsFromGraph} ./closure > $out/.reginfo
for path in $storePaths; do
cp --parents -r $path $out/
cp --parents -rp $path $out/
done
'';
}

View File

@ -1,14 +1,43 @@
{nixpkgs ? import <nixpkgs> {}}:
{ stdenv, writeText, nix-user-chroot, nix, cacert, coreutils, bash }:
with nixpkgs;
{ name, stage3 }:
let
stage1 = writeText "stage1.sh" ''
./${nix-user-chroot}/bin/nix-user-chroot ./nix ./${bash}/bin/sh -c $(dirname $0)/stage2.sh
'';
makebootstrap = callPackage ./makebootstrap.nix {};
install-nix-from-closure = callPackage ./install-nix-from-closure.nix {};
stage2 = writeText "stage2.sh" ''
unset NIX_REMOTE NIX_PROFILES NIX_USER_PROFILE_DIR NIX_OTHER_STORES NIX_PATH
export NIX_CONF_DIR=/nix/etc/nix/
export NIX_PROFILE=/nix/var/nix/profiles/default
export SSL_CERT_FILE="${cacert}/etc/ssl/certs/ca-bundle.crt"
export PATH="${coreutils}/bin:${bash}/bin:${nix.out}/bin"
in makebootstrap {
name = "nix-bootstrap.sh";
target = install-nix-from-closure;
run = "/install";
}
chmod -R a-w /nix/
chmod u+w /nix/ /nix/store/
mkdir -p /nix/etc/nix/ /nix/var/nix/profiles $HOME /bin/
ln -s ${bash}/bin/sh /bin/sh
nix-store --init
nix-store --load-db < ./.reginfo
. ${nix.out}/etc/profile.d/nix.sh
nix-channel --add https://nixos.org/channels/nixpkgs-unstable
nix-channel --update nixpkgs
nix-shell --pure -p ${nix.out} --run "${stage3}"
'';
in
stdenv.mkDerivation {
inherit name;
buildInputs = [ nix-user-chroot nix cacert ];
buildCommand = ''
mkdir -p $out
install -m 755 ${stage1} $out/stage1.sh
install -m 755 ${stage2} $out/stage2.sh
'';
}

21
nix-installer.nix Normal file
View File

@ -0,0 +1,21 @@
{ stdenv, fetchFromGitHub, writeText, nix, cacert }:
let
run-from-closure = writeText "run-from-closure" (builtins.readFile ./run-from-closure.sh);
in
stdenv.mkDerivation {
name = "nix-bootstrap";
propagatedBuildInputs = [ nix cacert ];
buildCommand = ''
mkdir -p $out/bin/
substitute ${run-from-closure} $out/bin/run-from-closure \
--subst-var-by nix ${nix.out} \
--subst-var-by cacert ${cacert}
chmod +x $out/bin/run-from-closure
'';
}

144
nix-user-chroot.c Normal file
View File

@ -0,0 +1,144 @@
#define _GNU_SOURCE
#include <sched.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <signal.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#include <sys/mount.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#define err_exit(format, ...) { fprintf(stderr, format ": %s\n", ##__VA_ARGS__, strerror(errno)); exit(EXIT_FAILURE); }
static void usage(char *pname) {
fprintf(stderr, "Usage: %s <nixpath> <command>\n", pname);
exit(EXIT_FAILURE);
}
static void update_map(char *mapping, char *map_file) {
int fd;
fd = open(map_file, O_WRONLY);
if (fd < 0) {
err_exit("map open");
}
int map_len = strlen(mapping);
if (write(fd, mapping, map_len) != map_len) {
err_exit("map write");
}
close(fd);
}
static void add_path(const char* name, const char* rootdir) {
char path_buf[PATH_MAX];
char path_buf2[PATH_MAX];
snprintf(path_buf, sizeof(path_buf), "/%s", name);
struct stat statbuf;
if (stat(path_buf, &statbuf) < 0) {
fprintf(stderr, "Cannot stat %s: %s\n", path_buf, strerror(errno));
return;
}
snprintf(path_buf2, sizeof(path_buf2), "%s/%s", rootdir, name);
if (S_ISDIR(statbuf.st_mode)) {
mkdir(path_buf2, statbuf.st_mode & ~S_IFMT);
if (mount(path_buf, path_buf2, "none", MS_BIND | MS_REC, NULL) < 0) {
fprintf(stderr, "Cannot bind mount %s to %s: %s\n", path_buf, path_buf2, strerror(errno));
}
}
}
int main(int argc, char *argv[]) {
if (argc < 3) {
usage(argv[0]);
}
char template[] = "/tmp/nixXXXXXX";
char *rootdir = mkdtemp(template);
if (!rootdir) {
err_exit("mkdtemp(%s)", template);
}
char *nixdir = realpath(argv[1], NULL);
if (!nixdir) {
err_exit("realpath(%s)", argv[1]);
}
uid_t uid = getuid();
gid_t gid = getgid();
if (unshare(CLONE_NEWNS | CLONE_NEWUSER) < 0) {
err_exit("unshare()");
}
// bind mount all / stuff into rootdir
DIR* d = opendir("/");
if (!d) {
err_exit("open /");
}
add_path("dev", rootdir);
add_path("proc", rootdir);
add_path("sys", rootdir);
add_path("run", rootdir);
add_path("tmp", rootdir);
add_path("var", rootdir);
struct stat statbuf2;
if (stat(nixdir, &statbuf2) < 0) {
err_exit("stat(%s)", nixdir);
}
char path_buf[PATH_MAX];
snprintf(path_buf, sizeof(path_buf), "%s/nix", rootdir);
mkdir(path_buf, statbuf2.st_mode & ~S_IFMT);
if (mount(nixdir, path_buf, "none", MS_BIND | MS_REC, NULL) < 0) {
err_exit("mount(%s, %s)", nixdir, path_buf);
}
// fixes issue #1 where writing to /proc/self/gid_map fails
// see user_namespaces(7) for more documentation
int fd_setgroups = open("/proc/self/setgroups", O_WRONLY);
if (fd_setgroups > 0) {
write(fd_setgroups, "deny", 4);
}
char map_buf[1024];
// map the original uid/gid in the new ns
snprintf(map_buf, sizeof(map_buf), "%d %d 1", uid, uid);
update_map(map_buf, "/proc/self/uid_map");
snprintf(map_buf, sizeof(map_buf), "%d %d 1", gid, gid);
update_map(map_buf, "/proc/self/gid_map");
char cwd[PATH_MAX];
if (!getcwd(cwd, PATH_MAX)) {
err_exit("getcwd()");
}
chdir("/");
if (chroot(rootdir) < 0) {
err_exit("chroot(%s)", rootdir);
}
chdir(cwd);
// execute the command
execvp(argv[2], argv+2);
err_exit("execvp(%s)", argv[2]);
}

10
nix-user-chroot.nix Normal file
View File

@ -0,0 +1,10 @@
{ stdenv, fetchFromGitHub }:
stdenv.mkDerivation {
name = "nix-user-chroot";
buildCommand = ''
cp ${./nix-user-chroot.c} nix-user-chroot.c
mkdir -p $out/bin/
cc nix-user-chroot.c -o $out/bin/nix-user-chroot
'';
}

39
run-from-closure.sh Normal file
View File

@ -0,0 +1,39 @@
#!/bin/sh
set -e
self="."
nix="@nix@"
cacert="@cacert@"
if ! [ -e $self/.reginfo ]; then
echo "$0: incomplete installer (.reginfo is missing)" >&2
exit 1
fi
echo "initialising Nix database..." >&2
if ! $nix/bin/nix-store --init; then
echo "$0: failed to initialize the Nix database" >&2
exit 1
fi
if ! $nix/bin/nix-store --load-db < $self/.reginfo; then
echo "$0: unable to register valid paths" >&2
exit 1
fi
. $nix/etc/profile.d/nix.sh
if ! $nix/bin/nix-env -i "$nix"; then
echo "$0: unable to install Nix into your default profile" >&2
exit 1
fi
# Install an SSL certificate bundle.
if [ -z "$SSL_CERT_FILE" -o ! -f "$SSL_CERT_FILE" ]; then
$nix/bin/nix-env -i "$cacert"
export SSL_CERT_FILE="$HOME/.nix-profile/etc/ssl/certs/ca-bundle.crt"
fi
$nix/bin/nix-channel --add https://nixos.org/channels/nixpkgs-unstable
$nix/bin/nix-channel --update nixpkgs