on master help sign in
Pull sources into repo.

nix-user-chroot now uses local version instead of lethalman's

commit97dd6220f8cdbc1df6a69d2a63f013bad6b24ce8 authorMatthew Bauer <mjbauer95@gmai.com> dateWed 15 Jun 2016, 16:23 (10 years ago) parent2ce8564
9 files changed+285−43
default.nix+31−1 install-nix-from-closure.nix−22 makebootstrap.nix+1−10 makedir.nix+1−1 nix-bootstrap.nix+38−9 nix-installer.nix+21 nix-user-chroot.c+144 nix-user-chroot.nix+10 run-from-closure.sh+39
default.nix+31−1
@@ -1 +1,31 @@
1−import ./nix-bootstrap.nix
1+{nixpkgs ? import <nixpkgs> {}}:
2+
3+with nixpkgs;
4+
5+let
6+
7+ makeself = callPackage ./makeself.nix {};
8+ makedir = callPackage ./makedir.nix {};
9+
10+ makebootstrap = callPackage ./makebootstrap.nix {
11+ inherit makedir makeself;
12+ };
13+
14+ nix-user-chroot = callPackage ./nix-user-chroot.nix {};
15+
16+ nix-bootstrap = callPackage ./nix-bootstrap.nix {
17+ inherit nix-user-chroot;
18+ };
19+
20+in {
21+
22+ versionTest = makebootstrap {
23+ name = "nix-bootstrap.sh";
24+ target = nix-bootstrap {
25+ name = "nix-bootstrap";
26+ stage3 = "nix-env --version";
27+ };
28+ run = "/stage1.sh";
29+ };
30+
31+}
install-nix-from-closure.nixdeleted−22
@@ -1,22 +0,0 @@
1−{ stdenv, fetchFromGitHub, nix, cacert }:
2−
3− stdenv.mkDerivation {
4− name = "nix-bootstrap";
5−
6− src = fetchFromGitHub {
7− owner = "matthewbauer";
8− repo = "nix-bootstrap";
9− rev = "cc882b2cb92d8de87dad9cb890ad1745b06a9787";
10− sha256 = "05w6xjg0cgz6a4szc7jd7v53bmy4zjrgph5xkgyj73g62jyq7ajf";
11− };
12−
13− propagatedBuildInputs = [ nix cacert ];
14−
15− installPhase = ''
16− mkdir -p $out/
17− substitute install-nix-from-closure.sh $out/install \
18− --subst-var-by nix .${nix} \
19− --subst-var-by cacert .${cacert}
20− chmod +x $out/install
21− '';
22− }
makebootstrap.nix+1−10
@@ -1,13 +1,4 @@
1−{nixpkgs ? import <nixpkgs> {}}:
2−
3−with nixpkgs;
4−
5−let
6−
7− makeself = callPackage ./makeself.nix {};
8− makedir = callPackage ./makedir.nix {};
9−
10−in
1+{makeself, makedir}:
112
123 { name, target, run }:
134 makeself {
makedir.nix+1−1
@@ -11,7 +11,7 @@
1111 storePaths=$(${perl}/bin/perl ${pathsFromGraph} ./closure)
1212 printRegistration=1 ${perl}/bin/perl ${pathsFromGraph} ./closure > $out/.reginfo
1313 for path in $storePaths; do
14− cp --parents -r $path $out/
14+ cp --parents -rp $path $out/
1515 done
1616 '';
1717 }
nix-bootstrap.nix+38−9
@@ -1,14 +1,43 @@
1−{nixpkgs ? import <nixpkgs> {}}:
1+{ stdenv, writeText, nix-user-chroot, nix, cacert, coreutils, bash }:
22
3−with nixpkgs;
3+{ name, stage3 }:
44
55let
6+ stage1 = writeText "stage1.sh" ''
7+ ./${nix-user-chroot}/bin/nix-user-chroot ./nix ./${bash}/bin/sh -c $(dirname $0)/stage2.sh
8+ '';
69
7− makebootstrap = callPackage ./makebootstrap.nix {};
8− install-nix-from-closure = callPackage ./install-nix-from-closure.nix {};
10+ stage2 = writeText "stage2.sh" ''
11+ unset NIX_REMOTE NIX_PROFILES NIX_USER_PROFILE_DIR NIX_OTHER_STORES NIX_PATH
12+ export NIX_CONF_DIR=/nix/etc/nix/
13+ export NIX_PROFILE=/nix/var/nix/profiles/default
14+ export SSL_CERT_FILE="${cacert}/etc/ssl/certs/ca-bundle.crt"
15+ export PATH="${coreutils}/bin:${bash}/bin:${nix.out}/bin"
916
10−in makebootstrap {
11− name = "nix-bootstrap.sh";
12− target = install-nix-from-closure;
13− run = "/install";
14−}
17+ chmod -R a-w /nix/
18+ chmod u+w /nix/ /nix/store/
19+ mkdir -p /nix/etc/nix/ /nix/var/nix/profiles $HOME /bin/
20+ ln -s ${bash}/bin/sh /bin/sh
21+
22+ nix-store --init
23+ nix-store --load-db < ./.reginfo
24+
25+ . ${nix.out}/etc/profile.d/nix.sh
26+
27+ nix-channel --add https://nixos.org/channels/nixpkgs-unstable
28+ nix-channel --update nixpkgs
29+
30+ nix-shell --pure -p ${nix.out} --run "${stage3}"
31+ '';
32+
33+in
34+
35+ stdenv.mkDerivation {
36+ inherit name;
37+ buildInputs = [ nix-user-chroot nix cacert ];
38+ buildCommand = ''
39+ mkdir -p $out
40+ install -m 755 ${stage1} $out/stage1.sh
41+ install -m 755 ${stage2} $out/stage2.sh
42+ '';
43+ }
nix-installer.nixnew file+21
@@ -0,0 +1,21 @@
1+{ stdenv, fetchFromGitHub, writeText, nix, cacert }:
2+
3+let
4+
5+ run-from-closure = writeText "run-from-closure" (builtins.readFile ./run-from-closure.sh);
6+
7+in
8+
9+ stdenv.mkDerivation {
10+ name = "nix-bootstrap";
11+
12+ propagatedBuildInputs = [ nix cacert ];
13+
14+ buildCommand = ''
15+ mkdir -p $out/bin/
16+ substitute ${run-from-closure} $out/bin/run-from-closure \
17+ --subst-var-by nix ${nix.out} \
18+ --subst-var-by cacert ${cacert}
19+ chmod +x $out/bin/run-from-closure
20+ '';
21+ }
nix-user-chroot.cnew file+144
@@ -0,0 +1,144 @@
1+#define _GNU_SOURCE
2+#include <sched.h>
3+#include <unistd.h>
4+#include <stdlib.h>
5+#include <sys/wait.h>
6+#include <signal.h>
7+#include <fcntl.h>
8+#include <stdio.h>
9+#include <string.h>
10+#include <limits.h>
11+#include <errno.h>
12+#include <sys/mount.h>
13+#include <sys/types.h>
14+#include <dirent.h>
15+#include <sys/stat.h>
16+
17+#define err_exit(format, ...) { fprintf(stderr, format ": %s\n", ##__VA_ARGS__, strerror(errno)); exit(EXIT_FAILURE); }
18+
19+static void usage(char *pname) {
20+ fprintf(stderr, "Usage: %s <nixpath> <command>\n", pname);
21+
22+ exit(EXIT_FAILURE);
23+}
24+
25+static void update_map(char *mapping, char *map_file) {
26+ int fd;
27+
28+ fd = open(map_file, O_WRONLY);
29+ if (fd < 0) {
30+ err_exit("map open");
31+ }
32+
33+ int map_len = strlen(mapping);
34+ if (write(fd, mapping, map_len) != map_len) {
35+ err_exit("map write");
36+ }
37+
38+ close(fd);
39+}
40+
41+static void add_path(const char* name, const char* rootdir) {
42+ char path_buf[PATH_MAX];
43+ char path_buf2[PATH_MAX];
44+
45+ snprintf(path_buf, sizeof(path_buf), "/%s", name);
46+
47+ struct stat statbuf;
48+ if (stat(path_buf, &statbuf) < 0) {
49+ fprintf(stderr, "Cannot stat %s: %s\n", path_buf, strerror(errno));
50+ return;
51+ }
52+
53+ snprintf(path_buf2, sizeof(path_buf2), "%s/%s", rootdir, name);
54+
55+ if (S_ISDIR(statbuf.st_mode)) {
56+ mkdir(path_buf2, statbuf.st_mode & ~S_IFMT);
57+ if (mount(path_buf, path_buf2, "none", MS_BIND | MS_REC, NULL) < 0) {
58+ fprintf(stderr, "Cannot bind mount %s to %s: %s\n", path_buf, path_buf2, strerror(errno));
59+ }
60+ }
61+}
62+
63+int main(int argc, char *argv[]) {
64+ if (argc < 3) {
65+ usage(argv[0]);
66+ }
67+
68+ char template[] = "/tmp/nixXXXXXX";
69+ char *rootdir = mkdtemp(template);
70+ if (!rootdir) {
71+ err_exit("mkdtemp(%s)", template);
72+ }
73+
74+ char *nixdir = realpath(argv[1], NULL);
75+ if (!nixdir) {
76+ err_exit("realpath(%s)", argv[1]);
77+ }
78+
79+ uid_t uid = getuid();
80+ gid_t gid = getgid();
81+
82+ if (unshare(CLONE_NEWNS | CLONE_NEWUSER) < 0) {
83+ err_exit("unshare()");
84+ }
85+
86+ // bind mount all / stuff into rootdir
87+ DIR* d = opendir("/");
88+ if (!d) {
89+ err_exit("open /");
90+ }
91+
92+ add_path("dev", rootdir);
93+ add_path("proc", rootdir);
94+ add_path("sys", rootdir);
95+ add_path("run", rootdir);
96+ add_path("tmp", rootdir);
97+ add_path("var", rootdir);
98+
99+ struct stat statbuf2;
100+ if (stat(nixdir, &statbuf2) < 0) {
101+ err_exit("stat(%s)", nixdir);
102+ }
103+
104+ char path_buf[PATH_MAX];
105+
106+ snprintf(path_buf, sizeof(path_buf), "%s/nix", rootdir);
107+ mkdir(path_buf, statbuf2.st_mode & ~S_IFMT);
108+ if (mount(nixdir, path_buf, "none", MS_BIND | MS_REC, NULL) < 0) {
109+ err_exit("mount(%s, %s)", nixdir, path_buf);
110+ }
111+
112+ // fixes issue #1 where writing to /proc/self/gid_map fails
113+ // see user_namespaces(7) for more documentation
114+ int fd_setgroups = open("/proc/self/setgroups", O_WRONLY);
115+ if (fd_setgroups > 0) {
116+ write(fd_setgroups, "deny", 4);
117+ }
118+
119+ char map_buf[1024];
120+
121+ // map the original uid/gid in the new ns
122+ snprintf(map_buf, sizeof(map_buf), "%d %d 1", uid, uid);
123+ update_map(map_buf, "/proc/self/uid_map");
124+
125+ snprintf(map_buf, sizeof(map_buf), "%d %d 1", gid, gid);
126+ update_map(map_buf, "/proc/self/gid_map");
127+
128+ char cwd[PATH_MAX];
129+
130+ if (!getcwd(cwd, PATH_MAX)) {
131+ err_exit("getcwd()");
132+ }
133+
134+ chdir("/");
135+ if (chroot(rootdir) < 0) {
136+ err_exit("chroot(%s)", rootdir);
137+ }
138+ chdir(cwd);
139+
140+ // execute the command
141+
142+ execvp(argv[2], argv+2);
143+ err_exit("execvp(%s)", argv[2]);
144+}
nix-user-chroot.nixnew file+10
@@ -0,0 +1,10 @@
1+{ stdenv, fetchFromGitHub }:
2+
3+ stdenv.mkDerivation {
4+ name = "nix-user-chroot";
5+ buildCommand = ''
6+ cp ${./nix-user-chroot.c} nix-user-chroot.c
7+ mkdir -p $out/bin/
8+ cc nix-user-chroot.c -o $out/bin/nix-user-chroot
9+ '';
10+ }
run-from-closure.shnew file+39
@@ -0,0 +1,39 @@
1+#!/bin/sh
2+
3+set -e
4+
5+self="."
6+nix="@nix@"
7+cacert="@cacert@"
8+
9+if ! [ -e $self/.reginfo ]; then
10+ echo "$0: incomplete installer (.reginfo is missing)" >&2
11+ exit 1
12+fi
13+
14+echo "initialising Nix database..." >&2
15+if ! $nix/bin/nix-store --init; then
16+ echo "$0: failed to initialize the Nix database" >&2
17+ exit 1
18+fi
19+
20+if ! $nix/bin/nix-store --load-db < $self/.reginfo; then
21+ echo "$0: unable to register valid paths" >&2
22+ exit 1
23+fi
24+
25+. $nix/etc/profile.d/nix.sh
26+
27+if ! $nix/bin/nix-env -i "$nix"; then
28+ echo "$0: unable to install Nix into your default profile" >&2
29+ exit 1
30+fi
31+
32+# Install an SSL certificate bundle.
33+if [ -z "$SSL_CERT_FILE" -o ! -f "$SSL_CERT_FILE" ]; then
34+ $nix/bin/nix-env -i "$cacert"
35+ export SSL_CERT_FILE="$HOME/.nix-profile/etc/ssl/certs/ca-bundle.crt"
36+fi
37+
38+$nix/bin/nix-channel --add https://nixos.org/channels/nixpkgs-unstable
39+$nix/bin/nix-channel --update nixpkgs