]> git.proxmox.com Git - mirror_lxc.git/blob - templates/lxc-gentoo.in
gentoo: Initial template
[mirror_lxc.git] / templates / lxc-gentoo.in
1 #!/bin/bash
2
3 #
4 # LXC template for gentoo
5 #
6 # Author: Guillaume Zitta <lxc@zitta.fr>
7 #
8 # Widely inspired from lxc-gentoo script at https://github.com/globalcitizen/lxc-gentoo
9 #
10 # this version is reworked with :
11 # - out of the lxc-create compat
12 # - vanilla gentoo config
13 # - ready to use cache
14 #
15
16 # Ensure strict root's umask doesen't render the VM unusable
17 umask 022
18
19 ################################################################################
20 # Various helper functions
21 ################################################################################
22
23 # param: $1: the name of the lock
24 # param: $2: the timeout for the lock
25 # The rest contain the command to execute and its parameters
26 execute_exclusively()
27 {
28 mkdir -p @LOCALSTATEDIR@/lock/subsys/
29
30 local lock_name="$1"
31 local timeout="$2"
32 shift 2
33
34 {
35 printf "Attempting to obtain an exclusive lock (timeout: %s sec) named \"%s\"...\n" "${timeout}" "$lock_name"
36
37 flock -x -w "${timeout}" 50
38
39 if [[ $? -ne 0 ]]; then
40 printf " => unable to obtain lock, aborting.\n"
41 return 2
42 else
43 printf " => done.\n"
44 fi
45
46 printf " => Executing \"%s\"\n" "$*"
47 "$@"
48 retval=$?
49 } 50> "@LOCALSTATEDIR@/lock/subsys/lxc-gentoo-${lock_name}"
50 return $retval
51 }
52
53 # a die function is always a good idea
54 die()
55 {
56 printf "\n[the last exit code leading to this death was: %s ]\n" "$?"
57 local retval="$1"
58 shift 1
59 printf "$@"
60 exit "$retval"
61 }
62
63 # gentoo arch/variant detection
64 set_default_arch()
65 {
66 printf "### set_default_arch: default arch/variant autodetect...\n"
67 arch=$(arch)
68 if [[ $arch =~ i.86 ]]; then
69 arch="x86"
70 variant="x86"
71 elif [[ $arch == "x86_64" ]]; then
72 arch="amd64"
73 variant="amd64"
74 elif [[ $arch =~ arm.* ]]; then
75 arch="arm"
76 variant="armv7a"
77 else
78 #who knows, it may work...
79 printf " => warn: unexpected arch:${arch} let me knows if it works :)\n"
80 variant="${arch}"
81 fi
82 printf " => Got: arch=%s variant=%s\n" "${arch}" "${variant}"
83 }
84
85 store_user_message()
86 {
87 user_message="${user_message}=> $@\n"
88 }
89
90 ################################################################################
91 # CACHE Preparation
92 ################################################################################
93 # during setup cachedir is $cacheroot/partial-$arch-$variant
94 # at the end, it will be $cacheroot/rootfs-$arch-$variant
95
96 cache_setup(){
97 partialfs="${cacheroot}/partial-${arch}-${variant}"
98
99 #if cache exists and flush not needed, return
100 [[ -d "${cachefs}" && -z "${flush_cache}" ]] && return 0
101
102 printf "###### cache_setup(): doing cache preparation\n"
103 local retval=1
104
105 #clean from failed previous run
106 rm -rf "${partialfs}"
107 mkdir -p "${partialfs}"
108
109 #let's go
110 cache_precheck && \
111 cache_stage3 && \
112 cache_portage && \
113 cache_inittab && \
114 cache_net && \
115 cache_dev && \
116 cache_openrc && \
117 rm -rf "${cachefs}" && \
118 mv "${partialfs}" "${cachefs}" && \
119 printf "###### cache_setup: Cache should be ready\n"
120
121 return $?
122 }
123
124 cache_precheck()
125 {
126 printf "### cache_precheck(): doing some pre-start checks ...\n"
127 # never hurts to have a fail-safe.
128 [[ -n "${cacheroot//\/}" ]] \
129 || die 8 "\$cacheroot (%s) IS EMPTY OR MADE OF ONLY DIRECTORY SEPERATORS, THIS IS *VERY* BAD!\n" "${cacheroot}"
130 }
131
132 #get latest stage3 tarball
133 cache_stage3()
134 {
135 printf "### cache_stage3(): stage3 cache deployment...\n"
136
137 if [ -z "${tarball}" ]; then
138 #variables init
139 local stage3_baseurl="${mirror}/releases/${arch}/autobuilds"
140
141 # get latest-stage3....txt file for subpath
142 local stage3_pointer="${stage3_baseurl}/latest-stage3-${variant}.txt"
143
144 printf "Determining path to latest Gentoo %s (%s) stage3 archive...\n" "${arch}" "${variant}"
145 printf " => downloading and processing %s\n" "${stage3_pointer}"
146
147 local stage3_latest_tarball=$(wget -q -O - "${stage3_pointer}" | tail -n1 ) \
148 || die 6 "Error: unable to fetch\n"
149
150 printf " => Got: %s\n" "${stage3_latest_tarball}"
151
152 printf "Downloading/untarring the actual stage3 tarball...\n"
153 wget -O - "${stage3_baseurl}/${stage3_latest_tarball}" | tar -xjpf - -C "${partialfs}" \
154 || die 6 "Error: unable to fetch or untar\n"
155 printf " => extracted to: %s\n" "${partialfs}"
156 else
157 printf "Extracting the stage3 tarball...\n"
158 tar -xpf "${tarball}" -C "${partialfs}" || die 6 "unable to untar ${tarball} to ${partialfs}"
159 fi
160
161 #check if it chroots
162 printf "chroot test..."
163 chroot ${partialfs} /bin/true || die 1 "Error: chroot %s /bin/true, failed" "${partialfs}"
164 printf " OK\n"
165 printf " => stage3 cache extracted in : %s\n" "${partialfs}"
166 return 0
167 }
168
169 cache_portage()
170 {
171 printf "### cache_portage: caching portage tree tarball...\n"
172 [[ -z "${flush_cache}" && -f "${portage_cache}" ]] && return 0
173
174 rm -f ${portage_cache}
175
176 printf "Downloading Gentoo portage (software build database) snapshot...\n"
177 execute_exclusively portage 60 wget -O "${portage_cache}" "${mirror}/snapshots/portage-latest.tar.bz2" \
178 || die 6 "Error: unable to fetch\n"
179 printf " => done.\n"
180 }
181
182 # custom inittab
183 cache_inittab()
184 {
185 printf "### cache_inittab: tuning inittab...\n"
186
187 INITTAB="${partialfs}/etc/inittab"
188
189 [[ -w "$INITTAB" ]] || die 1 "Error: $INITTAB is not writeable"
190
191 # create console
192 echo "# Lxc main console" >> "$INITTAB"
193 echo "1:12345:respawn:/sbin/agetty -a root --noclear 115200 console linux" >> "$INITTAB"
194
195 # finally we add a pf line to enable clean shutdown on SIGPWR (issue 60)
196 echo "# clean container shutdown on SIGPWR" >> "$INITTAB"
197 echo "pf:12345:powerwait:/sbin/halt" >> "$INITTAB"
198
199 # we also blank out /etc/issue here in order to prevent delays spawning login
200 # caused by attempts to determine domainname on disconnected containers
201 sed -i 's/[\][Oo]//g' "${partialfs}/etc/issue"
202 }
203
204 cache_net()
205 {
206 printf "### cache_net: doing some useful net tuning...\n"
207 # useful for chroot
208 # /etc/resolv.conf
209 grep -i 'search ' /etc/resolv.conf > "${partialfs}/etc/resolv.conf"
210 grep -i 'nameserver ' /etc/resolv.conf >> "${partialfs}/etc/resolv.conf"
211
212 # fix boot-time interface config wipe under aggressive cap drop
213 # (openrc 0.9.8.4 ~sep 2012 - https://bugs.gentoo.org/show_bug.cgi?id=436266)
214 # initial warkaround was: sed -i -e 's/^#rc_nostop=""/rc_nostop="net.eth0 net.lo"/' "${partialfs}/etc/rc.conf"
215 # but this one does not depends on interfaces names
216 echo 'rc_keyword="-stop"' >> "${partialfs}/etc/conf.d/net"
217 }
218
219 cache_dev()
220 {
221 printf "### cache_dev(): /dev tuning...\n"
222
223 #Wait for https://bugs.gentoo.org/show_bug.cgi?id=496054
224 mkdir "${partialfs}/dev/pts"
225
226 if [ -n "${nettun}" ]; then
227 mkdir -m 755 "${partialfs}/net"
228 mknod -m 666 "${partialfs}/net/tun" c 10 200
229 fi
230
231 return 0
232 }
233
234 # fix openrc system
235 cache_openrc()
236 {
237 printf "### cache_openrc(): doing openrc tuning\n"
238
239 #Wait for https://bugs.gentoo.org/show_bug.cgi?id=496054
240 chroot "${partialfs}" sed s/-lxc//g -i "/etc/init.d/devfs"
241
242 return 0
243 }
244
245 ################################################################################
246 # CONTAINER Preparation
247 ################################################################################
248
249 container_setup() {
250 printf "##### container_setup(): starting container setup\n"
251
252 #in most cases lxc-create should have provided a copy of default lxc.conf
253 #let's tag where template starts, or just create the files
254 echo '### lxc-gentoo template stuff starts here' >> "$path/config"
255
256 #Determine rootfs
257 #If backingstore was specified, lxc.rootfs should be present or --rootfs did the rootfs var creation
258 if [ -z "${rootfs}" ]; then
259 rootfs=`awk -F= '$1 ~ /^lxc.rootfs/ { print $2 }' "$path/config" 2>/dev/null`
260 if [ -z "${rootfs}" ]; then
261 #OK it's default
262 rootfs="${path}/rootfs"
263 fi
264 fi
265 store_user_message "rootfs of container is : ${rootfs}"
266 store_user_message "config of container is : ${path}/config"
267
268 container_precheck && \
269 container_rootfs && \
270 container_consoles && \
271 container_tz && \
272 container_portage && \
273 container_net && \
274 container_hostname && \
275 container_auth && \
276 container_conf
277 if [ $? -ne 0 ]; then
278 die 1 "container_setup(): one step didn't complete, sorry\n"
279 fi
280
281 printf "###### container_setup(): container should be ready to start!\n"
282 printf "\n\n"
283 printf "You could now use you container with: lxc-start -n %s\n" "${name}"
284 printf "little things you should know about your container:\n"
285 printf "${user_message}"
286 return 0
287 }
288
289 container_precheck()
290 {
291 printf "### container_precheck(): doing some pre-start checks ...\n"
292 # never hurts to have a fail-safe.
293 [[ -n "${name//\/}" ]] \
294 || die 8 "\$name (%s) IS EMPTY OR MADE OF ONLY DIRECTORY SEPERATORS, THIS IS *VERY* BAD!\n" "${name}"
295
296 [[ -n "${rootfs//\/}" ]] \
297 || die 8 "\$rootfs (%s) IS EMPTY OR MADE OF ONLY DIRECTORY SEPERATORS, THIS IS *VERY* BAD!\n" "${rootfs}"
298
299 [[ -n "${cachefs//\/}" ]] \
300 || die 8 "\$cachefs (%s) IS EMPTY OR MADE OF ONLY DIRECTORY SEPERATORS, THIS IS *VERY* BAD!\n" "${cachefs}"
301
302 # check if the rootfs already exists
303 [[ -d "${rootfs}/etc" ]] && die 18 "Error: \$rootfs (%s) already exists!" "${rootfs}"
304
305 # check cache
306 [[ ! -d "${cachefs}/etc" ]] && die 1 "Error: \$cachefs (%s) not found!" "${cachefs}"
307
308 return 0
309 }
310
311 container_rootfs()
312 {
313 printf "#### container_rootfs(): copying rootfs %s from cache %s ...\n" "${rootfs}" "${cachefs}"
314 tar -c -f - -C "${cachefs}" . | tar -x -p -f - -C "${rootfs}" || die 1 "Error: cache copy to rootfs failed"
315
316 printf "chroot test..."
317 chroot "${rootfs}" /bin/true || die 1 "Error: 'chroot %s /bin/true' failed"
318 printf " OK\n"
319
320 printf " => done\n"
321 return 0
322 }
323
324 container_consoles() {
325 printf "#### container_consoles(): setting container consoles ...\n"
326
327 # disable unwanted ttys
328 if [[ ${tty} < 6 ]]; then
329 local mindis=$(( ${tty} + 1 ))
330 sed -i "s/^c[${mindis}-6]/#&/" "${rootfs}/etc/inittab"
331 fi
332 printf " => main console + ${tty} ttys\n"
333
334 if [[ -z "${autologin}" ]]; then
335 sed 's/agetty -a root/agetty/' -i "${rootfs}/etc/inittab"
336 elif [[ "${user}" != "root" ]]; then
337 sed "s/agetty -a root/agetty -a ${user}/" -i "${rootfs}/etc/inittab"
338 printf " => Autologin on main console for %s enabled\n" "${user}"
339 [[ -z "${forced_password}" ]] && unset password
340 store_user_message "${user} has autologin on main console"
341 else
342 printf " => Autologin on main console for root enabled\n"
343 [[ -z "${forced_password}" ]] && unset password
344 store_user_message "${user} has autologin on main console"
345 fi
346 printf " => done\n"
347 }
348
349 container_tz()
350 {
351 printf "#### container_tz(): setting container timezone ...\n"
352
353 #let's try to copy it from host
354 if [ -L "/etc/localtime" ]; then
355 #host has a symlink
356 #let see if we can reproduct symlink
357 target=$(readlink /etc/localtime)
358 if [[ "$target" != "" ]]; then
359 if [ -f "${rootfs}/${target}" ]; then
360 #same target exists in container
361 chroot "${rootfs}" ln -sf "${target}" "/etc/localtime"
362 printf " => host symlink reproducted in container : %s\n" "${target}"
363 store_user_message "timezone copyed from host"
364 return 0
365 fi
366 fi
367 fi
368
369 if [ -e /etc/localtime ]; then
370 # duplicate host timezone
371 cat /etc/localtime > "${rootfs}/etc/localtime"
372 printf " => host localtime copyed to container\n"
373 store_user_message "timezone was staticly copyed from host"
374 else
375 # otherwise set up UTC
376 chroot "${rootfs}" ln -sf /usr/share/zoneinfo/UTC /etc/localtime
377 printf " => fallback: fixed to UTC\n"
378 store_user_message "timezone was fixed to UTC"
379 fi
380 }
381
382
383 container_portage()
384 {
385 printf "#### container_portage(): setting container portage... \n"
386
387 #default entry for conf
388 portage_mount="#container set with private portage tree, no mount here"
389
390 printf "Warnings are normal here, don't worry\n"
391 #container repos detection
392 if chroot ${rootfs} portageq get_repo_path / gentoo > /dev/null ; then
393 portage_container="$(chroot ${rootfs} portageq get_repo_path / gentoo)"
394 else
395 die 1 "Failed to figure out container portage tree location with portageq get_repo_path / gentoo\n"
396 fi
397
398 if [[ -n "${private_portage}" ]]; then
399 container_private_portage
400 return 0
401 fi
402
403 if [ -z "${portage_dir}" ]; then
404 #gentoo host detection
405 printf "trying to guess portage_dir from host...\n"
406 portage_dir="$(portageq get_repo_path / gentoo 2>/dev/null)"
407 if [ ! -d "${portage_dir}/profiles" ]; then
408 printf " => host portage detection failed (not gentoo host), fallback to private portage tree\n"
409 container_private_portage
410 return 0
411 fi
412 else
413 if [ ! -d "${portage_dir}/profiles" ]; then
414 die 1 "specified portage_dir (%s) does not contains profiles, is it a portage tree ?\n" "${portage_dir}"
415 fi
416 fi
417
418 # if we are here, we have shared portage_dir
419 #ensure dir exists
420 chroot "${rootfs}" mkdir ${portage_container}
421 portage_mount="#container set with shared portage
422 lxc.mount.entry=${portage_dir} ${portage_container/\//} none ro,bind 0 0"
423 store_user_message "container has a shared portage from host's ${portage_dir} to ${portage_container/\//}"
424 #Let's propose binary packages
425 cat <<- EOF >> "${rootfs}/etc/portage/make.conf"
426 # enable this to store built binary packages
427 #FEATURES="\$FEATURES buildpkg"
428
429 # enable this to use built binary packages
430 #EMERGE_DEFAULT_OPTS="\${EMERGE_DEFAULT_OPTS} --usepkg"
431
432 # enable and *tune* this kind of entry to slot binaries, specialy if you use multiples archs and variants
433 #PKGDIR="\${PKGDIR}/amd64
434 #or PKGDIR="\${PKGDIR}/hardened"
435 EOF
436 printf " => portage stuff done, see /etc/portage/make.conf for additionnal tricks\n"
437
438 }
439
440 container_private_portage()
441 {
442 #called from container_portage() do not call directly from container_setup
443 printf "# untaring private portage to %s from %s ... \n" "${rootfs}/${portage_container}" "${portage_cache}"
444 mkdir -p "${rootfs}/${portage_container}"
445 execute_exclusively portage 60 tar -xp --strip-components 1 -C "${rootfs}/${portage_container}" -f "${portage_cache}" \
446 || die 2 "Error: unable to extract the portage tree.\n"
447 store_user_message "container has its own portage tree at ${portage_container}"
448 printf "=> done\n"
449 }
450
451 #helper func for container_genconf_net()
452 nic_write()
453 {
454 #display with gentoo's confd.net format
455 echo "config_${nic_name}=\"${nic_conf}\""
456 #add to managed list
457 [[ "${nic_conf}" == "dhcp" ]] && nic_managed="${nic_managed} ${nic_name}"
458 [[ "${nic_conf}" == "null" ]] && nic_unmanaged="${nic_unmanaged} ${nic_name}"
459 [[ -z "${nic_hwaddr}" && ${nic_type} == "veth" ]] && nic_wo_hwaddr="${nic_wo_hwaddr} ${nic_name}"
460 nic_writed=1
461 }
462
463 #Analyse lxc.conf and print conf.d/net content
464 container_conf_net()
465 {
466 local file=${1}
467 [[ -z "${nic_last}" ]] && nic_last=-1
468 [[ -z "${nic_named}" ]] && nic_named=0
469 OLDIFS=$IFS
470 IFS="
471 "
472 #I'll drink champagne the day we do templates in python
473 #let's do some drity bash things
474 for line in $( sed -r "s/[ ]*=[ ]*/_real_ugly_sep_42_/" "${file}" ); do
475 key=$(echo "${line}" | sed 's/_real_ugly_sep_42_.*$//')
476 value=$(echo "${line}" | sed 's/^.*_real_ugly_sep_42_//')
477
478 #new nic !
479 if [[ "${key}" == "lxc.network.type" ]]; then
480 #we don't know what to do with it.
481 [[ "${value}" == "empty" ]] && continue
482
483 #write conf from previous loops
484 [[ "${nic_writed}" == "0" ]] && nic_write
485
486 #init defaults
487 let nic_last=nic_last+1
488
489 nic_writed=0
490 #if 1 named between 2 not named: last is eth1
491 #=> Number is ID munis number of named NIC before
492 nic_name="eth$(( ${nic_last} - ${nic_named} ))"
493 nic_conf="dhcp"
494 nic_type="${value}"
495 fi
496
497 if [[ "${key}" == "lxc.network.hwaddr" ]]; then
498 nic_hwaddr=1
499 fi
500
501 if [[ "${key}" =~ ^lxc.network.ipv(4|6) ]]; then
502 #tell openrc to not manage this NIC as LXC set there address
503 nic_conf="null"
504 fi
505 if [[ "${key}" =~ ^lxc.network.name ]]; then
506 nic_name="${value}"
507 let nic_named=nic_named+1
508 fi
509 if [[ "${key}" == "lxc.include" ]]; then
510 #recursive into include
511 container_conf_net "${value}"
512 fi
513 done
514 #write conf from previous loops
515 [[ "${nic_writed}" == "0" ]] && nic_write
516 IFS=$OLDIFS
517 }
518
519 container_net()
520 {
521 printf "container_net(): setting container network conf... \n"
522
523 #Analyse network configuration in config
524 container_conf_net "$path/config" >> "${rootfs}/etc/conf.d/net"
525
526 # found how much nic finaly have
527 nic_count=$(( ${nic_last} + 1 ))
528
529 # unless openrc manage a nic, we now have to force openrc to automatic
530 # provision of the 'net' dep. If we do not, network dependent services
531 # will fail to load
532 if [[ -z "${nic_managed}" ]]; then
533 #tell openrc that lxc already did the work
534 echo 'rc_provide="net"' >> "$CACHE/etc/rc.conf"
535 fi
536
537 #No NIC ?
538 if [[ ${nic_count} == 0 ]]; then
539 #If no Nic, no need to continue
540 bridge=$(brctl show | awk 'NR==2 {print $1}')
541 if [[ "${bridge}" != "" ]]; then
542 store_user_message "No network interface for this container
543 It's a pitty, you have bridge, ${bridge}.
544 If it is for Lxc, use it next time by adding this to your default.conf :
545 lxc.network.type = veth
546 lxc.network.link = ${bridge}
547 lxc.network.flags = up
548 lxc.network.hwaddr = fe:xx:xx:xx:xx:xx"
549 return 0
550 else
551 store_user_message "No network interface for this container"
552 return 0
553 fi
554 fi
555
556 #For each openrc managed nic, activate
557 for nic in ${nic_managed}
558 do
559 chroot "${rootfs}" ln -s net.lo "/etc/init.d/net.${nic}"
560 chroot "${rootfs}" rc-update add net.${nic} default
561 done
562
563 #Warn about dynamic hwaddr
564 if [[ -n "${nic_wo_hwaddr}" ]]; then
565 store_user_message "Warning, these veth NIC don't have fixed hwaddr :
566 ${nic_wo_hwaddr}
567
568 see http://lists.linuxcontainers.org/pipermail/lxc-devel/2013-December/006736.html
569 and man lxc.conf"
570 fi
571
572 printf " => network conf done.\n"
573 }
574
575 # custom hostname
576 container_hostname()
577 {
578 printf "#### container_hostname(): setting hostname... \n"
579 printf "hostnale=%s\n" "${name}" > "${rootfs}/etc/conf.d/hostname"
580 printf " => done.\n"
581 }
582
583 container_auth()
584 {
585 printf "#### container_auth(): setting authentification... \n"
586 if [[ "${user}" != "root" ]]; then
587 printf " non root user requested, creating... \n"
588 chroot "${rootfs}" useradd --create-home -s /bin/bash "${user}" || die 1 "failed to create user ${user}"
589 printf " => user %s created\n" "${user}"
590 fi
591 store_user_message "Connection user is ${user}"
592 #Home of user
593 auth_home=$(chroot "${rootfs}" getent passwd "${user}" | cut -d : -f 6)
594 if [[ -r "${auth_key}" ]]; then
595 printf " deploying auth_key %s for user %s ...\n" "${auth_key}" "${user}"
596 mkdir -p "${rootfs}/${auth_home}/.ssh"
597 cat >> "${rootfs}/${auth_home}/.ssh/authorized_keys"
598 chroot "${rootfs}" chown "${user}:" "${auth_home}/.ssh/authorized_keys"
599 printf " => inserted public key in %s/.ssh/authorized_keys\n" "${auth_home}"
600 [[ -z "${forced_password}" ]] && unset password
601 store_user_message "${user} has the ssh key you gived us"
602 fi
603
604 if [[ -n "${password}" ]]; then
605 printf " setting password for %s ...\n" "${user}"
606 echo "${user}:${password}" | chroot "${rootfs}" chpasswd || die 1 "failed to change password"
607 printf " => done. if you didn't specify , default is 'toor'\n"
608 if [[ -n "${forced_password}" ]]; then
609 store_user_message "${user} has the password you give for him"
610 else
611 store_user_message "${user} has the default password 'toor', please change it ASAP"
612 fi
613 fi
614
615 printf " => done.\n"
616 }
617
618 ################################################################################
619 # lxc configuration files
620 ################################################################################
621
622 container_conf()
623 {
624 printf "container_configuration(): making lxc configuration file... \n"
625
626 #at this point if there
627 conf_file="${path}/config"
628
629 if grep -q "^lxc.rootfs" "${conf_file}" ; then
630 #lxc-create already provided one
631 conf_rootfs_line=""
632 else
633 conf_rootfs_line="lxc.rootfs = $(readlink -f "${rootfs}")"
634 fi
635 if [[ "${arch}" == "x86" || "${arch}" == "amd64" ]]; then
636 local conf_arch_line="lxc.arch = ${arch}"
637 else
638 local conf_arch_line="# lxc.arch = ${arch}"
639 fi
640
641 conf_lxc_cap_drop="sys_module mac_admin mac_override mknod sys_time"
642 conf_sysfs="lxc.mount.entry=sys sys sysfs defaults 0 0"
643
644 #more aggressive configuration, for your safety. But less things may work
645 if [ -n "${more_secure}" ]; then
646 conf_lxc_cap_drop="${conf_lxc_cap_drop} audit_control audit_write dac_read_search fsetid ipc_owner linux_immutable setfcap sys_admin sys_boot sys_pacct sys_ptrace sys_rawio sys_resource sys_tty_config syslog"
647 conf_sysfs="# disabled for security, see http://blog.bofh.it/debian/id_413
648 #lxc.mount.entry=sys sys sysfs defaults 0 0"
649 fi
650
651 cat <<- EOF >> "${conf_file}"
652 # sets container architecture
653 # If desired architecture != amd64 or x86, then we leave it unset as
654 # LXC does not oficially support anything other than x86 or amd64.
655 ${conf_arch_line}
656
657 # console access
658 lxc.tty = ${tty}
659 lxc.pts = 1024
660
661 # set the hostname
662 lxc.utsname = ${name}
663
664 ${conf_rootfs_line}
665 ${portage_mount}
666 ${conf_sysfs}
667
668 # this part is based on 'linux capabilities', see: man 7 capabilities
669 # eg: you may also wish to drop 'cap_net_raw' (though it breaks ping)
670 #
671 # WARNING: the security vulnerability reported for 'cap_net_admin' at
672 # http://mainisusuallyafunction.blogspot.com/2012/11/attacking-hardened-linux-systems-with.html
673 # via JIT spraying (the BPF JIT module disabled on most systems was used
674 # in the example, but others are suggested vulnerable) meant that users
675 # with root in a container, that capability and kernel module may escape
676 # the container. ALWAYS be extremely careful granting any process root
677 # within a container, use a minimal configuration at all levels -
678 # including the kernel - and multiple layers of security on any system
679 # where security is a priority. note that not only LXC but PAX (and
680 # others?) were vulnerable to this issue.
681 #
682 # conservative: lxc.cap.drop = sys_module mknod mac_override sys_boot
683 # aggressive follows. (leaves open: chown dac_override fowner ipc_lock kill lease net_admin net_bind_service net_broadcast net_raw setgid setuid sys_chroot)
684 # lxc.cap.drop = audit_control audit_write dac_read_search fsetid ipc_owner linux_immutable mac_admin mac_override mknod setfcap sys_admin sys_boot sys_module sys_pacct sys_ptrace sys_rawio sys_resource sys_time sys_tty_config syslog
685
686 lxc.cap.drop = ${conf_lxc_cap_drop}
687
688 ${conf_mounts}
689
690 # deny access to all devices by default, explicitly grant some permissions
691 #
692 # format is [c|b] [major|*]:[minor|*] [r][w][m]
693 # ^ ^ ^
694 # char/block -' \`- device number \`-- read, write, mknod
695 #
696 # first deny all...
697 lxc.cgroup.devices.deny = a
698 # /dev/null and zero
699 lxc.cgroup.devices.allow = c 1:3 rw
700 lxc.cgroup.devices.allow = c 1:5 rw
701 # /dev/{,u}random
702 lxc.cgroup.devices.allow = c 1:9 rw
703 lxc.cgroup.devices.allow = c 1:8 r
704 # /dev/pts/*
705 lxc.cgroup.devices.allow = c 136:* rw
706 lxc.cgroup.devices.allow = c 5:2 rw
707 # /dev/tty{0,1}
708 lxc.cgroup.devices.allow = c 4:1 rwm
709 lxc.cgroup.devices.allow = c 4:0 rwm
710 # /dev/tty
711 lxc.cgroup.devices.allow = c 5:0 rwm
712 # /dev/console
713 lxc.cgroup.devices.allow = c 5:1 rwm
714 EOF
715 if [ -n "${nettun}" ]; then
716 cat <<- EOF >> "${conf_file}"
717 # /dev/net/tun
718 lxc.cgroup.devices.allow = c 10:200 rwm
719 EOF
720 fi
721 printf " => done.\n"
722 }
723
724 usage()
725 {
726 cat <<EOF
727 $1 -h|--help [-a|--arch <arch>] [-v|--variant <variant>] [-P|--private-portage] [--portage-dir <protagedir>] [-t|--tarball <stage3file>]
728 [-F|--flush-cache] [-c|--cache-only] [-u|--user <username>] [-w|--password <password>] [-S|--auth-key <keyfile>]
729 [-s|--more-secure] [-m|--mirror <gentoomirror>] [--tty <number>] [--nettun]
730
731 arch: the container architecture (e.g. amd64): defaults to host arch (currently: '${arch}')
732 If you choose one that needs emulation
733 tested: amd64, x86
734 You could try any other gentoo arch, why not...
735
736 variant: gentoo's Architecture variant as of dec 2013 : (currently: '${variant}')
737 for amd64 arch: amd64 (default), amd64-hardened+nomultilib, amd64-hardened, amd64-nomultilib, x32
738 for x86 arch: i686 (default), i486, i686-hardened
739 for arm arch: armv7a (default), armv7a_hardfp, armv6j, armv6j_hardfp, armv5tel, armv4tl
740
741 private-portage: by default, /usr/portage is mount-binded with host one if exists (currently: '${private_portage}')
742 this force container to have his own copy
743
744 portage-dir: portage dir used for shared portage
745 by default the host on if any (currently: '${portage_dir}')
746
747 tarball: force usage of local stage3 archive (currently: '${arch}')
748 If empty, latest will be downloaded
749
750 flush-cache: do like there is no previous cache
751
752 cache-only: just ensure cache is present
753 if cache exists and "flush-cache" not specified, does nothing
754
755 user: user used in auth oriented options (currently: '${user}')
756
757 password: password for user (currently: '${password}')
758 if default, usage of auth-key will disable password setting
759
760 autologin: enable autologin for user (currently: '${autologin}')
761 This unset default password setting
762
763 auth-key: SSH Public key file to inject into container for user (currently: '${auth_key}')
764 This unset default password setting
765
766 more-secure: does some additional security agressive settings (may prevent things to run) (currently: '${more_secure}')
767
768 mirror: gentoo mirror for download (currently: '${mirror}')
769
770 tty: number of tty (6 max) (currently: '${tty}')
771
772 nettun: enable creation of /dev/net/tun (for private container VPN) (currently: '${nettun}')
773 EOF
774 exit 0
775 }
776
777 #some overridable defaults
778 set_default_arch
779
780 mirror="http://distfiles.gentoo.org"
781 user="root"
782 password="toor"
783 tty=0
784 options=$(getopt -o hp:n:a:FcPv:t:S:u:w:sm: -l help,rootfs:,path:,name:,arch:,flush-cache,cache-only,private-portage,variant:,portage-dir:,tarball:,auth_key:,user:,autologin,password:,more-secure,mirror:,tty:,nettun -- "$@")
785
786 eval set -- "$options"
787
788 while true
789 do
790 case "$1" in
791 -h|--help) usage $0 && exit 0;;
792 --rootfs) rootfs=$2; shift 2;;
793 -p|--path) path=$2; shift 2;;
794 -n|--name) name=$2; shift 2;;
795 -a|--arch) arch=$2; shift 2;;
796 -F|--flush-cache) flush_cache=1; shift 1;;
797 -c|--cache-only) cache_only=1; shitf 1;;
798 -P|--private-portage) private_portage=1; shift 1;;
799 -v|--variant) variant=$2; shift 2;;
800 --portage-dir) portage_dir=$2; shift 2;;
801 -t|--tarball) tarball=$2; shift 2;;
802 -S|--auth-key) auth_key=$2; shift 2;;
803 -u|--user) user=$2; shift 2;;
804 -w|--password) forced_password=1; password=$2; shift 2;;
805 -s|--more-secure) more_secure=1; shift 1;;
806 -m|--mirror) mirror=$2; shift 2;;
807 --nettun) nettun=1; shift 1;;
808 --tty) [[ $2 -lt 6 ]] && tty=$2; shift 2;;
809 --autologin) autologin=1; shift 1;;
810 --) shift 1; break ;;
811 *) break ;;
812 esac
813 done
814
815 cacheroot="@LOCALSTATEDIR@/cache/lxc/gentoo"
816 portage_cache="${cacheroot}/portage.tbz"
817 cachefs="${cacheroot}/rootfs-${arch}-${variant}"
818
819 alias wget="wget --timeout=8 --read-timeout=15 -c -t10 -nd"
820
821 do_all() {
822 cache_setup
823 if [ -z "${cache_only}" ]; then
824 container_setup
825 fi
826 }
827
828 execute_exclusively "cache-${arch}-${variant}" 60 do_all