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