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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
|
{ nixpkgs, nixpkgs_i686, system
} :
{ name, profile ? ""
, pkgs ? null, targetPkgs ? pkgs: [], multiPkgs ? pkgs: []
, extraBuildCommands ? "", extraBuildCommandsMulti ? ""
}:
# HOWTO:
# All packages (most likely programs) returned from targetPkgs will only be
# installed once--matching the host's architecture (64bit on x86_64 and 32bit on
# x86).
#
# Packages (most likely libraries) returned from multiPkgs are installed
# once on x86 systems and twice on x86_64 systems.
# On x86 they are merged with packages from targetPkgs.
# On x86_64 they are added to targetPkgs and in addition their 32bit
# versions are also installed. The final directory structure looks as
# follows:
# /lib32 will include 32bit libraries from multiPkgs
# /lib64 will include 64bit libraries from multiPkgs and targetPkgs
# /lib will link to /lib32
let
isMultiBuild = pkgs == null && multiPkgs != null && system == "x86_64-linux";
isTargetBuild = !isMultiBuild;
# support deprecated "pkgs" option.
targetPkgs' =
if pkgs != null
then builtins.trace "buildFHSEnv: 'pkgs' option is deprecated, use 'targetPkgs'" (pkgs': pkgs)
else targetPkgs;
# list of packages (usually programs) which are only be installed for the
# host's architecture
targetPaths = targetPkgs' nixpkgs ++ (if multiPkgs == null then [] else multiPkgs nixpkgs);
# list of packages which are installed 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 host's architecture, gcc/glibc_multi are used for multilib
# builds.
chosenGcc = if isMultiBuild then nixpkgs.gcc_multi else nixpkgs.gcc;
basePkgs = with nixpkgs;
[ (if isMultiBuild then glibc_multi else glibc)
chosenGcc
bashInteractive coreutils less shadow su
gawk diffutils findutils gnused gnugrep
gnutar gzip bzip2 xz glibcLocales
];
etcProfile = nixpkgs.writeText "profile" ''
export PS1='${name}-chrootenv:\u@\h:\w\$ '
export LOCALE_ARCHIVE='/usr/lib/locale/locale-archive'
export LD_LIBRARY_PATH='/run/opengl-driver/lib:/run/opengl-driver-32/lib:/usr/lib:/usr/lib32'
export PATH='/var/setuid-wrappers:/usr/bin:/usr/sbin'
${profile}
'';
# Compose /etc for the chroot environment
etcPkg = nixpkgs.stdenv.mkDerivation {
name = "${name}-chrootenv-etc";
buildCommand = ''
mkdir -p $out/etc
cd $out/etc
# environment variables
ln -s ${etcProfile} profile
# compatibility with NixOS
ln -s /host-etc/static static
# symlink some NSS stuff
ln -s /host-etc/passwd passwd
ln -s /host-etc/group group
ln -s /host-etc/shadow shadow
ln -s /host-etc/hosts hosts
ln -s /host-etc/resolv.conf resolv.conf
ln -s /host-etc/nsswitch.conf nsswitch.conf
# symlink sudo and su stuff
ln -s /host-etc/login.defs login.defs
ln -s /host-etc/sudoers sudoers
ln -s /host-etc/sudoers.d sudoers.d
# symlink other core stuff
ln -s /host-etc/localtime localtime
ln -s /host-etc/machine-id machine-id
ln -s /host-etc/os-release os-release
# symlink PAM stuff
ln -s /host-etc/pam.d pam.d
# symlink fonts stuff
ln -s /host-etc/fonts fonts
# symlink ALSA stuff
ln -s /host-etc/asound.conf asound.conf
# symlink SSL certs
mkdir -p ssl
ln -s /host-etc/ssl/certs ssl/certs
# symlink /etc/mtab -> /proc/mounts (compat for old userspace progs)
ln -s /proc/mounts mtab
'';
};
# Composes a /usr-like directory structure
staticUsrProfileTarget = nixpkgs.buildEnv {
name = "${name}-usr-target";
paths = [ etcPkg ] ++ basePkgs ++ targetPaths;
ignoreCollisions = true;
};
staticUsrProfileMulti = nixpkgs.buildEnv {
name = "system-profile-multi";
paths = multiPaths;
ignoreCollisions = true;
};
# setup library paths only for the targeted architecture
setupLibDirs_target = ''
mkdir -m0755 lib
# copy content of targetPaths
cp -rsHf ${staticUsrProfileTarget}/lib/* lib/
'';
# setup /lib, /lib32 and /lib64
setupLibDirs_multi = ''
mkdir -m0755 lib32
mkdir -m0755 lib64
ln -s lib64 lib
# copy glibc stuff
cp -rsHf ${staticUsrProfileTarget}/lib/32/* lib32/ && chmod u+w -R lib32/
# copy content of multiPaths (32bit libs)
[ -d ${staticUsrProfileMulti}/lib ] && cp -rsHf ${staticUsrProfileMulti}/lib/* lib32/ && chmod u+w -R lib32/
# copy content of targetPaths (64bit libs)
cp -rsHf ${staticUsrProfileTarget}/lib/* lib64/ && chmod u+w -R lib64/
# most 64bit only libs put their stuff into /lib
# some pkgs (like gcc_multi) put 32bit libs into /lib and 64bit libs into /lib64
# by overwriting these we will hopefully catch all these cases
# in the end /lib32 should only contain 32bit and /lib64 only 64bit libs
cp -rsHf ${staticUsrProfileTarget}/lib64/* lib64/ && chmod u+w -R lib64/
# copy gcc libs
cp -rsHf ${chosenGcc.cc}/lib/* lib32/
cp -rsHf ${chosenGcc.cc}/lib64/* lib64/
# symlink 32-bit ld-linux.so
ln -s ${staticUsrProfileTarget}/lib/32/ld-linux.so.2 lib/
'';
setupLibDirs = if isTargetBuild then setupLibDirs_target
else setupLibDirs_multi;
# the target profile is the actual profile that will be used for the chroot
setupTargetProfile = ''
mkdir -m0755 usr
cd usr
${setupLibDirs}
for i in bin sbin share include; do
if [ -d "${staticUsrProfileTarget}/$i" ]; then
cp -rsHf "${staticUsrProfileTarget}/$i" "$i"
fi
done
cd ..
for i in var etc; do
if [ -d "${staticUsrProfileTarget}/$i" ]; then
cp -rsHf "${staticUsrProfileTarget}/$i" "$i"
fi
done
for i in usr/{bin,sbin,lib,lib32,lib64}; do
if [ -d "$i" ]; then
ln -s "$i"
fi
done
'';
in nixpkgs.stdenv.mkDerivation {
name = "${name}-fhs";
buildCommand = ''
mkdir -p $out
cd $out
${setupTargetProfile}
cd $out
${extraBuildCommands}
cd $out
${if isMultiBuild then extraBuildCommandsMulti else ""}
'';
preferLocalBuild = true;
passthru = {
pname = name;
};
}
|