Support template parameters in overlay directory. For now only
[grml2usb.git] / grml2iso
1 #!/usr/bin/env bash
2 # Filename:      grml2iso
3 # Purpose:       create a multiboot grml ISO using grml2usb
4 # Authors:       Michael Prokop <mika@grml.org>,
5 #                Thorsten Glaser <tg@mirbsd.org>
6 # Bug-Reports:   see http://grml.org/bugs/
7 # License:       This file is licensed under the GPL v2 or any later version.
8 ################################################################################
9
10 # define function getfilesize before "set -e" {{{
11   if stat --help >/dev/null 2>&1; then
12     getfilesize='stat -c %s'        # GNU stat
13   else
14     getfilesize='stat -f %z'        # BSD stat
15   fi
16 # }}}
17
18 # adjust variables if necessary through environment {{{
19 # path to the grml2usb script you'd like to use
20   [ -n "$GRML2USB" ] || GRML2USB='grml2usb'
21 # work directory for creating the filesystem
22   [ -n "$WRKDIR" ]   || WRKDIR='/tmp/grml2iso.tmp'
23 # support mkisofs as well as genisoimage
24 if which xorriso >/dev/null 2>&1 ; then
25   MKISOFS='xorriso -as mkisofs'
26 elif which mkisofs >/dev/null 2>&1; then
27   MKISOFS='mkisofs'
28 elif which genisoimage >/dev/null 2>&1; then
29   MKISOFS='genisoimage'
30 else
31   echo >&2 "Error: neither mkisofs nor genisoimage available - can not create ISO."
32   exit 1
33 fi
34 # }}}
35
36 # helper stuff {{{
37   set -e
38
39   usage() {
40     echo >&2 "Usage: $0 [OPTIONS] -o target.iso source1.iso [source2.iso ...]"
41     echo >&2 "
42 Options:
43      -b Boot Params      Additional boot parameters passed to grml2usb
44      -c Directory        Copy files from directory to generated ISO
45      -f                  Force overwrite of existing target.iso
46      -r BootParam        Remove specified boot params.
47                          Could be specfied multiple times.
48      -p <grml2usb param> Add the specified parameter to the grml2usb
49                          commandline. For a list of valid parameters have
50                          a look at the grml2usb manpage.
51                          Can be specified multiple times.
52      -s URI              Generate a small ISO file which downloads the squashfs
53                          file from the specified URI. Please note that due to
54                          restrictions in the bootprocess only IPs are allowed.
55                          Supported protocols are: http and ftp
56
57      Examples:
58      $0 -s http://192.168.23.42:8000/grml/ -o small.iso grml64_2010.12.iso
59
60      Will generate a file small.iso which tries to download the squashfs file from
61      http://192.168.23.42:8000/grml/ - the squashfs file is placed in the same
62      output directory as the ISO file.
63 "
64     [ -n "$1" ] && exit $1 || exit 1
65   }
66 # }}}
67
68 # command line handling {{{
69   [[ $# -gt 2 ]] || usage 1
70
71   ISOFILE=''
72   DIR=''
73   ADD_OPTS=''
74   FORCE=''
75   URI=''
76   typeset -a GRML2USB_OPTS
77   while getopts fb:c:o:r:p:s: name; do
78     case $name in
79       o)   ISOFILE="$OPTARG";;
80       b)   GRML2USB_OPTS+=(--bootoptions="$OPTARG");;
81       c)   DIR="$(readlink -f "$OPTARG")";;
82       f)   FORCE='true';;
83       r)   GRML2USB_OPTS+=(--remove-bootoption="$OPTARG");;
84       p)   GRML2USB_OPTS+=("$OPTARG");;
85       s)   URI="$OPTARG";;
86       ?)   usage 2;;
87     esac
88   done
89   # test for specified URI
90   if [ -n "$URI" ] ; then
91     GRML2USB_OPTS+=(--bootoptions="fetch=$URI")
92   fi
93
94 # make sure -o is specified
95   [ -n "$ISOFILE" ] || usage 1
96
97 # we don't to override any files by accident
98   if [ -e "$ISOFILE" -a ! -n "$FORCE" ]; then
99     echo "Error: target file $ISOFILE exists already." >&2
100     exit 1
101   fi
102
103   if [ ! -z "$DIR" -a ! -d "$DIR" ] ; then
104      echo "Error: specified parameter for -c is not a directory" >&2
105      exit 1
106   fi
107 # }}}
108
109 # we need root permissions for executing grml2usb {{{
110   if [[ $(id -u) != 0 ]]; then
111     echo >&2 "Error: please run $0 as root."
112     exit 1
113   fi
114 # }}}
115
116 # check for grml2usb {{{
117   if [ ! -x "$(which $GRML2USB)" ] && [ ! -x "$GRML2USB" ] ; then
118     echo >&2 "Error: Could not find grml2usb"
119     if [ -x "./$GRML2USB" ] ; then
120       echo >&2 "If you executed grml2iso from the grml2usb repository use"
121       echo >&2 "GRML2USB=./grml2usb $0 $*"
122     fi
123     exit 1
124   fi
125 # }}}
126
127 # variables {{{
128   ORIG_DIR="$(pwd)"
129
130 # normalise path
131   case $ISOFILE in
132     /*) ;;
133     *) ISOFILE=$ORIG_DIR/$ISOFILE ;;
134   esac
135 # }}}
136
137 # create necessary stuff under WRKDIR {{{
138   [ -d "$WRKDIR" ] && WRKDIR_EXISTED='true' || WRKDIR_EXISTED='false'
139   rm -rf "$WRKDIR/cddir" "$WRKDIR/grub_tmp"
140   mkdir -p "$WRKDIR/cddir"
141 # }}}}
142
143 # execute grml2usb with all ISOs you'd like to install {{{
144   # remove all parameters
145   shift $(($OPTIND - 1))
146
147   $GRML2USB "${GRML2USB_OPTS[@]}" "$@" "$WRKDIR/cddir"
148 # }}}
149
150 # move syslinux to isolinux {{{
151   mv "$WRKDIR"/cddir/boot/syslinux "$WRKDIR"/cddir/boot/isolinux
152
153   cd "$WRKDIR/cddir"
154   echo "menu label ^Isolinux prompt" > boot/isolinux/promptname.cfg
155   echo "include hd.cfg" >> boot/isolinux/grmlmain.cfg
156 # }}}
157
158 # efi boot {{{
159   # default, independent of UEFI support
160   BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
161
162   case "$MKISOFS" in
163     xorriso*)
164       echo "Using xorriso for ISO generation."
165       if ! dpkg --compare-versions $(dpkg-query -W -f='${Version}\n' xorriso 2>/dev/null) gt-nl 1.1.6-1 ; then
166         echo "Disabling (U)EFI boot support since xorriso version is not recent enough."
167       else
168         echo "xorriso with -eltorito-alt-boot support present"
169
170         if ! [ -r "${WRKDIR}/cddir/boot/efi.img" ] ; then
171           echo "File /boot/efi.img not found, not extending boot arguments for (U)EFI boot."
172         else
173           echo "/boot/efi.img found, extending boot arguments for (U)EFI boot."
174           BOOT_ARGS="$BOOT_ARGS -boot-info-table -eltorito-alt-boot -e boot/efi.img -no-emul-boot"
175         fi
176       fi
177       ;;
178   esac
179 # }}}
180
181 # adjust ISO for small output if necessary {{{
182   if [ -n "$URI" ] ; then
183      bootloader_files=$(find . -name "*.cfg" -type f)
184      bootloader_files+=" "
185      bootloader_files+=$(find . -name "*.lst" -type f)
186      output_dir=$(dirname "$ISOFILE")
187      for squashfs in $(find . -name *.squashfs) ; do
188         media_path="$(dirname "$squashfs")"
189         filename="$(basename "$squashfs")"
190         target="$output_dir/$filename"
191         if [ -f "$target" ] && [ ! -n "$FORCE" ] ; then
192            echo >&2 "Warning: $target already exists, and -force not specified, not overwriting"
193         else
194            mv $squashfs $target
195            OUTPUT_FILES+=("$target")
196         fi
197         sed -i -e "s#^\(^.*$media_path.*\)\($URI\)\(.*$\)#\1$URI/$filename\3#g" $bootloader_files
198
199    done
200   fi
201 # }}}
202
203 # copy specified directory to cd {{{
204   if [ -n "$DIR" ] ; then
205      echo >&2 "Copying ${DIR} to generated ISO"
206      for param in SHORT_NAME VERSION BOOTID ; do
207        EXCLUDE_PARAM="$EXCLUDE_PARAM --exclude **%${param}%**"
208      done
209      rsync -a ${DIR}/ $EXCLUDE_PARAM .
210   fi
211
212   # adjust files from overlay directory
213   for GRML_VERSION_FILE in $(find . -name grml-version) ; do
214     GRML_NAME=$(awk '{print $1}' "$GRML_VERSION_FILE")
215     VERSION=$(awk '{print $2}' "$GRML_VERSION_FILE")
216     RELEASENAME=$(sed 's/.*- \(.*\).*\[.*/\1/' "$GRML_VERSION_FILE")
217     DATE=$(sed 's/.*\[\(.*\)].*/\1/' "$GRML_VERSION_FILE")
218     SHORT_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
219     BOOTID=$(cat conf/bootid.txt)
220
221     for param in SHORT_NAME VERSION BOOTID ; do
222       value="$(eval echo '$'"$param")"
223
224       # copy parameterized files from the overlay directory
225       for file in $(find ${DIR} -name "*%$param%*") ; do
226         file=${file##$DIR/}
227         target_dir="$(dirname ${file})"
228         mkdir -p "$target_dir" || true
229         cp -r ${DIR}/${file} ./${target_dir}/"$(basename ${file/\%${param}\%/$value})"
230       done
231
232       # adjust config files
233       for file in ./boot/isolinux/*.cfg ./boot/isolinux/*.msg \
234         ./boot/grub/*.cfg ; do
235         sed -i "s/%$param%/$value/g" ${file} 2>/dev/null || true
236       done
237     done
238   done
239 # }}}
240
241 # generate the CD/DVD ISO {{{
242   $MKISOFS -V 'grml-multiboot' -l -r -J -no-pad $BOOT_ARGS \
243     -o "$ISOFILE" .
244 # }}}
245
246 # pad the output ISO to multiples of 256 KiB for partition table support {{{
247   siz=$($getfilesize "$ISOFILE")
248   cyls=$(echo "$siz / 512 / 32 / 16 + 1" | bc)  # C=$cyls H=16 S=32
249   ofs=$(echo "$cyls * 16 * 32 * 512 - 1" | bc)  # padding offset (size - 1)
250   dd if=/dev/zero bs=1 count=1 seek=$ofs of="$ISOFILE" 2>/dev/null
251 # }}}
252
253 # cleanup {{{
254   cd "$ORIG_DIR"
255   sync
256   rm -rf "$WRKDIR/cddir" "$WRKDIR/grub_tmp"
257   [[ $WRKDIR_EXISTED = 'false' ]] && rmdir "$WRKDIR"
258   echo "Generated $ISOFILE"
259   if [ -n "$URI" ] ; then
260      echo "
261 Information:
262 ==============
263 You requested to generate a small ISO image. Your generated
264 ISO image $ISOFILE does _not_ contain the squashfs files from
265 the source ISO images.
266
267 You have to provide the extracted squashfs files under $URI.
268
269 ISO image: $ISOFILE
270 Squashfs files: ${OUTPUT_FILES[@]}
271 URI: $URI
272 "
273   fi
274 # }}}
275
276 ## EOF #########################################################################
277 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=3