summary refs log tree commit diff
path: root/pkgs/build-support/build-fhs-chrootenv/default.nix
blob: 411e73ab8102f7adb6186e3c03c0a51ad2e81ab4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
{ buildEnv, nixpkgs, nixpkgs_i686, system
, stdenv, glibc, glibc_multi, glibcLocales
, bashInteractive, coreutils, less, shadow su
, gawk, gcc, diffutils, findutils, gnused, gnugrep
, gnutar, gzip, bzip2, xz
} :
{ name, pkgs ? [], profile ? ""
, targetPkgs ? null, multiPkgs ? null
, extraBuildCommands ? "", extraBuildCommandsMulti ? ""
}:

assert pkgs       != []   -> targetPkgs == null && multiPkgs == null;
assert targetPkgs != null -> multiPkgs  != null;
assert multiPkgs  != null -> targetPkgs != null;
assert targetPkgs != null -> pkgs       == [];

let
  is64Bit       = system == "x86_64-linux";
  # enable multi builds on x86_64 hosts if pakgs_target/multi are defined
  isMultiBuild  = is64Bit && targetPkgs != null;
  isNormalBuild = !isMultiBuild;

  # list of packages (usually programs) which will only be installed for the
  # hosts architecture
  targetPaths = if targetPkgs == null
                  then pkgs
                  else targetPkgs nixpkgs ++ multiPkgs nixpkgs;

  # list of pckages which should be build for both x86 and x86_64 on x86_64
  # systems
  multiPaths = if isMultiBuild
                  then multiPkgs nixpkgs_i686
                  else [];

  # base packages of the chroot
  # these match the hosts architecture, glibc_multi will be choosen
  # on multi builds
  basePkgs =
    [ (if isMultiBuild then glibc_multi else glibc)
      bashInteractive coreutils less shadow su
      gawk gcc diffutils findutils gnused gnugrep
      gnutar gzip bzip2 xz
    ];

  # Compose a global profile for the chroot environment
  profilePkg = nixpkgs.stdenv.mkDerivation {
    name         = "${name}-chrootenv-profile";
    buildCommand = ''
      mkdir -p $out/etc
      cat >> $out/etc/profile << "EOF"
      export PS1='${name}-chrootenv:\u@\h:\w\$ '
      ${profile}
      EOF
    '';
  };

  # Composes a /usr like directory structure
  staticUsrProfileTarget = buildEnv {
    name = "system-profile-target";
    paths = basePkgs ++ [ profilePkg ] ++ targetPaths;
  };

  staticUsrProfileMulti = buildEnv {
    name = "system-profile-multi";
    paths = multiPaths;
  };

  # References to shell scripts that set up or tear down the environment
  initSh    = ./init.sh.in;
  mountSh   = ./mount.sh.in;
  loadSh    = ./load.sh.in;
  umountSh  = ./umount.sh.in;
  destroySh = ./destroy.sh.in;

  linkProfile = profile: ''
    for i in ${profile}/{etc,bin,lib{,32,64},sbin,share,var}; do
        if [ -x "$i" ]
        then
            ln -s "$i"
        fi
    done
  '';

  # the target profile is the actual profile that will be used for the chroot
  setupTargetProfile = ''
    ${linkProfile staticUsrProfileTarget}
    mkdir -m0755 usr
    cd usr
    ${linkProfile staticUsrProfileTarget}
    cd ..
  '';

  # this will happen on x86_64 host:
  # /x86         -> links to the whole profile defined by multiPaths
  # /lib, /lib32 -> links to 32bit binaries
  # /lib64       -> links to 64bit binaries
  # /usr/lib*    -> same as above
  setupMultiProfile = if isNormalBuild then "" else ''
    mkdir -m0755 x86
    cd x86
    ${linkProfile staticUsrProfileMulti}
    cd ..

    ${setupLibDirs}

    cd usr
    ${setupLibDirs}
    cd ..
  '';

  setupLibDirs = ''
    rm -f lib lib32 lib64
    mkdir -m0755 lib
    # copy glibc stuff
    cp -rs  ${staticUsrProfileTarget}/lib/32/* lib/
    # copy contents of multiPaths
    cp -rsf ${staticUsrProfileMulti}/lib/*     lib/

    ln -s lib lib32
    ln -s ${staticUsrProfileTarget}/lib lib64
  '';

in stdenv.mkDerivation {
  name         = "${name}-chrootenv";
  buildCommand = ''
    mkdir -p "$out/sw"
    cd "$out/sw"
    ${setupTargetProfile}
    ${setupMultiProfile}
    cd ..

    mkdir -p bin
    cd bin

    sed -e "s|@chrootEnv@|$out|g" \
        -e "s|@name@|${name}|g" \
        -e "s|@shell@|${stdenv.shell}|g" \
        ${initSh} > init-${name}-chrootenv
    chmod +x init-${name}-chrootenv

    sed -e "s|@shell@|${stdenv.shell}|g" \
        -e "s|@name@|${name}|g" \
        ${mountSh} > mount-${name}-chrootenv
    chmod +x mount-${name}-chrootenv

    sed -e "s|@shell@|${stdenv.shell}|g" \
        -e "s|@name@|${name}|g" \
        ${loadSh} > load-${name}-chrootenv
    chmod +x load-${name}-chrootenv

    sed -e "s|@shell@|${stdenv.shell}|g" \
        -e "s|@name@|${name}|g" \
        ${umountSh} > umount-${name}-chrootenv
    chmod +x umount-${name}-chrootenv

    sed -e "s|@chrootEnv@|$out|g" \
        -e "s|@shell@|${stdenv.shell}|g" \
        -e "s|@name@|${name}|g" \
        ${destroySh} > destroy-${name}-chrootenv
    chmod +x destroy-${name}-chrootenv

    cd ..

    cd "$out/sw"
    ${extraBuildCommands}
    cd "$out/sw"
    ${extraBuildCommandsMulti}
    cd ..
  '';
}