Zerocat’s Coreboot Machines  v0.10.0
How to create Zerocat’s Coreboot Machines like the ZC-X230 and others...
gen-payload-grub.sh File Reference

Third script to use. Pack the GRUB2 executable payload for platform i386-coreboot, generate required keymap layout files and code snippets. Generate configuration files as well. More...

Detailed Description

Third script to use. Pack the GRUB2 executable payload for platform i386-coreboot, generate required keymap layout files and code snippets. Generate configuration files as well.

Toolchain Script 3(4): “gen-payload-grub.sh”

Invocation Examples

./gen-payload-grub.sh --usage

./gen-payload-grub.sh --toolbox <folder> --clean-all --gen-snippets --pack-minimal

./gen-payload-grub.sh --toolbox <folder> --clean --gen-config

./gen-payload-grub.sh --toolbox <folder> --clean --gen-config --grub-keymap de --grub-nomorse --grub-nonvramcui --grub-nocoreinfo

./gen-payload-grub.sh --grub-background <image.png>

Description

With option --gen-snippets, this script will generate a rich set of *.gkb keyboard layout files and code snippets, which are required for the GRUB2 Payload. Besides the generation of executable GRUB payload files with options --pack and --pack-minimal, a GRUB configuration can be created in the same go with option --gen-config. Option --grub-background helps you to specify background images. Use with option --help or --usage to see detailed usage information.

Todo:
  • Allow to pass a list of desired keymap layouts via command line.
  • Add authentication support.

Script Code

#!/bin/bash
##>! @file
##>! @cond
#

# Zerocat Coreboot-Machines --- Create Zerocat Coreboot Images
#
# Copyright (C) 2019 Kai Mertens <kmx@posteo.net>
#
# The Zerocat Coreboot-Machines Project is free software: you can redistribute
# it and/or modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# The Zerocat Coreboot-Machines Project is distributed in the hope that it
# will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# This file is part of the Zerocat Coreboot-Machines Project.
#
# Purpose:
#   Generate grub exectable *.elf payload file for platform i386-coreboot.
#
# Usage:
#  ./gen-payload-grub.sh --usage
#

# external sources ###
source globals__ANSI-color-escapes.sh
source globals__project.sh
source lib__debug.sh
source lib__get-input.sh
source func__print_licheader.sh
source func__print_logo.sh

# global constants ###

# global variables ###

