]> git.proxmox.com Git - mirror_lxc.git/blame - templates/lxc-debian.in
Merge pull request #2055 from marcosps/cgfsng_debug
[mirror_lxc.git] / templates / lxc-debian.in
CommitLineData
bad69158 1#!/bin/bash
7afc269d 2
fb7460fe
DL
3#
4# lxc: linux Container library
06388011 5
fb7460fe
DL
6# Authors:
7# Daniel Lezcano <daniel.lezcano@free.fr>
8
9# This library is free software; you can redistribute it and/or
10# modify it under the terms of the GNU Lesser General Public
11# License as published by the Free Software Foundation; either
12# version 2.1 of the License, or (at your option) any later version.
13
14# This library is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
14d9c0f0 16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
fb7460fe 17# Lesser General Public License for more details.
06388011 18
fb7460fe
DL
19# You should have received a copy of the GNU Lesser General Public
20# License along with this library; if not, write to the Free Software
250b1eec 21# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
06388011 22
8ec981fc 23# Detect use under userns (unsupported)
c63c04fc 24for arg in "$@"; do
96283b54
SG
25 [ "$arg" = "--" ] && break
26 if [ "$arg" = "--mapped-uid" -o "$arg" = "--mapped-gid" ]; then
8ec981fc
SG
27 echo "This template can't be used for unprivileged containers." 1>&2
28 echo "You may want to try the \"download\" template instead." 1>&2
29 exit 1
30 fi
31done
32
207bf0e4
SG
33# Make sure the usual locations are in PATH
34export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
192dbe6f 35export GREP_OPTIONS=""
207bf0e4 36
d312bb74 37MIRROR=${MIRROR:-http://deb.debian.org/debian}
5d20559c 38SECURITY_MIRROR=${SECURITY_MIRROR:-http://security.debian.org/}
00fe5e1d
SG
39LOCALSTATEDIR="@LOCALSTATEDIR@"
40LXC_TEMPLATE_CONFIG="@LXCTEMPLATECONFIG@"
6dc6f80b
KC
41# Allows the lxc-cache directory to be set by environment variable
42LXC_CACHE_PATH=${LXC_CACHE_PATH:-"$LOCALSTATEDIR/cache/lxc"}
2a7c16dc 43
d50cebd6
LV
44find_interpreter()
45{
46 given_interpreter=$(basename "$1")
47
48 if [ ! -d /proc/sys/fs/binfmt_misc/ ] ; then
49 return 1
50 fi
51 for file in /proc/sys/fs/binfmt_misc/* ; do
52 if [ "$file" = "/proc/sys/fs/binfmt_misc/register" -o \
53 "$file" = "/proc/sys/fs/binfmt_misc/status" ] ; then
54 continue
55 fi
56 interpreter_path=$(sed -n "/^interpreter/s/interpreter \([^[:space:]]*\)/\1/p" "$file")
bf39edb3 57 interpreter=$(basename "$interpreter_path")
d50cebd6
LV
58
59 if [ "$given_interpreter" = "$interpreter" ] ; then
60 echo "$interpreter_path"
61 return 0
62 fi
63 done
64 return 1
65}
66
fb7460fe
DL
67configure_debian()
68{
69 rootfs=$1
70 hostname=$2
a3d42f4b 71 num_tty=$3
fb7460fe 72
4e0eb765
DB
73 # squeeze only has /dev/tty and /dev/tty0 by default,
74 # therefore creating missing device nodes for tty1-4.
bf39edb3
AF
75 for tty in $(seq 1 "$num_tty"); do
76 if [ ! -e "$rootfs/dev/tty$tty" ]; then
77 mknod "$rootfs/dev/tty$tty" c 4 "$tty"
14d9c0f0 78 fi
4e0eb765
DB
79 done
80
fb7460fe
DL
81 # configure the inittab
82 cat <<EOF > $rootfs/etc/inittab
06388011 83id:3:initdefault:
84si::sysinit:/etc/init.d/rcS
85l0:0:wait:/etc/init.d/rc 0
86l1:1:wait:/etc/init.d/rc 1
87l2:2:wait:/etc/init.d/rc 2
88l3:3:wait:/etc/init.d/rc 3
89l4:4:wait:/etc/init.d/rc 4
90l5:5:wait:/etc/init.d/rc 5
91l6:6:wait:/etc/init.d/rc 6
92# Normally not reached, but fallthrough in case of emergency.
93z6:6:respawn:/sbin/sulogin
941:2345:respawn:/sbin/getty 38400 console
bf39edb3 95$(for tty in $(seq 1 "$num_tty"); do echo "c${tty}:12345:respawn:/sbin/getty 38400 tty${tty} linux" ; done;)
f79d43bb 96p6::ctrlaltdel:/sbin/init 6
6bf8daf9 97p0::powerfail:/sbin/init 0
06388011 98EOF
06388011 99
23e88083 100 # symlink mtab
bf39edb3
AF
101 [ -e "$rootfs/etc/mtab" ] && rm "$rootfs/etc/mtab"
102 ln -s /proc/self/mounts "$rootfs/etc/mtab"
23e88083 103
fb7460fe 104 # disable selinux in debian
bf39edb3
AF
105 mkdir -p "$rootfs/selinux"
106 echo 0 > "$rootfs/selinux/enforce"
06388011 107
fb7460fe
DL
108 # configure the network using the dhcp
109 cat <<EOF > $rootfs/etc/network/interfaces
110auto lo
111iface lo inet loopback
06388011 112
fb7460fe
DL
113auto eth0
114iface eth0 inet dhcp
06388011 115EOF
1846e71a 116
fb7460fe
DL
117 # set the hostname
118 cat <<EOF > $rootfs/etc/hostname
119$hostname
120EOF
06388011 121
fb7460fe 122 # reconfigure some services
06388011 123
e160e450 124 # but first reconfigure locales - so we get no noisy perl-warnings
c99055ea 125 if [ -z "$LANG" ] || echo $LANG | grep -E -q "^C(\..+)*$"; then
bf39edb3 126 cat >> "$rootfs/etc/locale.gen" << EOF
e160e450
AF
127en_US.UTF-8 UTF-8
128EOF
bf39edb3
AF
129 chroot "$rootfs" locale-gen en_US.UTF-8 UTF-8
130 chroot "$rootfs" update-locale LANG=en_US.UTF-8
e160e450 131 else
bf39edb3
AF
132 encoding=$(echo "$LANG" | cut -d. -f2)
133 chroot "$rootfs" sed -e "s/^# \(${LANG} ${encoding}\)/\1/" \
e160e450 134 -i /etc/locale.gen 2> /dev/null
bf39edb3 135 cat >> "$rootfs/etc/locale.gen" << EOF
e160e450
AF
136$LANG $encoding
137EOF
bf39edb3
AF
138 chroot "$rootfs" locale-gen "$LANG" "$encoding"
139 chroot "$rootfs" update-locale LANG="$LANG"
e160e450
AF
140 fi
141
fb7460fe 142 # remove pointless services in a container
bf39edb3
AF
143 chroot "$rootfs" /usr/sbin/update-rc.d -f checkroot.sh disable
144 chroot "$rootfs" /usr/sbin/update-rc.d -f umountfs disable
145 chroot "$rootfs" /usr/sbin/update-rc.d -f hwclock.sh disable
146 chroot "$rootfs" /usr/sbin/update-rc.d -f hwclockfirst.sh disable
19d618b1 147
ce68d5b4 148 # generate new SSH keys
bf39edb3
AF
149 if [ -x "$rootfs/var/lib/dpkg/info/openssh-server.postinst" ]; then
150 cat > "$rootfs/usr/sbin/policy-rc.d" << EOF
ce68d5b4
SG
151#!/bin/sh
152exit 101
153EOF
bf39edb3 154 chmod +x "$rootfs/usr/sbin/policy-rc.d"
ce68d5b4 155
bf39edb3
AF
156 if [ -f "$rootfs/etc/init/ssh.conf" ]; then
157 mv "$rootfs/etc/init/ssh.conf" "$rootfs/etc/init/ssh.conf.disabled"
ce68d5b4
SG
158 fi
159
bf39edb3 160 rm -f "$rootfs/etc/ssh/"ssh_host_*key*
ce68d5b4 161
bf39edb3
AF
162 DPKG_MAINTSCRIPT_PACKAGE=openssh DPKG_MAINTSCRIPT_NAME=postinst chroot "$rootfs" /var/lib/dpkg/info/openssh-server.postinst configure
163 sed -i "s/root@$(hostname)/root@$hostname/g" "$rootfs/etc/ssh/"ssh_host_*.pub
ce68d5b4
SG
164
165 if [ -f "$rootfs/etc/init/ssh.conf.disabled" ]; then
bf39edb3 166 mv "$rootfs/etc/init/ssh.conf.disabled" "$rootfs/etc/init/ssh.conf"
ce68d5b4
SG
167 fi
168
bf39edb3 169 rm -f "$rootfs/usr/sbin/policy-rc.d"
ce68d5b4
SG
170 fi
171
f7365a24 172 # set initial timezone as on host
173 if [ -f /etc/timezone ]; then
bf39edb3
AF
174 cat /etc/timezone > "$rootfs/etc/timezone"
175 chroot "$rootfs" dpkg-reconfigure -f noninteractive tzdata
f7365a24 176 elif [ -f /etc/sysconfig/clock ]; then
17abf278 177 . /etc/sysconfig/clock
bf39edb3
AF
178 echo "$ZONE" > "$rootfs/etc/timezone"
179 chroot "$rootfs" dpkg-reconfigure -f noninteractive tzdata
f7365a24 180 else
181 echo "Timezone in container is not configured. Adjust it manually."
182 fi
183
9b6fb5d4
BJ
184 if [ -n "$authkey" ]; then
185 local ssh_dir_path="${rootfs}/root/.ssh"
186 mkdir -p "$ssh_dir_path"
187 cp "$authkey" "${ssh_dir_path}/authorized_keys"
188 chmod 700 "$ssh_dir_path"
189 echo "Inserted SSH public key from '$authkey' into /root/.ssh/authorized_keys"
190 fi
191
19d618b1 192 return 0
06388011 193}
194
177f2cd2
AD
195write_sourceslist()
196{
197 local rootfs="$1"; shift
198 local release="$1"; shift
199 local arch="$1"; shift
200
201 local prefix="deb"
202 if [ -n "${arch}" ]; then
203 prefix="deb [arch=${arch}]"
204 fi
205
c2a85d04
AT
206 if [ "$mainonly" = 1 ]; then
207 non_main=''
208 else
209 non_main=' contrib non-free'
210 fi
211
177f2cd2 212 cat >> "${rootfs}/etc/apt/sources.list" << EOF
c2a85d04 213${prefix} $MIRROR ${release} main${non_main}
d203007e
AT
214EOF
215
216 if [ "$release" != "unstable" -a "$release" != "sid" ]; then
217 cat >> "${rootfs}/etc/apt/sources.list" << EOF
c2a85d04 218${prefix} $SECURITY_MIRROR ${release}/updates main${non_main}
177f2cd2 219EOF
d203007e 220 fi
177f2cd2
AD
221}
222
223install_packages()
224{
225 local rootfs="$1"; shift
226 local packages="$*"
227
bf39edb3 228 chroot "${rootfs}" apt-get update
177f2cd2 229 if [ -n "${packages}" ]; then
bf39edb3 230 chroot "${rootfs}" apt-get install --force-yes -y --no-install-recommends ${packages}
177f2cd2
AD
231 fi
232}
233
a9bf60ba
AT
234configure_debian_systemd()
235{
236 path=$1
237 rootfs=$2
a3d42f4b
AP
238 config=$3
239 num_tty=$4
2b75b644 240
2b75b644 241 # just in case systemd is not installed
c45df3b8 242 mkdir -p "${rootfs}/lib/systemd/system"
bf39edb3 243 mkdir -p "${rootfs}/etc/systemd/system/getty.target.wants"
a9bf60ba 244
19fcf68f 245 # Fix getty-static-service as debootstrap does not install dbus
bf39edb3 246 if [ -e "$rootfs//lib/systemd/system/getty-static.service" ] ; then
ade83cbf
AF
247 local tty_services
248 tty_services=$(for i in $(seq 2 "$num_tty"); do echo -n "getty@tty${i}.service "; done; )
a3d42f4b 249 sed 's/ getty@tty.*/'" $tty_services "'/g' \
bf39edb3
AF
250 "$rootfs/lib/systemd/system/getty-static.service" | \
251 sed 's/\(tty2-tty\)[5-9]/\1'"${num_tty}"'/g' > "$rootfs/etc/systemd/system/getty-static.service"
19fcf68f
CB
252 fi
253
a9bf60ba 254 # This function has been copied and adapted from lxc-fedora
bf39edb3
AF
255 rm -f "${rootfs}/etc/systemd/system/default.target"
256 chroot "${rootfs}" ln -s /dev/null /etc/systemd/system/udev.service
257 chroot "${rootfs}" ln -s /dev/null /etc/systemd/system/systemd-udevd.service
258 chroot "${rootfs}" ln -s /lib/systemd/system/multi-user.target /etc/systemd/system/default.target
a3d42f4b 259 # Setup getty service on the ttys we are going to allow in the
fe1c5887 260 # default config. Number should match lxc.tty.max
bf39edb3
AF
261 ( cd "${rootfs}/etc/systemd/system/getty.target.wants"
262 for i in $(seq 1 "$num_tty") ; do ln -sf ../getty\@.service getty@tty"${i}".service; done )
a3d42f4b
AP
263
264 # Since we use static-getty.target; we need to mask container-getty@.service generated by
265 # container-getty-generator, so we don't get multiple instances of agetty running.
266 # See https://github.com/lxc/lxc/issues/520 and https://github.com/lxc/lxc/issues/484
bf39edb3
AF
267 ( cd "${rootfs}/etc/systemd/system/getty.target.wants"
268 for i in $(seq 0 "$num_tty"); do ln -sf /dev/null container-getty\@"${i}".service; done )
a9bf60ba
AT
269
270 return 0
271}
272
4737d51a
LV
273# Check if given path is in a btrfs partition
274is_btrfs()
275{
bf39edb3 276 [ -e "$1" -a "$(stat -f -c '%T' "$1")" = "btrfs" ]
4737d51a
LV
277}
278
279# Check if given path is the root of a btrfs subvolume
280is_btrfs_subvolume()
281{
bf39edb3 282 [ -d "$1" -a "$(stat -f -c '%T' "$1")" = "btrfs" -a "$(stat -c '%i' "$1")" -eq 256 ]
4737d51a
LV
283}
284
285try_mksubvolume()
286{
287 path=$1
bf39edb3
AF
288 [ -d "$path" ] && return 0
289 mkdir -p "$(dirname "$path")"
290 if which btrfs >/dev/null 2>&1 && is_btrfs "$(dirname "$path")"; then
291 btrfs subvolume create "$path"
4737d51a 292 else
bf39edb3 293 mkdir -p "$path"
4737d51a
LV
294 fi
295}
296
297try_rmsubvolume()
298{
299 path=$1
bf39edb3
AF
300 [ -d "$path" ] || return 0
301 if which btrfs >/dev/null 2>&1 && is_btrfs_subvolume "$path"; then
302 btrfs subvolume delete "$path"
4737d51a 303 else
bf39edb3 304 rm -rf "$path"
4737d51a
LV
305 fi
306}
307
f1ccde27
SH
308cleanup()
309{
bf39edb3
AF
310 try_rmsubvolume "$cache/partial-$release-$arch"
311 try_rmsubvolume "$cache/rootfs-$release-$arch"
f1ccde27
SH
312}
313
fb7460fe
DL
314download_debian()
315{
f95776df
AT
316 case "$release" in
317 wheezy)
318 init=sysvinit
319 ;;
320 *)
321 init=init
322 ;;
323 esac
fb7460fe 324 packages=\
f95776df 325$init,\
fb7460fe
DL
326ifupdown,\
327locales,\
fb7460fe 328dialog,\
06a1e1db 329isc-dhcp-client,\
fb7460fe
DL
330netbase,\
331net-tools,\
332iproute,\
333openssh-server
334
335 cache=$1
336 arch=$2
b269b8ad 337 release=$3
d50cebd6
LV
338 interpreter="$4"
339 interpreter_path="$5"
fb7460fe 340
f1ccde27 341 trap cleanup EXIT SIGHUP SIGINT SIGTERM
11438797
SG
342
343 # Create the cache
344 mkdir -p "$cache"
345
f16fb156
VD
346 # If debian-archive-keyring isn't installed, fetch GPG keys directly
347 releasekeyring=/usr/share/keyrings/debian-archive-keyring.gpg
348 if [ ! -f $releasekeyring ]; then
349 releasekeyring="$cache/archive-key.gpg"
350 case $release in
f16fb156
VD
351 "wheezy")
352 gpgkeyname="archive-key-7.0"
353 ;;
87eacd4d 354 *)
42139323 355 gpgkeyname="archive-key-8"
87eacd4d 356 ;;
f16fb156
VD
357 esac
358 wget https://ftp-master.debian.org/keys/${gpgkeyname}.asc -O - --quiet \
bf39edb3 359 | gpg --import --no-default-keyring --keyring="${releasekeyring}"
f16fb156 360 fi
fb7460fe 361 # check the mini debian was not already downloaded
4737d51a 362 try_mksubvolume "$cache/partial-$release-$arch"
fb7460fe 363 if [ $? -ne 0 ]; then
b269b8ad 364 echo "Failed to create '$cache/partial-$release-$arch' directory"
14d9c0f0 365 return 1
81f6a40a
RT
366 fi
367
fb7460fe
DL
368 # download a mini debian into a cache
369 echo "Downloading debian minimal ..."
d50cebd6 370 if [ "$interpreter" = "" ] ; then
bf39edb3
AF
371 debootstrap --verbose --variant=minbase --arch="$arch" \
372 --include=$packages --keyring="${releasekeyring}" \
373 "$release" "$cache/partial-$release-$arch" "$MIRROR"
d50cebd6
LV
374 if [ $? -ne 0 ]; then
375 echo "Failed to download the rootfs, aborting."
376 return 1
377 fi
378 else
bf39edb3
AF
379 debootstrap --foreign --verbose --variant=minbase --arch="$arch" \
380 --include=$packages --keyring="${releasekeyring}" \
381 "$release" "$cache/partial-$release-$arch" "$MIRROR"
d50cebd6
LV
382 if [ $? -ne 0 ]; then
383 echo "Failed to download the rootfs, aborting."
384 return 1
385 fi
bf39edb3 386 mkdir -p "$(basename "$cache/partial-$release-$arch/$interpreter_path")"
d50cebd6
LV
387 cp "$interpreter" "$cache/partial-$release-$arch/$interpreter_path"
388 if [ $? -ne 0 ]; then
389 echo "failed to copy $interpreter to $cache/partial-$release-$arch/$interpreter_path"
390 return 1
391 fi
392 chroot "$cache/partial-$release-$arch" debootstrap/debootstrap --second-stage
393 if [ $? -ne 0 ]; then
394 echo "failed to update the rootfs, aborting"
395 return 1
396 fi
c952d1b9 397 fi
cd830f33 398
b269b8ad 399 mv "$1/partial-$release-$arch" "$1/rootfs-$release-$arch"
fb7460fe 400 echo "Download complete."
f1ccde27
SH
401 trap EXIT
402 trap SIGINT
403 trap SIGTERM
404 trap SIGHUP
cd830f33 405
fb7460fe 406 return 0
c952d1b9 407}
bad69158 408
fb7460fe 409copy_debian()
c952d1b9 410{
fb7460fe
DL
411 cache=$1
412 arch=$2
413 rootfs=$3
b269b8ad 414 release=$4
bad69158 415
fb7460fe
DL
416 # make a local copy of the minidebian
417 echo -n "Copying rootfs to $rootfs..."
bf39edb3 418 try_mksubvolume "$rootfs"
4737d51a
LV
419 if which btrfs >/dev/null 2>&1 && \
420 is_btrfs_subvolume "$cache/rootfs-$release-$arch" && \
bf39edb3
AF
421 is_btrfs_subvolume "$rootfs"; then
422 realrootfs="$(dirname "$config")"/rootfs
423 [ "$rootfs" = "$realrootfs" ] || umount "$rootfs" || return 1
424 btrfs subvolume delete "$realrootfs" || return 1
425 btrfs subvolume snapshot "$cache/rootfs-$release-$arch" "$realrootfs" || return 1
426 [ "$rootfs" = "$realrootfs" ] || mount --bind "$realrootfs" "$rootfs" || return 1
4737d51a 427 else
6273aef1 428 rsync -SHaAX "$cache/rootfs-$release-$arch"/ $rootfs/ || return 1
4737d51a 429 fi
fb7460fe 430 return 0
c952d1b9 431}
432
fb7460fe
DL
433install_debian()
434{
fb7460fe 435 rootfs=$1
b269b8ad 436 release=$2
1927a6be 437 arch=$3
6dc6f80b 438 cache="$4/debian"
d50cebd6
LV
439 interpreter="$5"
440 interpreter_path="$6"
6ffa3291 441 flushcache=$7
00fe5e1d 442 mkdir -p $LOCALSTATEDIR/lock/subsys/
fb7460fe 443 (
17abf278 444 flock -x 9
14d9c0f0
SG
445 if [ $? -ne 0 ]; then
446 echo "Cache repository is busy."
447 return 1
448 fi
7afc269d 449
bf39edb3 450 if [ "$flushcache" -eq 1 ]; then
6ffa3291
LV
451 echo "Flushing cache..."
452 cleanup
453 fi
454
b269b8ad
LV
455 echo "Checking cache download in $cache/rootfs-$release-$arch ... "
456 if [ ! -e "$cache/rootfs-$release-$arch" ]; then
bf39edb3 457 download_debian "$cache" "$arch" "$release" "$interpreter" "$interpreter_path"
14d9c0f0
SG
458 if [ $? -ne 0 ]; then
459 echo "Failed to download 'debian base'"
460 return 1
461 fi
462 fi
c952d1b9 463
bf39edb3 464 copy_debian "$cache" "$arch" "$rootfs" "$release"
14d9c0f0
SG
465 if [ $? -ne 0 ]; then
466 echo "Failed to copy rootfs"
467 return 1
468 fi
c952d1b9 469
14d9c0f0 470 return 0
c952d1b9 471
00fe5e1d 472 ) 9>$LOCALSTATEDIR/lock/subsys/lxc-debian
85cbaa06 473
fb7460fe 474 return $?
bad69158 475}
476
fb7460fe
DL
477copy_configuration()
478{
479 path=$1
480 rootfs=$2
16501521 481 hostname=$3
1927a6be 482 arch=$4
a3d42f4b 483 num_tty=$5
bad69158 484
00fe5e1d 485 # Generate the configuration file
aea1cd3c
SG
486 # if there is exactly one veth network entry, make sure it has an
487 # associated hwaddr.
7fa3f2e9 488 nics=$(grep -ce '^lxc\.net\.0\.type[ \t]*=[ \t]*veth' "$path/config")
bf39edb3 489 if [ "$nics" -eq 1 ]; then
7fa3f2e9 490 grep -q "^lxc.net.0.hwaddr" "$path/config" || sed -i -e "/^lxc\.net\.0\.type[ \t]*=[ \t]*veth/a lxc.net.0.hwaddr = 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')" "$path/config"
aea1cd3c
SG
491 fi
492
00fe5e1d 493 ## Add all the includes
bf39edb3
AF
494 echo "" >> "$path/config"
495 echo "# Common configuration" >> "$path/config"
00fe5e1d 496 if [ -e "${LXC_TEMPLATE_CONFIG}/debian.common.conf" ]; then
bf39edb3 497 echo "lxc.include = ${LXC_TEMPLATE_CONFIG}/debian.common.conf" >> "$path/config"
00fe5e1d
SG
498 fi
499 if [ -e "${LXC_TEMPLATE_CONFIG}/debian.${release}.conf" ]; then
bf39edb3 500 echo "lxc.include = ${LXC_TEMPLATE_CONFIG}/debian.${release}.conf" >> "$path/config"
00fe5e1d
SG
501 fi
502
503 ## Add the container-specific config
bf39edb3
AF
504 echo "" >> "$path/config"
505 echo "# Container specific configuration" >> "$path/config"
7a96a068 506 grep -q "^lxc.rootfs.path" "$path/config" 2> /dev/null || echo "lxc.rootfs.path = $rootfs" >> "$path/config"
00fe5e1d 507
fb7460fe 508 cat <<EOF >> $path/config
fe1c5887 509lxc.tty.max = $num_tty
b67771bc 510lxc.uts.name = $hostname
00fe5e1d 511lxc.arch = $arch
232763d6 512lxc.pty.max = 1024
fb7460fe 513EOF
bad69158 514
fb7460fe 515 if [ $? -ne 0 ]; then
14d9c0f0
SG
516 echo "Failed to add configuration"
517 return 1
bad69158 518 fi
519
520 return 0
521}
522
177f2cd2
AD
523post_process()
524{
525 local rootfs="$1"; shift
526 local release="$1"; shift
527 local arch="$1"; shift
528 local hostarch="$1"; shift
d50cebd6 529 local interpreter="$1"; shift
177f2cd2
AD
530 local packages="$*"
531
532 # Disable service startup
bf39edb3 533 cat > "${rootfs}/usr/sbin/policy-rc.d" << EOF
177f2cd2
AD
534#!/bin/sh
535exit 101
536EOF
bf39edb3 537 chmod +x "${rootfs}/usr/sbin/policy-rc.d"
177f2cd2
AD
538
539 # If the container isn't running a native architecture, setup multiarch
d50cebd6 540 if [ "$interpreter" = "" -a "${arch}" != "${hostarch}" ]; then
28e58a6a 541 # Test if dpkg supports multiarch
7d4c775a 542 if ! chroot "$rootfs" dpkg --print-foreign-architectures 2>&1; then
bf39edb3 543 chroot "$rootfs" dpkg --add-architecture "${hostarch}"
28e58a6a 544 fi
177f2cd2
AD
545 fi
546
547 # Write a new sources.list containing both native and multiarch entries
bf39edb3 548 > "${rootfs}/etc/apt/sources.list"
d50cebd6 549 if [ "$interpreter" != "" -a "${arch}" = "${hostarch}" ]; then
bf39edb3 550 write_sourceslist "${rootfs}" "${release}" "${arch}"
177f2cd2 551 else
bf39edb3 552 write_sourceslist "${rootfs}" "${release}"
177f2cd2
AD
553 fi
554
555 # Install Packages in container
556 if [ -n "${packages}" ]; then
ade83cbf
AF
557 local pack_list
558 pack_list="${packages//,/ }"
177f2cd2 559 echo "Installing packages: ${pack_list}"
bf39edb3 560 install_packages "${rootfs}" "${pack_list}"
177f2cd2
AD
561 fi
562
563 # Re-enable service startup
bf39edb3 564 rm "${rootfs}/usr/sbin/policy-rc.d"
114eb32f 565
114eb32f 566 # end
177f2cd2
AD
567}
568
fb7460fe
DL
569clean()
570{
6dc6f80b 571 cache=${LXC_CACHE_PATH:-"$LOCALSTATEDIR/cache/lxc/debian"}
bad69158 572
bf39edb3 573 if [ ! -e "$cache" ]; then
14d9c0f0 574 exit 0
bad69158 575 fi
576
577 # lock, so we won't purge while someone is creating a repository
578 (
17abf278 579 flock -x 9
14d9c0f0
SG
580 if [ $? != 0 ]; then
581 echo "Cache repository is busy."
582 exit 1
583 fi
bad69158 584
14d9c0f0 585 echo -n "Purging the download cache..."
bf39edb3 586 rm --preserve-root --one-file-system -rf "$cache" && echo "Done." || exit 1
14d9c0f0 587 exit 0
bad69158 588
00fe5e1d 589 ) 9>$LOCALSTATEDIR/lock/subsys/lxc-debian
bad69158 590}
591
fb7460fe
DL
592usage()
593{
594 cat <<EOF
9cbffb9f
TP
595Template specific options can be passed to lxc-create after a '--' like this:
596
597 lxc-create --name=NAME [-lxc-create-options] -- [-template-options]
598
599Usage: $1 -h|--help -p|--path=<path> [-c|--clean] [-a|--arch=<arch>] [-r|--release=<release>]
600 [--mirror=<mirror>] [--security-mirror=<security mirror>]
601 [--package=<package_name1,package_name2,...>]
d50cebd6 602 [-I|--interpreter-path=<interpreter path>]
9b6fb5d4 603 [-F | --flush-cache] [-S|--auth-key=<keyfile>]
9cbffb9f
TP
604
605Options :
606
607 -h, --help print this help text
608 -p, --path=PATH directory where config and rootfs of this VM will be kept
9b6fb5d4 609 -S, --auth-key=KEYFILE SSH public key to inject into the container as the root user.
9cbffb9f
TP
610 -a, --arch=ARCH The container architecture. Can be one of: i686, x86_64,
611 amd64, armhf, armel, powerpc. Defaults to host arch.
52c5ac5f 612 -r, --release=RELEASE Debian release. Can be one of: wheezy, jessie, stretch, buster, sid.
9cbffb9f
TP
613 Defaults to current stable.
614 --mirror=MIRROR Debian mirror to use during installation. Overrides the MIRROR
615 environment variable (see below).
616 --security-mirror=SECURITY_MIRROR
617 Debian mirror to use for security updates. Overrides the
618 SECURITY_MIRROR environment variable (see below).
619 --packages=PACKAGE_NAME1,PACKAGE_NAME2,...
620 List of additional packages to install. Comma separated, without space.
621 -c, --clean only clean up the cache and terminate
57b40c08 622 --enable-non-free include also Debian's contrib and non-free repositories.
d50cebd6
LV
623 -I|--interpreter-path=INTERPRETER-PATH
624 Path of the binfmt interpreter to copy to the rootfs
6ffa3291 625 -F | --flush-cache Flush the debian release cache
9cbffb9f
TP
626
627Environment variables:
628
629 MIRROR The Debian package mirror to use. See also the --mirror switch above.
630 Defaults to '$MIRROR'
631 SECURITY_MIRROR The Debian package security mirror to use. See also the --security-mirror switch above.
632 Defaults to '$SECURITY_MIRROR'
633
fb7460fe
DL
634EOF
635 return 0
636}
637
9b6fb5d4 638options=$(getopt -o hp:n:a:r:cI:FS: -l arch:,auth-key:,clean,help,enable-non-free,mirror:,name:,packages:,path:,release:,rootfs:,security-mirror:,interpreter-path:,flush-cache -- "$@")
fb7460fe 639if [ $? -ne 0 ]; then
bf39edb3 640 usage "$(basename "$0")"
14d9c0f0 641 exit 1
fb7460fe
DL
642fi
643eval set -- "$options"
644
6f943dd9
JC
645littleendian=$(lscpu | grep '^Byte Order' | grep -q Little && echo yes)
646
4963978b
SG
647arch=$(uname -m)
648if [ "$arch" = "i686" ]; then
649 arch="i386"
650elif [ "$arch" = "x86_64" ]; then
651 arch="amd64"
652elif [ "$arch" = "armv7l" ]; then
653 arch="armhf"
2c660503
EG
654elif [ "$arch" = "aarch64" ]; then
655 arch="arm64"
944d1191
SRR
656elif [ "$arch" = "ppc" ]; then
657 arch="powerpc"
bfbf7936
TF
658elif [ "$arch" = "ppc64le" ]; then
659 arch="ppc64el"
6f943dd9
JC
660elif [ "$arch" = "mips" -a "$littleendian" = "yes" ]; then
661 arch="mipsel"
662elif [ "$arch" = "mips64" -a "$littleendian" = "yes" ]; then
663 arch="mips64el"
1927a6be
LV
664fi
665hostarch=$arch
57b40c08 666mainonly=1
6ffa3291 667flushcache=0
1927a6be 668
fb7460fe
DL
669while true
670do
671 case "$1" in
bf39edb3 672 -h|--help) usage "$0" && exit 1;;
177f2cd2
AD
673 --) shift 1; break ;;
674
675 -a|--arch) arch=$2; shift 2;;
9b6fb5d4 676 -S|--auth-key) authkey=$2; shift 2;;
d50cebd6
LV
677 -I|--interpreter-path)
678 interpreter="$2"; shift 2;;
e4d4da62 679 -c|--clean) clean=1; shift 1;;
57b40c08 680 --enable-non-free) mainonly=0; shift 1;;
177f2cd2
AD
681 --mirror) MIRROR=$2; shift 2;;
682 -n|--name) name=$2; shift 2;;
683 --packages) packages=$2; shift 2;;
684 -p|--path) path=$2; shift 2;;
685 -r|--release) release=$2; shift 2;;
686 --rootfs) rootfs=$2; shift 2;;
687 --security-mirror) SECURITY_MIRROR=$2; shift 2;;
6ffa3291 688 -F|--flush-cache) flushcache=1; shift 1;;
177f2cd2 689 *) break ;;
fb7460fe
DL
690 esac
691done
692
693if [ ! -z "$clean" -a -z "$path" ]; then
694 clean || exit 1
695 exit 0
696fi
697
17abf278 698if [ "$arch" = "i686" ]; then
1927a6be
LV
699 arch=i386
700fi
701
17abf278 702if [ "$arch" = "x86_64" ]; then
1927a6be
LV
703 arch=amd64
704fi
705
d50cebd6
LV
706if [ "$interpreter" = "" ] ; then
707 if [ $hostarch = "i386" -a $arch = "amd64" ]; then
708 echo "can't create $arch container on $hostarch"
709 exit 1
710 fi
1927a6be 711
d50cebd6
LV
712 if [ $hostarch = "armhf" -o $hostarch = "armel" ] && \
713 [ $arch != "armhf" -a $arch != "armel" ]; then
714 echo "can't create $arch container on $hostarch"
715 exit 1
716 fi
1927a6be 717
d50cebd6
LV
718 if [ $hostarch = "powerpc" -a $arch != "powerpc" ]; then
719 echo "can't create $arch container on $hostarch"
720 exit 1
721 fi
6f943dd9
JC
722
723 if [ $hostarch = "mips" -a $arch != "mips" ] || \
724 [ $hostarch = "mipsel" -a $arch != "mipsel" ] || \
725 [ $hostarch = "mips64" -a $arch != "mips" -a $arch != "mips64" ] || \
726 [ $hostarch = "mips64el" -a $arch != "mipsel" -a $arch != "mips64el" ]; then
727 echo "can't create $arch container on $hostarch"
728 exit 1
729 fi
d50cebd6
LV
730else
731 if ! file -b "${interpreter}" |grep -q "statically linked" ; then
732 echo "'${interpreter}' must be statically linked" 1>&2
733 exit 1
734 fi
735 interpreter_path=$(find_interpreter "$interpreter")
736 if [ $? -ne 0 ] ; then
bf39edb3 737 echo "no binfmt interpreter using $(basename "$interpreter")" 1>&2
d50cebd6
LV
738 exit 1
739 fi
1927a6be
LV
740fi
741
fb7460fe
DL
742type debootstrap
743if [ $? -ne 0 ]; then
744 echo "'debootstrap' command is missing"
745 exit 1
746fi
747
748if [ -z "$path" ]; then
749 echo "'path' parameter is required"
750 exit 1
751fi
752
753if [ "$(id -u)" != "0" ]; then
754 echo "This script should be run as 'root'"
755 exit 1
c01d62f2 756fi
bad69158 757
9b6fb5d4
BJ
758if [ -n "$authkey" ]; then
759 if [ ! -f "$authkey" ]; then
760 echo "SSH keyfile '$authkey' not found"
761 exit 1
762 fi
763 # This is mostly to prevent accidental uage of the private key instead
764 # of the public key.
765 if [ "${authkey: -4}" != ".pub" ]; then
766 echo "SSH keyfile '$authkey' does not end with '.pub'"
767 exit 1
768 fi
769fi
770
dba285d5
AT
771release=${release:-stable}
772permanent_releases=('stable' 'testing' 'sid' 'unstable')
773if [[ ! "${permanent_releases[*]}" =~ (^|[^[:alpha:]])$release([^[:alpha:]]|$) ]]; then
774 if ! wget "${MIRROR}/dists/${release}/Release" -O /dev/null 2> /dev/null; then
775 echo "Invalid release ${release} (not found in mirror)"
776 exit 1
777 fi
b269b8ad
LV
778fi
779
1881820a
SH
780# detect rootfs
781config="$path/config"
1897e3bc 782if [ -z "$rootfs" ]; then
7a96a068
CB
783 if grep -q '^lxc.rootfs.path' "$config" 2> /dev/null ; then
784 rootfs=$(awk -F= '/^lxc.rootfs.path[ \t]+=/{ print $2 }' "$config")
1897e3bc
SH
785 else
786 rootfs=$path/rootfs
787 fi
1881820a
SH
788fi
789
a3d42f4b 790# determine the number of ttys - default is 4
fe1c5887
CB
791if grep -q '^lxc.tty.max' "$config" 2> /dev/null ; then
792 num_tty=$(awk -F= '/^lxc.tty.max[ \t]+=/{ print $2 }' "$config")
a3d42f4b
AP
793else
794 num_tty=4
795fi
796
bf39edb3 797install_debian "$rootfs" "$release" "$arch" "$LXC_CACHE_PATH" "$interpreter" "$interpreter_path" "$flushcache"
fb7460fe
DL
798if [ $? -ne 0 ]; then
799 echo "failed to install debian"
800 exit 1
801fi
802
bf39edb3 803configure_debian "$rootfs" "$name" $num_tty
fb7460fe
DL
804if [ $? -ne 0 ]; then
805 echo "failed to configure debian for a container"
806 exit 1
807fi
808
bf39edb3 809copy_configuration "$path" "$rootfs" "$name" $arch $num_tty
fb7460fe
DL
810if [ $? -ne 0 ]; then
811 echo "failed write configuration file"
812 exit 1
813fi
814
bf39edb3 815configure_debian_systemd "$path" "$rootfs" "$config" $num_tty
a9bf60ba 816
bf39edb3 817post_process "${rootfs}" "${release}" ${arch} ${hostarch} "${interpreter}" "${packages}"
177f2cd2 818
227c5600 819if [ ! -z "$clean" ]; then
fb7460fe
DL
820 clean || exit 1
821 exit 0
822fi