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