# functions ###
# usage
usage()
{
  _funcstart "$FUNCNAME"

  _info "Provide usage information ..."
  cat<<EOF

${SET_BOLD}NAME${RESET_BOLD}
    ${SET_BOLD}$BASH_SOURCE${RESET_BOLD} – Generate GRUB payload for platform ${FG_BLUE}i386-coreboot${FG_DEFAULT}.

${SET_BOLD}USAGE${RESET_BOLD}
    ${SET_BOLD}bash $BASH_SOURCE${RESET_BOLD} \\
        [<Help-Options>] \\
        [<Screen-Output-Control>]
    ${SET_BOLD}bash $BASH_SOURCE${RESET_BOLD} \\
        [<Clean-Options>] \\
        [<Screen-Output-Control>]
    ${SET_BOLD}bash $BASH_SOURCE${RESET_BOLD} \\
        [<Clean-Options>] \\
        [<Toolbox-Options>] \\
        [<Snippet-Options>] \\
        [<Payload-Options>] \\
        [<Screen-Output-Control>]
    ${SET_BOLD}bash $BASH_SOURCE${RESET_BOLD} \\
        [<Clean-Options>] \\
        [<Toolbox-Options>] \\
        [<Config-Options>] \\
        [<Screen-Output-Control>]

${SET_BOLD}OPTIONS${RESET_BOLD}
    Note the order of options on the command line should have no importance, as the order of job execution
    is hardcoded. Use ${SET_BOLD}--clean-all${RESET_BOLD} to clean up the working directory as a precondition, but use
    ${SET_BOLD}--clean${RESET_BOLD} in case you intend to re-use a previously generated *.elf payload file.

    ${SET_BOLD}<Help-Options>${RESET_BOLD}
        ${SET_BOLD}--help${RESET_BOLD}|${SET_BOLD}--usage${RESET_BOLD}
            Show usage information.

    ${SET_BOLD}<Clean-Options>${RESET_BOLD}
        ${SET_BOLD}--clean${RESET_BOLD}
            In the working directory, clean *.cfg and links to background images, but keep *.elf and
            <Snippet-Files>.
        ${SET_BOLD}--clean-all${RESET_BOLD}
            Same as --clean, but furthermore remove generated *.elf and <Snippet-Files>.

    ${SET_BOLD}<Toolbox-Options>${RESET_BOLD}
        ${SET_BOLD}--toolbox${RESET_BOLD} <toolbox-folder>
            Specify a toolbox folder that holds required external projects.
        <toolbox-folder>
            This folder should have previously been created by ${SET_BOLD}${TOOLCHAIN_SCRIPT[1]}${RESET_BOLD}.

    ${SET_BOLD}<Snippet-Options>${RESET_BOLD}
        ${SET_BOLD}--gen-snippets${RESET_BOLD}
            Generate keyboard layout files *.gkb and create appropriate <Snippet-Files>.
        ${SET_BOLD}--show-snippets${RESET_BOLD}
            Display generated <Snippet-Files> on ${SET_BOLD}stdout${RESET_BOLD}.

    ${SET_BOLD}<Payload-Options>${RESET_BOLD}
        ${SET_BOLD}--pack${RESET_BOLD}
            Generate a full GRUB executable *.elf payload file for platform i386-coreboot:
            ${SET_BOLD}${GRUB_PAYLOAD}${RESET_BOLD}
        ${SET_BOLD}--pack-minimal${RESET_BOLD}
            Generate a minimal GRUB executable *.elf payload file for platform i386-coreboot:
            ${SET_BOLD}${GRUB_PAYLOAD_MINIMAL}${RESET_BOLD}

    ${SET_BOLD}<Config-Options>${RESET_BOLD}
        ${SET_BOLD}--gen-config${RESET_BOLD}
            Generate GRUB configuration files, made from templates and code-snippets.
            Default: ${SET_BOLD}${TEMPLATE_GRUB_CONFIG##*\/}${RESET_BOLD}
        ${SET_BOLD}--grub-keymap${RESET_BOLD} <layout>
            Specify a valid keymap layout, as like us, gb, de, etc.
            See ${SET_BOLD}${SNIPPET_KEYMAP}${RESET_BOLD} to see valid layouts.
        ${SET_BOLD}--grub-default${RESET_BOLD} <number>
            Specify a valid default menuentry, as like ${SET_BOLD}0${RESET_BOLD} (the default) or ${SET_BOLD}1${RESET_BOLD}.
            Parameter <number> might be one of first 10 entries, i.e. 0..9.
        ${SET_BOLD}--grub-nocoreinfo${RESET_BOLD}
            This will remove menuentry ‘Coreinfo’ from the Boot Menu of the generated GRUB
            configuration file. Note payload ‘Coreinfo’ freezes on T60 machines.
        ${SET_BOLD}--grub-nonvramcui${RESET_BOLD}
            This will remove menuentry ‘NVRAMCUI’ from the Boot Menu of the generated GRUB
            configuration file.
        ${SET_BOLD}--grub-nopoweroff${RESET_BOLD}
            This will remove menuentry ‘Poweroff’ from the Boot Menu of the generated GRUB
            configuration file. Note the related GRUB command ‘halt’ sometimes doesn’t work
            on T60 machines, for instance.
        ${SET_BOLD}--grub-nomorse${RESET_BOLD}
            This will remove menuentry ‘Toggle Morse Feedback On/Off’ from the Boot Menu of the
            generated GRUB configuration file. Note on some hardware, GRUB has no audio.
            Otherwise, an additional GRUB configuration file for Morse Code Dialogues will be
            generated: ${SET_BOLD}${TEMPLATE_GRUB_CONFIG_MORSE##*\/}${RESET_BOLD}
        ${SET_BOLD}--grub-background${RESET_BOLD} <image.png>
            With this option, a symbolic link to a background image <image.png> can be created.
            The link name will be placed in the working directory, where it will be automatically picked
            from by script ${SET_BOLD}${TOOLCHAIN_SCRIPT[4]}${RESET_BOLD}. This option might be used up to four times.

    ${SET_BOLD}<Screen-Output-Control>${RESET_BOLD}
        ${SET_BOLD}--mute${RESET_BOLD}
            Discard standard output of verbose external processes.
            However, their output to stderr will still be visible.
        ${SET_BOLD}--debug${RESET_BOLD}
            Enable extra screen output which eases debugging.

${SET_BOLD}FILES${RESET_BOLD}
    ${SET_BOLD}<Snippet-Files>${RESET_BOLD}
        ${SET_BOLD}${SNIPPET_LAYOUTS}${RESET_BOLD}
            Simple list of generated keymap layouts.
        ${SET_BOLD}${SNIPPET_GRUB_LAYOUTS}${RESET_BOLD}
            Generated code snippet used by this script.
        ${SET_BOLD}${SNIPPET_KEYMAP}${RESET_BOLD}
            Generated code snippet for GRUB configuration files, with list of available
            keymap layouts and a keymap statement defaulting to ‘${KEYMAP_DEFAULT}’.

    ${SET_BOLD}<Payload-Files>${RESET_BOLD}
        ${SET_BOLD}${GRUB_PAYLOAD}${RESET_BOLD}
        ${SET_BOLD}${GRUB_PAYLOAD_MINIMAL}${RESET_BOLD}
        ${SET_BOLD}${TEMPLATE_GRUB_CONFIG##*\/}${RESET_BOLD}
        ${SET_BOLD}${TEMPLATE_GRUB_CONFIG_MORSE##*\/}${RESET_BOLD}

    ${SET_BOLD}<Required-Templates>${RESET_BOLD}
        ${SET_BOLD}${TEMPLATE_GRUB_MODULES_MINIMAL}${RESET_BOLD}
        ${SET_BOLD}${TEMPLATE_GRUB_MODULES_PRELOAD}${RESET_BOLD}
        ${SET_BOLD}${TEMPLATE_GRUB_CONFIG_MEMDISK}${RESET_BOLD}
        ${SET_BOLD}${TEMPLATE_GRUB_CONFIG}${RESET_BOLD}
        ${SET_BOLD}${TEMPLATE_GRUB_CONFIG_MORSE}${RESET_BOLD}

${SET_BOLD}EXIT STATUS${RESET_BOLD}
    ${SET_BOLD}0${RESET_BOLD}
        Normal exit.
    ${SET_BOLD}1${RESET_BOLD}
        An error occurred.

${SET_BOLD}EXAMPLES${RESET_BOLD}
    Generate GRUB Payload File, generic:
    ${SET_BOLD}bash $BASH_SOURCE${RESET_BOLD} \\
        ${SET_BOLD}--toolbox${RESET_BOLD} <toolbox-folder> \\
        ${SET_BOLD}--clean-all${RESET_BOLD} \\
        ${SET_BOLD}--gen-snippets${RESET_BOLD} \\
        ${SET_BOLD}--pack-minimal${RESET_BOLD}

    Generate GRUB Configuration Files, generic:
    ${SET_BOLD}bash $BASH_SOURCE${RESET_BOLD} \\
        ${SET_BOLD}--toolbox${RESET_BOLD} <toolbox-folder> \\
        ${SET_BOLD}--clean${RESET_BOLD} \\
        ${SET_BOLD}--gen-config${RESET_BOLD} \\
        ${SET_BOLD}--grub-keymap de${RESET_BOLD}

    Generate GRUB Configuration Files, dedicated for T60 targets:
    ${SET_BOLD}bash $BASH_SOURCE${RESET_BOLD} \\
        ${SET_BOLD}--clean${RESET_BOLD} \\
        ${SET_BOLD}--toolbox${RESET_BOLD} <toolbox-folder> \\
        ${SET_BOLD}--gen-config${RESET_BOLD} \\
        ${SET_BOLD}--grub-keymap de${RESET_BOLD} \\
        ${SET_BOLD}--grub-nocoreinfo${RESET_BOLD} \\
        ${SET_BOLD}--grub-nopoweroff${RESET_BOLD}

    Generate GRUB Configuration Files, dedicated for targets like x230, t430, t430s that do not provide
    sound output with GRUB:
    ${SET_BOLD}bash $BASH_SOURCE${RESET_BOLD} \\
        ${SET_BOLD}--toolbox${RESET_BOLD} <toolbox-folder> \\
        ${SET_BOLD}--clean${RESET_BOLD} \\
        ${SET_BOLD}--gen-config${RESET_BOLD} \\
        ${SET_BOLD}--grub-keymap de${RESET_BOLD} \\
        ${SET_BOLD}--grub-nomorse${RESET_BOLD}

    Generate link names to selected background images, a Zerocat Background for the x230, for instance:
    ${SET_BOLD}bash $BASH_SOURCE${RESET_BOLD} \\
        ${SET_BOLD}--grub-background ../backgrounds/ZC-X230-Coreboot.png${RESET_BOLD}

EOF
  _pass "... usage information has been provided."

  _funcstop "$FUNCNAME"
}

# generate console layouts for GRUB and add to lists
mkmap()
{
  _funcstart "$FUNCNAME"

  declare i=0
  declare map="${1}"

  [[ "${2}" ]] && {
    i=1
    map+="_${2}"
  }
  [[ "${3}" ]] && {
    i=2
    map+="_${3}"
  }

  _info "Create console keymap ${map}.gkb ..."
  echo -e -n "${SET_DIM}" &&
    ckbcomp "${1}" -variant "${2}" -model "${3}" |
      "${bin__grub_mklayout:?is not set}" -o "${map}.gkb" \
        1>"${opt__mute:-/dev/stdout}" && {
          comment[i]+="${map} "
          layouts[i]+="${map}.gkb "
          grub_layouts+="/boot/grub/layouts/${map}.gkb=$PATH_TO_WD/${map}.gkb \\"$'\n'
          _pass "... keymap created:${RTAB}${map}.gkb"
        } ||
          go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"

  _funcstop "$FUNCNAME"
}

# create maps
maps()
{
  _funcstart "$FUNCNAME"

  declare -r -a layout=(  us    us      us      gb  ca  'fi'  dk  se  hu  cz  pl  bg  ro  tr  tr  fr  fr      pt  es  it  nl  be  de  de          ch  ch  sk      )
  declare -r -a variant=( ''    ''      ''      ''  fr  ''    ''  ''  ''  ''  ''  ''  ''  ''  f   ''  ''      ''  ''  ''  ''  ''  ''  ''          de  fr  ''      )
  declare -r -a model=(   ''    intl    dvorak  ''  ''  ''    ''  ''  ''  ''  ''  ''  ''  ''  ''  ''  latin9  ''  ''  ''  ''  ''  ''  nodeadkeys  ''  ''  qwerty  )
  declare -i i

  for (( i=0 ; i<${#layout[@]} ; i++ )) ; do
    mkmap "${layout[$i]}" "${variant[$i]}" "${model[i]}"
  done

  _funcstop "$FUNCNAME"
}

gen_snippet_layouts()
{
  _funcstart "$FUNCNAME"

  _info "Create snippet list of generated layout files ..."
  echo -e "${layouts[0]}\\ " > $SNIPPET_LAYOUTS
  echo -e "${layouts[1]}\\ " >> $SNIPPET_LAYOUTS
  echo -e "${layouts[2]}" >> $SNIPPET_LAYOUTS
  _pass "... file created:${RTAB}$SNIPPET_LAYOUTS"

  _funcstop "$FUNCNAME"
}

# suggest code snippet for GRUB configuration file
gen_snippet_keymap()
{
  _funcstart "$FUNCNAME"

  _info "Create keymap configuration snippet file ..."
  echo "# Keymap --- several options available, adapt to your needs:" > $SNIPPET_KEYMAP
  echo "# ${comment[0]}" >> $SNIPPET_KEYMAP
  echo "# ${comment[1]}" >> $SNIPPET_KEYMAP
  echo "# ${comment[2]}" >> $SNIPPET_KEYMAP
  echo "keymap ${KEYMAP_DEFAULT}" >> $SNIPPET_KEYMAP
  _pass "... file created:${RTAB}$SNIPPET_KEYMAP"

  _funcstop "$FUNCNAME"
}

# $1: list of layouts as in $grub_layouts
gen_snippet_GRUB_layouts()
{
  _funcstart "$FUNCNAME"

  _info "Create snippet file of GRUB layouts ..."
  echo "$(echo ${1:?is not set} | sed -r -e 's#\\##g; s#  # #g;' - )" > $SNIPPET_GRUB_LAYOUTS
  _pass "... file created:${RTAB}$SNIPPET_GRUB_LAYOUTS"

  _funcstop "$FUNCNAME"
}

# $1: snippet file to be displayed
display_snippet()
{
  _funcstart "$FUNCNAME"

  _info "Display snippet file $1 ..."
  if [ -f "$1" ]; then
    echo -e -n "${SET_DIM}" &&
      cat<<EOF

---------8<------------cut here cut here cut here------------>8---------
$(cat ${1:?is not set})
---------8<------------cut here cut here cut here------------>8---------

EOF
    _pass "... file displayed:${RTAB}$1"
  else
    _fail "No such file:${RTAB}$1"
  fi

  _funcstop "$FUNCNAME"
}

# $@:  files to remove
clean()
{
  _funcstart "$FUNCNAME"

  declare -a files=()
  declare i=
  declare -i n=

  n=0
  for i in $@; do
    [ -f "$i" ] && {
      files[n]="$i"
      n+=1
    }
  done
  [[ "${#files[@]}" -eq 0 ]] || {
    _warn "This will remove files ..."
    for i in "${files[@]}"; do
      _mesg "· $i"
    done
    yes_no && {
      rm -f "${files[@]}"
      _pass "... files removed."
    }
  }

  _funcstop "$FUNCNAME"
}

pack_payload()
{
  _funcstart "$FUNCNAME"

  _info "Create memdisk-based GRUB payload for Coreboot ..."
  echo -e -n "${SET_DIM}" &&
    ${bin__grub_mkstandalone:?is not set} \
      -O i386-coreboot \
      -o "${PATH_TO_WD}/${file_elf}" \
      --verbose \
      --modules="${modules_preload}" \
      /boot/grub/grub.cfg="${PATH_TO_WD}/${file_memdisk_config}" \
      $(cat ${PATH_TO_WD}/${SNIPPET_GRUB_LAYOUTS}) \
      1>"${opt__mute:-/dev/stdout}" ||
        go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  _pass "... GRUB payload created:"
  _mesg "${INDENT}${file_elf}"

  _funcstop "$FUNCNAME"
}

pack_payload_minimal()
{
  _funcstart "$FUNCNAME"

  _info "Create memdisk-based GRUB payload for Coreboot, small size ..."
  echo -e -n "${SET_DIM}" &&
    "${bin__grub_mkstandalone:?is not set}" \
      -O i386-coreboot \
      -o "${PATH_TO_WD}/${file_elf_minimal}" \
      --verbose \
      --fonts=unicode \
      --locales= \
      --themes= \
      --modules="${modules_preload}" \
      /boot/grub/grub.cfg="${PATH_TO_WD}/${file_memdisk_config}" \
      $(cat ${PATH_TO_WD}/${SNIPPET_GRUB_LAYOUTS}) \
      1>"${opt__mute:-/dev/stdout}" ||
        go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  _pass "... GRUB payload – small size – created:"
  _mesg "${INDENT}${file_elf_minimal}"

  _funcstop "$FUNCNAME"
}

check_options()
{
  _funcstart "$FUNCNAME"

  _info "Check options ..."

  # --debug

  # --mute

  # --grub-default
  [ "$arg__grub_default" ] && {
    [ "$opt__gen_config" ] ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--grub-default: incomplete set of command line options"
  }

  # --grub-keymap
  [ "$opt__grub_keymap" ] && {
    [ "$opt__gen_config" ] ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--grub-keymap: incomplete set of command line options"
  }

  # --grub-background

  # --grub-nocoreinfo
  [ "$opt__grub_nocoreinfo" ] && {
    [ "$opt__gen_config" ] ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--grub-nocoreinfo: incomplete set of command line options"
  }

  # --grub-nonvramcui
  [ "$opt__grub_nonvramcui" ] && {
    [ "$opt__gen_config" ] ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--grub-nonvramcui: incomplete set of command line options"
  }

  # --grub-nopoweroff
  [ "$opt__grub_nopoweroff" ] && {
    [ "$opt__gen_config" ] ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--grub-nopoweroff: incomplete set of command line options"
  }

  # --grub-nomorse
  [ "$opt__grub_nomorse" ] && {
    [ "$opt__gen_config" ] ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--grub-nomorse: incomplete set of command line options"
  }

  # --toolbox

  # --help | --usage

  # --clean

  # --clean-all

  # --gen-snippets
  [ "$opt__gen_snippets" ] && {
    [ "$arg__toolbox" ] ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--gen-snippets: incomplete set of command line options"
  }

  # --show-snippets
  [ "$opt__show_snippets" ] && {
    [ "$opt__gen_snippets" ] || {
      [ -f "$SNIPPET_GRUB_LAYOUTS" ] && [ -f "$SNIPPET_KEYMAP" ] ||
        go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--show-snippets: incomplete set of command line options"
    }
  }

  # --pack
  [ "$opt__pack" ] && {
    [ "$arg__toolbox" ] ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--pack: incomplete set of command line options"
    [ "$opt__gen_snippets" ] || [ -f "$SNIPPET_GRUB_LAYOUTS" ] ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--pack: incomplete set of command line options"
  }

  # --pack-minimal
  [ "$opt__pack_minimal" ] && {
    [ "$arg__toolbox" ] ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--pack-minimal: incomplete set of command line options"
    [ "$opt__gen_snippets" ] || [ -f "$SNIPPET_GRUB_LAYOUTS" ] ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--pack-minimal: incomplete set of command line options"
  }

  # --gen-config
  [ "$opt__gen_config" ] && {
    [ "$arg__toolbox" ] ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--gen-config: incomplete set of command line options"
    [ "$opt__gen_snippets" ] || [ -f "$SNIPPET_KEYMAP" ] ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--gen-config: incomplete set of command line options"
  }

  _pass "... options checked."

  _funcstop "$FUNCNAME"
}

parse_cmdline()
{
  _funcstart "$FUNCNAME"

  declare -i n=
  declare opt=

  _info "Parse command line ..."
  while [ $# -gt 0 ]; do
    opt=${1:?missing parameter}
    n=1
    opt=${opt,,}
    case "${opt}" in
      # parameters
      '--debug')
        # no action here, see bottom of script
        ;;
      '--mute')
        opt__mute="/dev/null"
        ;;
      '--grub-default')
        [ "$arg__grub_default" ] &&
          go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--grub-default: duplicate option"
        [ "${2:0:2}" == '--' ] || [ "$2" == '' ] &&
          go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--grub-default: missing argument"
        opt=$2
        n+=1
        case "$opt" in
          [0-9])
            arg__grub_default=${opt}
            ;;
          *)
            go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--grub-default: number out of range: $opt"
            ;;
        esac
        ;;
      '--grub-keymap')
        [ "$arg__grub_keymap" ] &&
          go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--grub-keymap: duplicate option"
        [ "${2:0:2}" == '--' ] || [ "$2" == '' ] &&
          go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--grub-keymap: missing argument"
        opt=${2,,}
        n+=1
        arg__grub_keymap=${opt}
        ;;
      '--grub-background')
        [ ${#grub_background[@]} -lt ${#BACKGROUND_CBFS[@]} ] ||
          go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--grub-background: array exceeded"
        [ "${2:0:2}" == '--' ] || [ "$2" == '' ] &&
          go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--grub-background: missing argument"
        [ -f "$2" ] ||
          go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--grub-background: no such file: $2"
        opt=$2
        n+=1
        case "${opt##*.}" in
          [pP][nN][gG])
            grub_background[${#grub_background[@]}]=$opt
            ;;
          *)
            go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--grub-background: extension not supported: ${opt##*.}"
            ;;
        esac
        opt__grub_background=1
        ;;
      '--grub-nocoreinfo')
        [ "$opt__grub_nocoreinfo" ] &&
          go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--grub-nocoreinfo: duplicate option"
        opt__grub_nocoreinfo=1
        ;;
      '--grub-nonvramcui')
        [ "$opt__grub_nonvramcui" ] &&
          go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--grub-nonvramcui: duplicate option"
        opt__grub_nonvramcui=1
        ;;
      '--grub-nopoweroff')
        [ "$opt__grub_nopoweroff" ] &&
          go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--grub-nopoweroff: duplicate option"
        opt__grub_nopoweroff=1
        ;;
      '--grub-nomorse')
        [ "$opt__grub_nomorse" ] &&
          go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--grub-nomorse: duplicate option"
        opt__grub_nomorse=1
        ;;
      '--toolbox')
        [ "$arg__toolbox" ] &&
          go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--toolbox: duplicate option"
        [ "${2:0:2}" == '--' ] || [ "${2}" == '' ] &&
          go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--toolbox: missing argument"
        opt=$2
        n+=1
        pushd "$opt" &>/dev/null ||
          go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "--toolbox: no such directory: $opt"
        arg__toolbox=$(dirs -l +0)
        popd &>/dev/null
        path_to_grub=$(echo "${arg__toolbox}"/grub[-@]*/)
        select_option path_to_grub
        [ -d "$path_to_grub" ] ||
          go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "no such directory: $path_to_grub"
        bin__grub_mklayout="${path_to_grub}/grub-mklayout"
        bin__grub_mkstandalone="${path_to_grub}/grub-mkstandalone"
        version_grub="${path_to_grub##*\/grub[-@]}"
        version_grub="${version_grub%\/}"
        file_elf="${GRUB_PAYLOAD/\$\{version_grub\}/${version_grub}}"
        file_elf_minimal="${GRUB_PAYLOAD_MINIMAL/\$\{version_grub\}/${version_grub}}"
        file_memdisk_config="${TEMPLATE_GRUB_CONFIG_MEMDISK/\$\{version_grub\}/${version_grub}}"
        [ -f "$file_memdisk_config" ] ||
          go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "no such file: $file_memdisk_config"
        file_modules_minimal="${TEMPLATE_GRUB_MODULES_MINIMAL/\$\{version_grub\}/${version_grub}}"
        [ -f "$file_modules_minimal" ] ||
          go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "no such file: $file_modules_minimal"
        file_modules_preload="${TEMPLATE_GRUB_MODULES_PRELOAD/\$\{version_grub\}/${version_grub}}"
        [ -f "$file_modules_preload" ] ||
          go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "no such file: $file_modules_preload"
        source "./$file_modules_minimal"  # note this source statement is NOT optional.
        source "./$file_modules_preload"  # note this source statement is optional.
        modules_preload+="$modules_preload_minimal"
        ;;
      # jobs
      '--help'|'--usage')
        opt__usage=1
        ;;
      '--clean')
        opt__clean=1
        ;;
      '--clean-all')
        opt__clean_all=1
        ;;
      '--gen-snippets')
        opt__gen_snippets=1
        ;;
      '--show-snippets')
        opt__show_snippets=1
        ;;
      '--pack')
        opt__pack=1
        ;;
      '--pack-minimal')
        opt__pack_minimal=1
        ;;
      '--gen-config')
        opt__gen_config=1
        ;;
      *)
        go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "unknown option: ${opt}"
        ;;
    esac
    shift $n
  done
  if [ $# -ne 0 ]; then
    _warn "... $# parameters were skipped."
  else
    _pass "... all parameters parsed."
  fi

  _funcstop "$FUNCNAME"
}

