Github action: do not install virtualenv + python3-setuptools
[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 # make sure we have the sbin directories in our PATH to find grml2usb ootb
10 PATH="${PATH}:/sbin:/usr/local/sbin:/usr/sbin"
11
12 # adjust variables if necessary through environment {{{
13 # path to the grml2usb script you'd like to use
14   [ -n "$GRML2USB" ] || GRML2USB='grml2usb'
15 # work directory for creating the filesystem
16   [ -n "$TMPDIR" ]   && WRKDIR="${TMPDIR}/grml2iso.tmp"
17   [ -n "$WRKDIR" ]   || WRKDIR='/tmp/grml2iso.tmp'
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   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                          Can be specified 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      -t Directory        Directory that should be used for temporary files
57                          during build. Defaults to /tmp/grml2iso.tmp if unset.
58
59      Examples:
60      $0 -s http://192.168.23.42:8000/grml/ -o small.iso grml64-small_2018.12.iso 
61
62      Will generate a file small.iso which tries to download the squashfs file from
63      http://192.168.23.42:8000/grml/ - the squashfs file is placed in the same
64      output directory as the ISO file.
65 "
66     [ -n "$1" ] && exit $1 || exit 1
67   }
68 # }}}
69
70 # command line handling {{{
71   [[ $# -gt 2 ]] || usage 1
72
73   ISOFILE=''
74   DIR=''
75   ADD_OPTS=''
76   FORCE=''
77   URI=''
78   typeset -a GRML2USB_OPTS
79   while getopts fb:c:o:r:p:s:t: name; do
80     case $name in
81       o)   ISOFILE="$OPTARG";;
82       b)   GRML2USB_OPTS+=(--bootoptions="$OPTARG");;
83       c)   DIR="$(readlink -f "$OPTARG")"; [ -n "$DIR" ] || { echo "Could not read $OPTARG - exiting" >&2 ; exit 1 ; } ;;
84       f)   FORCE='true';;
85       r)   GRML2USB_OPTS+=(--remove-bootoption="$OPTARG");;
86       p)   GRML2USB_OPTS+=("$OPTARG");;
87       s)   URI="$OPTARG";;
88       t)   WRKDIR="$(readlink -f "$OPTARG")";;
89       ?)   usage 2;;
90     esac
91   done
92
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 "Error: Could not find grml2usb executable. Is /usr/sbin missing in PATH?" >&2
127     echo "Tip: run GRML2USB=/usr/sbin/grml2usb grml2iso ... as workaround" >&2
128     if [ -x "./$GRML2USB" ] ; then
129       echo >&2 "If you executed grml2iso from the grml2usb repository use"
130       echo >&2 "GRML2USB=./grml2usb $0 $*"
131     fi
132     exit 1
133   fi
134 # }}}
135
136 # variables {{{
137   ORIG_DIR="$(pwd)"
138
139 # normalise path
140   case $ISOFILE in
141     /*) ;;
142     *) ISOFILE=$ORIG_DIR/$ISOFILE ;;
143   esac
144 # }}}
145
146 # create necessary stuff under WRKDIR {{{
147   [ -d "$WRKDIR" ] && WRKDIR_EXISTED='true' || WRKDIR_EXISTED='false'
148   rm -rf "$WRKDIR/cddir" "$WRKDIR/grub_tmp"
149   mkdir -p "$WRKDIR/cddir"
150 # }}}}
151
152 # execute grml2usb with all ISOs you'd like to install {{{
153   # remove all parameters
154   shift $(($OPTIND - 1))
155
156   $GRML2USB "${GRML2USB_OPTS[@]}" "$@" "$WRKDIR/cddir"
157 # }}}
158
159 # move syslinux to isolinux {{{
160   mv "$WRKDIR"/cddir/boot/syslinux "$WRKDIR"/cddir/boot/isolinux
161   echo "menu label ^Isolinux prompt" > "$WRKDIR"/cddir/boot/isolinux/promptname.cfg
162   echo "include hd.cfg" >> "$WRKDIR"/cddir/boot/isolinux/grmlmain.cfg
163 # }}}
164
165 # change to $WRKDIR {{{
166   # make sure $WRKDIR is an absolute path, otherwise accessing files
167   # in it will fail later in the code path if user provided a
168   # relative directory
169   WRKDIR=$(realpath $WRKDIR)
170   cd "$WRKDIR/cddir"
171 # }}}
172
173 # efi boot {{{
174   # default, independent of UEFI support
175   BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
176   UEFI_ENABLE=false
177
178   case "$MKISOFS" in
179     xorriso*)
180       echo "Using xorriso for ISO generation."
181       if ! dpkg --compare-versions $(dpkg-query -W -f='${Version}\n' xorriso 2>/dev/null) gt-nl 1.1.6-1 ; then
182         echo "Disabling (U)EFI boot support since xorriso version is not recent enough."
183       else
184         echo "xorriso with -eltorito-alt-boot support present"
185         UEFI_ENABLE=true
186
187         if ! [ -r "${WRKDIR}/cddir/boot/efi.img" ] ; then
188           echo "Warning: File /boot/efi.img not found, not extending boot arguments for (U)EFI boot."
189           UEFI_ENABLE=false
190         else
191           echo "/boot/efi.img found, extending boot arguments for (U)EFI boot."
192           if ! [ -r /usr/lib/ISOLINUX/isohdpfx.bin ] ; then
193             echo "Error: /usr/lib/ISOLINUX/isohdpfx.bin not available, required for xorriso/isohybrid though." >&2
194             echo "Hint:  make sure isolinux is installed." >&2
195             exit 1
196           else
197             BOOT_ARGS+=" -boot-info-table -eltorito-alt-boot -e boot/efi.img -no-emul-boot"
198             BOOT_ARGS+=" -isohybrid-mbr /usr/lib/ISOLINUX/isohdpfx.bin -eltorito-alt-boot -e boot/efi.img -no-emul-boot -isohybrid-gpt-basdat -no-pad"
199           fi
200         fi
201       fi
202       ;;
203     *)
204       echo "Using $MKISOFS for ISO generation (lacking UEFI option), disabling (U)EFI boot support."
205       ;;
206   esac
207 # }}}
208
209 # adjust ISO for small output if necessary {{{
210   if [ -n "$URI" ] ; then
211      bootloader_files=$(find . -name "*.cfg" -type f)
212      bootloader_files+=" "
213      bootloader_files+=$(find . -name "*.lst" -type f)
214      output_dir=$(dirname "$ISOFILE")
215      for squashfs in $(find . -name *.squashfs) ; do
216         media_path="$(dirname "$squashfs")"
217         filename="$(basename "$squashfs")"
218         target="$output_dir/$filename"
219         if [ -f "$target" ] && [ ! -n "$FORCE" ] ; then
220            echo >&2 "Warning: $target already exists, and -force not specified, not overwriting"
221         else
222            mv $squashfs $target
223            OUTPUT_FILES+=("$target")
224         fi
225         sed -i -e "s#^\(^.*$media_path.*\)\($URI\)\(.*$\)#\1$URI/$filename\3#g" $bootloader_files
226
227    done
228   fi
229 # }}}
230
231 # copy specified directory to cd {{{
232   if [ -n "$DIR" ] ; then
233      echo >&2 "Copying ${DIR} to generated ISO"
234      for param in GRML_NAME VERSION RELEASENAME DATE SHORT_NAME \
235          VERSION BOOTID RELEASE_INFO ; do
236        EXCLUDE_PARAM="$EXCLUDE_PARAM --exclude **%${param}%**"
237      done
238      rsync -a ${DIR}/ $EXCLUDE_PARAM .
239   fi
240
241   # adjust files from overlay directory
242   for GRML_VERSION_FILE in $(find . -name grml-version) ; do
243     GRML_NAME=$(awk '{print $1}' "$GRML_VERSION_FILE")
244     VERSION=$(awk '{print $2}' "$GRML_VERSION_FILE")
245     RELEASENAME=$(sed 's/.*- \(.*\).*\[.*/\1/' "$GRML_VERSION_FILE")
246     DATE=$(sed 's/.*\[\(.*\)].*/\1/' "$GRML_VERSION_FILE")
247     SHORT_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
248     RELEASE_INFO="$GRML_NAME $VERSION - $RELEASENAME"
249     BOOTID=$(cat conf/bootid.txt)
250
251     for param in GRML_NAME VERSION RELEASENAME DATE SHORT_NAME \
252         RELEASE_INFO BOOTID  ; do
253       value="$(eval echo '$'"$param")"
254
255       # copy parameterized files from the overlay directory
256       for file in $(find ${DIR} -name "*%$param%*") ; do
257         file=${file##$DIR/}
258         target_dir="$(dirname ${file})"
259         mkdir -p "$target_dir" || true
260         cp -r ${DIR}/${file} ./${target_dir}/"$(basename ${file/\%${param}\%/$value})"
261       done
262
263       # adjust config files
264       for file in ./boot/isolinux/*.cfg ./boot/isolinux/*.msg \
265         ./boot/grub/*.cfg ; do
266         sed -i "s/%$param%/$value/g" ${file} 2>/dev/null || true
267       done
268     done
269   done
270 # }}}
271
272 # generate the CD/DVD ISO {{{
273   $MKISOFS -V 'grml-multiboot' -l -r -J $BOOT_ARGS \
274     -o "$ISOFILE" .
275 # }}}
276
277 # cleanup {{{
278   cd "$ORIG_DIR"
279   sync
280   rm -rf "$WRKDIR/cddir" "$WRKDIR/grub_tmp"
281   [[ $WRKDIR_EXISTED = 'false' ]] && rmdir "$WRKDIR"
282   echo "Generated $ISOFILE"
283   if [ -n "$URI" ] ; then
284      echo "
285 Information:
286 ==============
287 You requested to generate a small ISO image. Your generated
288 ISO image $ISOFILE does _not_ contain the squashfs files from
289 the source ISO images.
290
291 You have to provide the extracted squashfs files under $URI.
292
293 ISO image: $ISOFILE
294 Squashfs files: ${OUTPUT_FILES[@]}
295 URI: $URI
296 "
297   fi
298 # }}}
299
300 ## EOF #########################################################################
301 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=2