VM feature: improve sed command line to replace root=... kernel option
[grml-debootstrap.git] / chroot-script
1 #!/bin/sh
2 # Filename:      /etc/debootstrap/chroot-script
3 # Purpose:       script executed in chroot when installing Debian via grml-debootstrap
4 # Authors:       grml-team (grml.org), (c) Michael Prokop <mika@grml.org>
5 # Bug-Reports:   see http://grml.org/bugs/
6 # License:       This file is licensed under the GPL v2.
7 ################################################################################
8
9 . /etc/debootstrap/config    || exit 1
10 . /etc/debootstrap/variables || exit 1
11
12 [ -r /proc/1 ] || mount -t proc none /proc
13
14 # variable checks {{{
15
16 # use aptitude only if it's available
17 if [ -x /usr/bin/aptitude ] ; then
18    APTINSTALL="aptitude -y --without-recommends install $DPKG_OPTIONS"
19    APTUPDATE='aptitude update'
20    APTUPGRADE='aptitude -y safe-upgrade'
21 else
22    APTINSTALL="apt-get --force-yes -y --no-install-recommends install $DPKG_OPTIONS"
23    APTUPDATE='apt-get update'
24    APTUPGRADE='apt-get --force-yes -y upgrade'
25 fi
26
27 if [ -z "$STAGES" ] ; then
28    STAGES='/etc/debootstrap/stages'
29    [ -d "$STAGES" ] || mkdir -p "$STAGES"
30 fi
31 # }}}
32
33 # helper functions {{{
34 stage() {
35   if [ -n "$2" ] ; then
36      echo "$2" > "$STAGES/$1"
37      return 0
38   elif grep -q done "$STAGES/$1" 2>/dev/null ; then
39      echo "   [*] Notice: stage $1 has been executed already, skipping execution therefore.">&2
40      return 1
41   fi
42   echo "   Executing stage ${1}"
43   return 0
44 }
45
46 askpass() {
47   # read -s emulation for dash. result is in $resp.
48   set -o noglob
49   stty -echo
50   read resp
51   stty echo
52   set +o noglob
53 }
54 # }}}
55
56 # define chroot mirror {{{
57 chrootmirror() {
58   if [ -n "$KEEP_SRC_LIST" ] ; then
59     echo "KEEP_SRC_LIST has been set, skipping chrootmirror stage."
60     return
61   fi
62
63   if [ -z "$COMPONENTS" ] ; then
64     COMPONENTS='main contrib non-free'
65   fi
66   echo "Using repository components $COMPONENTS"
67
68   if [ -n "$ISO" ] ; then
69     echo "Adjusting sources.list for ISO (${ISO})."
70     echo "deb $ISO $RELEASE $COMPONENTS" > /etc/apt/sources.list
71     echo "Adding mirror entry (${MIRROR}) to sources.list."
72     [ -n "$MIRROR" ] && echo "deb $MIRROR $RELEASE $COMPONENTS" >> /etc/apt/sources.list || true
73   else
74     if [ -n "$MIRROR" ] ; then
75       echo "Adjusting sources.list for mirror (${MIRROR})."
76       echo "deb $MIRROR $RELEASE $COMPONENTS" > /etc/apt/sources.list
77     fi
78   fi
79
80   # add security.debian.org:
81   case "$RELEASE" in
82     unstable|sid) ;;  # no security pool available
83     *)
84       echo "Adding security.debian.org to sources.list."
85       echo "deb http://security.debian.org ${RELEASE}/updates $COMPONENTS" >> /etc/apt/sources.list
86       ;;
87   esac
88 }
89 # }}}
90
91 # set up grml repository {{{
92 grmlrepos() {
93   if [ -n "$GRMLREPOS" ] ; then
94      # user might have provided their own apt sources.list
95      if ! grep -q grml /etc/apt/sources.list.d/grml.list 2>/dev/null ; then
96         cat >> /etc/apt/sources.list.d/grml.list << EOF
97 # grml: stable repository:
98   deb     http://deb.grml.org/ grml-stable  main
99   deb-src http://deb.grml.org/ grml-stable  main
100
101 # grml: testing/development repository:
102   deb     http://deb.grml.org/ grml-testing main
103   deb-src http://deb.grml.org/ grml-testing main
104 EOF
105      fi
106
107      if apt-get update ; then
108        apt-get -y --allow-unauthenticated install grml-debian-keyring
109        apt-get update
110      else
111        # make sure we have the keys available for aptitude
112        gpg --keyserver subkeys.pgp.net --recv-keys F61E2E7CECDEA787
113        gpg --export F61E2E7CECDEA787 | apt-key add - || true # not yet sure
114        # why it's necessary, sometimes we get an error even though it works [mika]
115      fi
116
117      # make sure we install packages from Grml's pool only if not available
118      # from Debian!
119      if ! grep -q grml /etc/apt/preferences 2>/dev/null ; then
120         cat >> /etc/apt/preferences << EOF
121 // debian pool (default):
122 Package: *
123 Pin: release o=Debian
124 Pin-Priority: 996
125
126 // main grml-repository:
127 Package: *
128 Pin: origin deb.grml.org
129 Pin-Priority: 991
130 EOF
131      fi
132   fi
133 }
134 # }}}
135
136 # set up kernel-img.conf {{{
137 kernelimg_conf() {
138   if ! [ -r /etc/kernel-img.conf ] ; then
139      echo "Setting up /etc/kernel-img.conf"
140      cat > /etc/kernel-img.conf << EOF
141 # Kernel Image management overrides
142 # See kernel-img.conf(5) for details
143 do_initrd = Yes
144 do_symlinks = Yes
145 EOF
146   fi
147 }
148 # }}}
149
150 # make sure services do not start up {{{
151 install_policy_rcd() {
152   if ! [ -r /usr/sbin/policy-rc.d ] ; then
153      export POLICYRCD=1
154      cat > /usr/sbin/policy-rc.d << EOF
155 #!/bin/sh
156 exit 101
157 EOF
158      chmod 775 /usr/sbin/policy-rc.d
159   fi
160 }
161 # }}}
162
163 # make sure we have an up2date system {{{
164 upgrade_system() {
165   if [ "$UPGRADE_SYSTEM" = "yes" ] ; then
166     echo "Running update + upgrade"
167     $APTUPDATE
168     $APTUPGRADE
169   else
170     echo "Not running update + upgrade as \$UPDATE_AND_UPGRADE is not set to 'yes'."
171   fi
172 }
173
174 # }}}
175 # remove now useless apt cache {{{
176 remove_apt_cache() {
177   if [ "$RM_APTCACHE" = 'yes' ] ; then
178     echo "Cleaning apt cache."
179     apt-get clean
180   else
181     echo "Not cleaning apt cache as \$RM_APTCACHE is unset."
182   fi
183 }
184 # }}}
185
186 # install additional packages {{{
187 packages() {
188   # Pre-seed the debconf database with answers. Each question will be marked
189   # as seen to prevent debconf from asking the question interactively.
190   [ -f /etc/debootstrap/debconf-selections ] && {
191     echo "Preseeding the debconf database, some lines might be skipped..."
192     cat /etc/debootstrap/debconf-selections | debconf-set-selections
193   }
194
195   if [ "$PACKAGES" = 'yes' ] ; then
196      if ! [ -r /etc/debootstrap/packages ] ; then
197        echo "Error: /etc/debootstrap/packages (inside chroot) not found, exiting." >&2
198        exit 1
199      else
200        $APTUPDATE
201        DEBIAN_FRONTEND=$DEBIAN_FRONTEND $APTINSTALL $(grep -v '^#' /etc/debootstrap/packages) $GRMLPACKAGES
202      fi
203   fi
204 }
205 # }}}
206
207 # install extra packages {{{
208 extrapackages() {
209     if [ "$EXTRAPACKAGES" = 'yes' ] ; then
210         PACKAGELIST=$(find /etc/debootstrap/extrapackages -type f -name '*.deb')
211         if [ -n "$PACKAGELIST" ]; then
212             dpkg -i $PACKAGELIST
213             # run apt again to resolve any deps
214             DEBIAN_FRONTEND=$DEBIAN_FRONTEND $APTINSTALL
215         fi
216     fi
217 }
218 # }}}
219
220 # install kernel packages {{{
221 kernel() {
222   # do not override $KERNEL if set via config file
223   if [ -z "$KERNEL" ] ; then
224      if [ "$ARCH" = 'i386' ] ; then
225         KERNEL='2.6-686'
226      elif [ "$ARCH" = 'amd64' ] ; then
227         KERNEL='2.6-amd64'
228      fi
229   fi
230
231   if [ -n "$KERNEL" ] ; then
232      $APTUPDATE
233      # note: install busybox to be able to debug initramfs
234      KERNELPACKAGES="linux-image-$KERNEL linux-headers-$KERNEL busybox firmware-linux"
235      DEBIAN_FRONTEND=$DEBIAN_FRONTEND $APTINSTALL $KERNELPACKAGES
236   fi
237 }
238 # }}}
239
240 # reconfigure packages {{{
241 reconfigure() {
242   if [ -n "$RECONFIGURE" ] ; then
243      for package in $RECONFIGURE ; do
244          if dpkg --list $package >/dev/null 2>&1 | grep -q '^ii' ; then
245            DEBIAN_FRONTEND=$DEBIAN_FRONTEND dpkg-reconfigure $package || \
246            echo "Warning: $package does not exist, can not reconfigure it."
247          fi
248      done
249   fi
250 }
251 # }}}
252
253 # set password of user root {{{
254 passwords()
255 {
256   if [ -n "$NOPASSWORD" ] ; then
257     echo "Skip setting root password as requested."
258     return 0
259   fi
260
261   echo "Activating shadow passwords."
262   shadowconfig on
263
264   CHPASSWD_OPTION=
265   if chpasswd --help 2>&1 | grep -q -- '-m,' ; then
266      CHPASSWD_OPTION='-m'
267   fi
268
269   if [ -n "$ROOTPASSWORD" ] ; then
270      echo root:"$ROOTPASSWORD" | chpasswd $CHPASSWD_OPTION
271      export ROOTPASSWORD=''
272   else
273     a='1'
274     b='2'
275      echo "Setting password for user root:"
276      while [ "$a" != "$b" ] ; do
277        echo -n "Enter new UNIX password for user root: "
278        askpass
279        a="$resp"
280        unset resp
281        echo
282        echo -n "Retype new UNIX password for user root: "
283        askpass
284        b="$resp"
285        unset resp
286        echo
287        if [ "$a" != "$b" ] ; then
288          echo "Sorry, passwords do not match. Retry."
289          a='1'
290          b='2'
291        else
292          echo root:"$a" | chpasswd $CHPASSWD_OPTION
293          unset a
294          unset b
295        fi
296      done
297   fi
298 }
299 # }}}
300
301 # set up /etc/hosts {{{
302 hosts() {
303   if [ -f /etc/hosts ] ; then
304      sed -i "s#127.0.0.1 .*#127.0.0.1       localhost  $HOSTNAME#" /etc/hosts
305      [ -n "$HOSTNAME" ] && sed -i "s/grml/$HOSTNAME/g" /etc/hosts
306   else
307      cat > /etc/hosts << EOF
308 127.0.0.1       localhost $HOSTNAME
309
310 #127.0.0.1       localhost
311 #127.0.1.1       $HOSTNAME.example.org $HOSTNAME
312
313 # The following lines are desirable for IPv6 capable hosts
314 #::1     ip6-localhost ip6-loopback $HOSTNAME
315 ::1     ip6-localhost ip6-loopback
316 fe00::0 ip6-localnet
317 ff00::0 ip6-mcastprefix
318 ff02::1 ip6-allnodes
319 ff02::2 ip6-allrouters
320 ff02::3 ip6-allhosts
321 EOF
322   fi
323 }
324 # }}}
325
326 # set up /etc/network/interfaces {{{
327 interfaces() {
328   if ! [ -r /etc/network/interfaces ] || ! grep -q "auto lo" /etc/network/interfaces ; then
329      echo "Setting up /etc/network/interfaces"
330      cat >> /etc/network/interfaces << EOF
331
332 # loopback device:
333 iface lo inet loopback
334 auto lo
335
336 # eth0:
337 # iface eth0 inet dhcp
338 # auto eth0
339
340 EOF
341   fi
342 }
343 # }}}
344
345 # adjust timezone {{{
346 timezone() {
347   if [ -n "$TIMEZONE" ] ; then
348      echo "Adjusting /etc/localtime"
349      ln -sf /usr/share/zoneinfo/$TIMEZONE /etc/localtime
350   fi
351 }
352 # }}}
353
354 # helper function for fstab() {{{
355 createfstab(){
356      echo "Setting up /etc/fstab"
357 if [ -n "$TARGET_UUID" ] ; then
358    echo "/dev/disk/by-uuid/${TARGET_UUID} /  auto    defaults,errors=remount-ro 0   1" > /etc/fstab
359 else
360    echo "${TARGET} /  auto    defaults,errors=remount-ro 0   1" > /etc/fstab
361 fi
362
363 cat >> /etc/fstab << EOF
364 proc           /proc        proc    defaults                      0   0
365 /dev/cdrom     /mnt/cdrom0  iso9660 ro,user,noauto                0   0
366 # some other examples:
367 # /dev/sda2       none         swap    sw,pri=0             0   0
368 # /dev/hda1       /Grml        ext3    dev,suid,user,noauto 0  2
369 # //1.2.3.4/pub   /smb/pub     smbfs   defaults,user,noauto,uid=grml,gid=grml 0 0
370 # linux:/pub      /beer        nfs     defaults             0  0
371 # tmpfs           /tmp         tmpfs   size=300M            0  0
372 # /dev/sda5       none         swap    sw                   0  0
373 EOF
374 }
375 # }}}
376
377 # generate /etc/fstab {{{
378 fstab() {
379   # set up /etc/fstab if file is not present (cdebootstrap)
380   if [ ! -f /etc/fstab  ] ; then
381      createfstab
382   fi
383
384   # set up /etc/fstab if file is UNCONFIGURED (debootstrap)
385   if grep -q UNCONFIGURED /etc/fstab ; then
386      createfstab
387   fi
388 }
389 # }}}
390
391 # set up hostname {{{
392 hostname() {
393   if [ -n "$HOSTNAME" ] ; then
394      echo "Setting hostname to ${HOSTNAME}."
395      echo "$HOSTNAME" > /etc/hostname
396
397      # adjust postfix configuration
398      if [ -r /etc/postfix/main.cf ] ; then
399         # adjust hostname related options:
400         sed -i "s/grml/$HOSTNAME/g" /etc/postfix/main.cf
401
402         # listen on loopback interface only:
403         sed -i "s/^inet_interfaces = .*/inet_interfaces = loopback-only/" /etc/postfix/main.cf
404         grep -q inet_interfaces /etc/postfix/main.cf || echo 'inet_interfaces = loopback-only' >> /etc/postfix/main.cf
405      fi
406   fi
407 }
408 # }}}
409
410 # generate initrd/initramfs {{{
411 initrd() {
412   # assume the first available kernel as our main kernel
413   KERNELIMG=$(ls -1 /boot/vmlinuz-* 2>/dev/null | head -1)
414   if [ -z "$KERNELIMG" ] ; then
415      echo 'No kernel image found, skipping initrd stuff.'>&2
416      return
417   fi
418
419   KERNELVER=${KERNELIMG#/boot/vmlinuz-}
420
421   # generate initrd
422   if [ -n "$INITRD" ] ; then
423      echo "Generating initrd."
424      update-initramfs -c -t -k $KERNELVER
425   fi
426 }
427 # }}}
428
429 # grub configuration/installation {{{
430 grub_install() {
431
432   if [ -z "$GRUB" ] ; then
433     echo "Notice: \$GRUB not defined, will not install grub inside chroot at this stage."
434     return 0
435   fi
436
437   if ! dpkg --list grub-pc 2>/dev/null | grep -q '^ii' ; then
438     echo "Notice: grub option set but no grub-pc package, installing it therefore."
439     DEBIAN_FRONTEND=$DEBIAN_FRONTEND $APTINSTALL grub-pc
440   fi
441
442   if ! [ -x "$(which grub-install)" ] ; then
443      echo "Error: grub-install not available. (Error while installing grub package?)" >&2
444      return 1
445   fi
446
447   if [ -n "$SELECTED_PARTITIONS" ] ; then # using sw-raid
448      for device in $SELECTED_PARTITIONS ; do
449         GRUB="${device%%[0-9]}"
450         echo "Installing grub on ${GRUB}:"
451         grub-install --no-floppy "$GRUB"
452      done
453   else
454      echo "Installing grub on ${GRUB}:"
455      grub-install --no-floppy "$GRUB"
456   fi
457
458   echo "Adjusting grub configuration for use on ${GRUB}."
459
460   # finally install grub
461   if [ -x /usr/sbin/update-grub ] ; then
462      UPDATEGRUB='/usr/sbin/update-grub'
463   elif [ -x /sbin/update-grub ] ; then
464      UPDATEGRUB='/sbin/update-grub'
465   else
466     echo "Error: update-grub not available, can not execute it." >&2
467     return 1
468   fi
469
470   $UPDATEGRUB
471 }
472 # }}}
473
474 # execute all scripts present in /etc/debootstrap/chroot-scripts/ {{{
475 custom_scripts() {
476   [ -d /etc/debootstrap/chroot-scripts/ ] || return 0
477
478   for script in /etc/debootstrap/chroot-scripts/* ; do
479       echo "Executing script $script"
480       $script && echo "done" || echo "failed"
481   done
482 }
483 # }}}
484
485 # make sure we don't have any running processes left {{{
486 services() {
487   for service in ssh mdadm mdadm-raid ; do
488     if [ -x /etc/init.d/"$service" ] ; then
489        /etc/init.d/"$service" stop || true
490     fi
491   done
492 }
493 # }}}
494
495 # unmount /proc and make sure nothing is left {{{
496 finalize() {
497   # make sure we don't leave any sensible data
498   rm -f /etc/debootstrap/variables
499
500   [ -n "$POLICYRCD" ] && rm -f /usr/sbin/policy-rc.d
501
502   umount /proc >/dev/null 2>/dev/null || true
503 }
504 # }}}
505
506 # signal handler {{{
507 signal_handler() {
508   finalize
509   [ -n "$1" ] && EXIT="$1" || EXIT="1"
510   exit "$EXIT"
511 }
512 # }}}
513
514 # set signal handler {{{
515 trap signal_handler HUP INT QUIT TERM
516 # }}}
517
518 # execute the functions {{{
519
520  # always execute install_policy_rcd
521  install_policy_rcd
522
523  for i in chrootmirror grmlrepos kernelimg_conf \
524      kernel packages extrapackages  reconfigure hosts interfaces \
525      timezone fstab hostname initrd grub_install passwords        \
526      custom_scripts upgrade_system remove_apt_cache services ; do
527      if stage $i ; then
528        $i && stage $i done || exit 1
529      fi
530   done
531   # always execute the finalize stage:
532   finalize
533 # }}}
534
535 # finally exit the chroot {{{
536   echo "Finished chroot installation, exiting."
537   exit 0
538 # }}}
539
540 ## END OF FILE #################################################################
541 # vim: ai tw=80 expandtab foldmethod=marker