check_settings()
{
  _funcstart "$FUNCNAME"

  _info "Check settings ..."

  # --debug
  [ "$DEBUG" -eq 0 ] ||
    _mesg "Debug output is activated."

  # --mute
  [ "$opt__mute" ] &&
    _mesg "Standard output of external processes is muted."

  # --toolbox
  [ "$arg__toolbox" ] && {
    declare grub_versinfo=`grub-mkstandalone --version`
    grub_versinfo=${grub_versinfo#*(GRUB) }

    _mesg "Toolbox Folder:${RTAB}${arg__toolbox}"
    _mesg "Path to GRUB:${RTAB}${SET_BOLD}${path_to_grub}${RESET_BOLD}"
    _mesg "grub-mklayout:${RTAB}${bin__grub_mklayout:?is not set}"
    _mesg "grub-mkstandalone:${RTAB}${bin__grub_mkstandalone}"
    _dbug "GRUB Version:${RTAB}${version_grub:?is not set}"

    # check installed grub version
    [ "$grub_versinfo" != "${version_grub//[^.0-9]}" ] && {
      _fail "The version of your installed GRUB mismatches the required version."
      _mesg "Required:${RTAB}${version_grub//[^.0-9]}"
      _mesg "Installed:${RTAB}${grub_versinfo}"
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "GRUB version mismatch"
    }
  }

  # --gen-config
  [ "$opt__gen_config" ] && {
    template_grub_config="${TEMPLATE_GRUB_CONFIG/\$\{version_grub\}/${version_grub}}"
    _mesg "Configuration Template:${RTAB}$template_grub_config"
    [ -f "$template_grub_config" ] ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "no such file: $template_grub_config"

    _mesg "Keymap Snippet:${RTAB}$SNIPPET_KEYMAP"
    [ "$opt__gen_snippets" ] || [ -f "$SNIPPET_KEYMAP" ] ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "no such file: $SNIPPET_KEYMAP"

    # --grub-default
    [ "$arg__grub_default" ] &&
      _mesg "GRUB Default Menuentry:${RTAB}${arg__grub_default}"

    # --grub-keymap
    [ "$arg__grub_keymap" ] &&
      _mesg "GRUB Keymap:${RTAB}${arg__grub_keymap}"

    # --grub-nomorse
    [ "$opt__grub_nomorse" ] &&
      _mesg "Menuentry “Morse”:${RTAB}configured to be removed"

    # --grub-nopoweroff
    [ "$opt__grub_nopoweroff" ] &&
      _mesg "Menuentry “Poweroff”:${RTAB}configured to be removed"

    # --grub-nocoreinfo
    [ "$opt__grub_nocoreinfo" ] &&
      _mesg "Menuentry “Coreinfo”:${RTAB}configured to be removed"

    # --grub-nonvramcui
    [ "$opt__grub_nonvramcui" ] &&
      _mesg "Menuentry “NVRAMCUI”:${RTAB}configured to be removed"
  }

  # --show_snippets

  # --pack

  # --pack-minimal

  # --grub-background
  declare i
  for i in "${!grub_background[@]}"; do
    _mesg "GRUB Background $i:${RTAB}${grub_background[$i]}"
  done
  unset i

  _pass "... settings checked."

  _funcstop "$FUNCNAME"
}

parse_debug()
{
  declare i=

  DEBUG=0
  for i in "$@"; do
    [ "$i" == '--debug' ] && DEBUG=1
  done
}

gen_config()
{
  _funcstart "$FUNCNAME"

  declare -r snippet_keymap="$SNIPPET_KEYMAP"
  declare -r new_config="${template_grub_config##*\/}"

  _info "Generate GRUB Configuration File ..."

  _mesg "Copy template file and update list of keymaps ..."
  sed -r \
    -e '/^# Keymap/r '"$snippet_keymap"'' \
    -e '/^# Keymap/,/^keymap/d;' \
    "$template_grub_config" \
    > "$new_config" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"

  [ "$opt__grub_nocoreinfo" ] && {
    _mesg "Remove menuentry “Coreinfo” ..."
    sed -r -i \
      -e '/Coreinfo/,/\}/d;' \
      -e '/# Hotkeys in use\:/s/, f//;' \
      "$new_config" ||
        go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }

  [ "$opt__grub_nonvramcui" ] && {
    _mesg "Remove menuentry “NVRAMCUI” ..."
    sed -r -i \
      -e '/NVRAMCUI/,/\}/d;' \
      -e '/# Hotkeys in use\:/s/, n//;' \
      "$new_config" ||
        go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }

  [ "$opt__grub_nopoweroff" ] && {
    _mesg "Remove menuentry “Poweroff” ..."
    sed -r -i \
      -e '/Poweroff/,/\}/d;' \
      -e '/# Hotkeys in use\:/s/, h//;' \
      "$new_config" ||
        go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }

  [ "$opt__grub_nomorse" ] && {
    _mesg "Remove Morse Feedback Feature ..."
    sed -r -i \
      -e '/^## Morse Feedback Feature: Settings/,+2d;' \
      -e '/^## Morse Feedback Feature: Menuentry/,/^fi/d;' \
      -e '/if \[ \"\$morse_feedback\" \=\= .1. \];/,/fi/d;' \
      -e '/# Hotkeys in use\:/s/, m//;' \
      "$new_config" ||
        go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }

  [ "$arg__grub_default" ] && {
    _mesg "Apply new default menuentry $arg__grub_default ..."
    sed -r -i \
      -e 's/(^set default=)(0)/\1'"$arg__grub_default"'/;' \
      "$new_config" ||
        go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }

  [ "$arg__grub_keymap" ] && {
    _mesg "Apply keymap ‘$arg__grub_keymap’ ..."
    [ "$(sed -r \
      -e '/# Keymap/,/^keymap/!d;' \
      -e '/# Keymap/d; /^keymap/d;' \
      -e '/ '"$arg__grub_keymap"'[ $]/!d' \
      "$new_config")" ] ||
        go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "No such keymap: ${arg__grub_keymap}"
    sed -r -i -e '/^keymap/ckeymap '"${arg__grub_keymap}"'' "${new_config}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
  }

  _pass "... file generated:${RTAB}$new_config"

  [ "$opt__grub_nomorse" ] || {
    declare -r morse_cfg_template="${TEMPLATE_GRUB_CONFIG_MORSE/\$\{version_grub\}/${version_grub}}"

    _info "Generate GRUB Morse Feedback configuration file ..."
    [ -f "$morse_cfg_template" ] ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "No such file: ${morse_cfg_template}"
    cp -f "$morse_cfg_template" "./${morse_cfg_template##*\/}" ||
      go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO"
    _pass "... file generated:${RTAB}${morse_cfg_template##*\/}"
  }

  _funcstop "$FUNCNAME"
}

job_list()
{
  _funcstart "$FUNCNAME"

  declare retval=1

  # jobs
  _dbug "${FG_MAGENTA}Jobs ...${FG_DEFAULT}"
  _info "Requested jobs are:"
  [ "$opt__usage" ] && {
    _mesg "${LIITEM}display usage information"
    retval=0
  }
  [ "$opt__clean" ] && {
    _mesg "${LIITEM}clean configuration files and symbolic links to background files"
    retval=0
  }
  [ "$opt__clean_all" ] && {
    _mesg "${LIITEM}clean all generated files"
    retval=0
  }
  [ "$opt__grub_background" ] && {
    _mesg "${LIITEM}create symbolic links to specified background images"
    retval=0
  }
  [ "$opt__gen_snippets" ] && {
    _mesg "${LIITEM}generate snippet files"
    _mesg "${INDENT}${LIITEM}keyboard layout files, to be used with GRUB on platform coreboot:"
    _mesg "${INDENT}${INDENT}${INDENT}*.gkb"
    _mesg "${INDENT}${LIITEM}snippet file, listing all generated keyboard layout files:"
    _mesg "${INDENT}${INDENT}${INDENT}${SNIPPET_LAYOUTS}"
    _mesg "${INDENT}${LIITEM}snippet file, listing new GRUB paths for generated keyboard layout files:"
    _mesg "${INDENT}${INDENT}${INDENT}${SNIPPET_GRUB_LAYOUTS}"
    _mesg "${INDENT}${LIITEM}snippet file for the GRUB configuration file:"
    _mesg "${INDENT}${INDENT}${INDENT}${SNIPPET_KEYMAP}"
    retval=0
  }
  [ "$opt__pack" ] && {
    _mesg "${LIITEM}pack the payload file"
    retval=0
  }
  [ "$opt__pack_minimal" ] && {
    _mesg "${LIITEM}pack the payload file, small size"
    retval=0
  }
  [ "$opt__gen_config" ] && {
    _mesg "${LIITEM}generate configuration files"
    retval=0
  }
  [ "$opt__show_snippets" ] && {
    _mesg "${LIITEM}show the content of generated snippet files"
    retval=0
  }
  [ "$retval" -eq 0 ] ||
    _mesg "${INDENT}none"

  _funcstop "$FUNCNAME"
  return "$retval"
}

main()
{
  trap '
    echo
    go_exit "$BASH_SOURCE" "$FUNCNAME" "" "$BASH_COMMAND"
    ' SIGINT ERR   # what sigspec is related to ERR??

  _funcstart "$FUNCNAME"

  declare -r scriptname="${TOOLCHAIN_SCRIPT[3]}"
  # Script’s Requirements:
  # source, echo, printf, cat, sed, rm, mv, cd, sleep, exit
  declare -r -a script_requirements=(
    'source'
    'echo'
    'printf'
    'cat'
    'sed'
    'rm'
    'mv'
    'cd'
    'sleep'
    'exit'
    'ckbcomp'
  )
  declare -r PATH_TO_WD="$(pwd)"
  declare -r KEYMAP_DEFAULT="us"
  declare -r SNIPPET_KEYMAP="snippet-keymap.txt"
  declare -r SNIPPET_LAYOUTS="snippet-layouts.txt"
  declare -r SNIPPET_GRUB_LAYOUTS="snippet-GRUB-layouts.txt"
  declare -r TEMPLATE_GRUB_MODULES_MINIMAL="config-templates/grub@\${version_grub}_modules-preload-minimal.conf"
  declare -r TEMPLATE_GRUB_MODULES_PRELOAD="config-templates/grub@\${version_grub}_modules-preload.conf"

  declare opt__usage=
  declare opt__clean=
  declare opt__clean_all=
  declare opt__gen_snippets=
  declare opt__gen_config=
  declare opt__pack=
  declare opt__pack_minimal=
  declare opt__show_snippets=
  declare opt__grub_background=
  declare opt__mute=
  declare opt__grub_nocoreinfo=
  declare opt__grub_nonvramcui=
  declare opt__grub_nopoweroff=
  declare opt__grub_nomorse=

  declare arg__toolbox=
  declare arg__grub_default=
  declare arg__grub_keymap=

  declare path_to_grub=               # directly related to $arg__toolbox
  declare version_grub=
  declare bin__grub_mklayout=
  declare bin__grub_mkstandalone=
  declare file_elf=
  declare file_elf_minimal=
  declare file_memdisk_config=
  declare file_modules_minimal=
  declare file_modules_preload=
  declare template_grub_config=

  declare -a layouts=("" "" "")
  declare -a comment=("" "" "")
  declare grub_layouts=
  declare modules_preload=
  declare modules_preload_minimal=

  declare -a grub_background

  _head "Zerocat Project: “Coreboot-Machines ${DOXYFILE_PROJECT_NUMBER}”"
  _head "$scriptname – Generate GRUB Payload"
  print_licheader
  print_logo
  test_scriptname "$BASH_SOURCE" "$scriptname" && {
    check_commands 'script_requirements'
    _info "$(date), ready to start."
    hit_enter
    parse_cmdline "$@"
    check_options
    check_settings
    job_list && {
      yes_no && {
        [ "$opt__usage" ] && {
          usage
        }
        [ "$opt__clean" ] && {
          clean \
            *.cfg \
            "${GRUB_BG/\$\{ibg\}/?}"
        }
        [ "$opt__clean_all" ] && {
          clean \
            *.cfg \
            "${GRUB_BG/\$\{ibg\}/?}" \
            $SNIPPET_LAYOUTS \
            $SNIPPET_GRUB_LAYOUTS \
            $SNIPPET_KEYMAP \
            *.gkb \
            *.elf
        }
        [ "$opt__grub_background" ] && {
          _info "Create symbolic links to background images ..."
          declare grub_bg
          declare i
          for i in "${!grub_background[@]}"; do
            grub_bg="${GRUB_BG/\$\{ibg\}/$i}"
            ln -f -s "${grub_background[$i]}" "$grub_bg" ||
              go_exit "$BASH_SOURCE" "$FUNCNAME" "$LINENO" "failed to create symbolic link"
            _mesg "GRUB Background ${i}:${RTAB}${SET_BOLD}$(ls -l $grub_bg | sed -r -e 's/(^.* )(.* -> .*)/\2/;' -)${RESET_BOLD}"
          done
          unset i
          unset grub_bg
          _pass "... symbolic links created."
        }
        [ "$opt__gen_snippets" ] && {
          _info "This will generate Files and Code Snippets:"
          maps
          gen_snippet_layouts
          gen_snippet_GRUB_layouts "$grub_layouts"
          gen_snippet_keymap
          _pass "... all snippet files generated."
        }
        [ "$opt__pack_minimal" ] && {
          pack_payload_minimal
        }
        [ "$opt__pack" ] && {
          pack_payload
        }
        [ "$opt__gen_config" ] && {
          gen_config
        }
        [ "$opt__show_snippets" ] && {
          display_snippet "$SNIPPET_GRUB_LAYOUTS"
          display_snippet "$SNIPPET_KEYMAP"
        }
      }
    }
  }
  _info "Good Bye."

  _funcstop "$FUNCNAME"

  trap - ERR SIGINT
}

# script
parse_debug "$@"
main "$@"

##>! @endcond