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