420527
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
420527
From: Javier Martinez Canillas <javierm@redhat.com>
420527
Date: Wed, 3 Oct 2018 20:48:32 +0200
420527
Subject: [PATCH] add 10_linux_bls grub.d snippet to generate menu entries from
420527
 BLS files
420527
420527
This grub.d snippet can be used on platforms where the bootloader doesn't
420527
have BLS support and only can parse a normal grub configuration file.
420527
420527
Portions of this script were taken from the ostree-grub-generator script
420527
included in the OSTree project.
420527
420527
Resolves: rhbz#1636013
420527
420527
Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
420527
---
420527
 Makefile.util.def           |   7 +
420527
 util/grub.d/10_linux_bls.in | 440 ++++++++++++++++++++++++++++++++++++++++++++
420527
 2 files changed, 447 insertions(+)
420527
 create mode 100644 util/grub.d/10_linux_bls.in
420527
420527
diff --git a/Makefile.util.def b/Makefile.util.def
420527
index c8cb91308d9..eca3dfa753f 100644
420527
--- a/Makefile.util.def
420527
+++ b/Makefile.util.def
420527
@@ -508,6 +508,13 @@ script = {
420527
   condition = COND_HOST_LINUX;
420527
 };
420527
 
420527
+script = {
420527
+  name = '10_linux_bls';
420527
+  common = util/grub.d/10_linux_bls.in;
420527
+  installdir = grubconf;
420527
+  condition = COND_HOST_LINUX;
420527
+};
420527
+
420527
 script = {
420527
   name = '10_xnu';
420527
   common = util/grub.d/10_xnu.in;
420527
diff --git a/util/grub.d/10_linux_bls.in b/util/grub.d/10_linux_bls.in
420527
new file mode 100644
420527
index 00000000000..3cc7803c6a1
420527
--- /dev/null
420527
+++ b/util/grub.d/10_linux_bls.in
420527
@@ -0,0 +1,440 @@
420527
+#! /bin/sh
420527
+set -e
420527
+
420527
+# grub-mkconfig helper script.
420527
+# Copyright (C) 2006,2007,2008,2009,2010  Free Software Foundation, Inc.
420527
+#
420527
+# GRUB is free software: you can redistribute it and/or modify
420527
+# it under the terms of the GNU General Public License as published by
420527
+# the Free Software Foundation, either version 3 of the License, or
420527
+# (at your option) any later version.
420527
+#
420527
+# GRUB is distributed in the hope that it will be useful,
420527
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
420527
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
420527
+# GNU General Public License for more details.
420527
+#
420527
+# You should have received a copy of the GNU General Public License
420527
+# along with GRUB.  If not, see <http: www.gnu.org="" licenses=""/>.
420527
+
420527
+prefix="@prefix@"
420527
+exec_prefix="@exec_prefix@"
420527
+datarootdir="@datarootdir@"
420527
+
420527
+. "$pkgdatadir/grub-mkconfig_lib"
420527
+
420527
+export TEXTDOMAIN=@PACKAGE@
420527
+export TEXTDOMAINDIR="@localedir@"
420527
+
420527
+CLASS="--class gnu-linux --class gnu --class os --unrestricted"
420527
+
420527
+if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then
420527
+  OS="$(eval $(grep PRETTY_NAME /etc/os-release) ; echo ${PRETTY_NAME})"
420527
+  CLASS="--class $(eval $(grep '^ID_LIKE=\|^ID=' /etc/os-release) ; [ -n "${ID_LIKE}" ] && echo ${ID_LIKE} || echo ${ID}) ${CLASS}"
420527
+else
420527
+  OS="${GRUB_DISTRIBUTOR}"
420527
+  CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1|LC_ALL=C sed 's,[^[:alnum:]_],_,g') ${CLASS}"
420527
+fi
420527
+
420527
+# loop-AES arranges things so that /dev/loop/X can be our root device, but
420527
+# the initrds that Linux uses don't like that.
420527
+case ${GRUB_DEVICE} in
420527
+  /dev/loop/*|/dev/loop[0-9])
420527
+    GRUB_DEVICE=`losetup ${GRUB_DEVICE} | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"`
420527
+  ;;
420527
+esac
420527
+
420527
+# Default to disabling partition uuid support to maintian compatibility with
420527
+# older kernels.
420527
+GRUB_DISABLE_LINUX_PARTUUID=${GRUB_DISABLE_LINUX_PARTUUID-true}
420527
+
420527
+# btrfs may reside on multiple devices. We cannot pass them as value of root= parameter
420527
+# and mounting btrfs requires user space scanning, so force UUID in this case.
420527
+if ( [ "x${GRUB_DEVICE_UUID}" = "x" ] && [ "x${GRUB_DEVICE_PARTUUID}" = "x" ] ) \
420527
+    || ( [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \
420527
+	&& [ "x${GRUB_DISABLE_LINUX_PARTUUID}" = "xtrue" ] ) \
420527
+    || ( ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" \
420527
+	&& ! test -e "/dev/disk/by-partuuid/${GRUB_DEVICE_PARTUUID}" ) \
420527
+    || ( test -e "${GRUB_DEVICE}" && uses_abstraction "${GRUB_DEVICE}" lvm ); then
420527
+  LINUX_ROOT_DEVICE=${GRUB_DEVICE}
420527
+elif [ "x${GRUB_DEVICE_UUID}" = "x" ] \
420527
+    || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ]; then
420527
+  LINUX_ROOT_DEVICE=PARTUUID=${GRUB_DEVICE_PARTUUID}
420527
+else
420527
+  LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID}
420527
+fi
420527
+
420527
+case x"$GRUB_FS" in
420527
+    xbtrfs)
420527
+	if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ]; then
420527
+	GRUB_CMDLINE_LINUX="${GRUB_CMDLINE_LINUX} \${extra_cmdline}"
420527
+	else
420527
+	rootsubvol="`make_system_path_relative_to_its_root /`"
420527
+	rootsubvol="${rootsubvol#/}"
420527
+	if [ "x${rootsubvol}" != x ]; then
420527
+	    GRUB_CMDLINE_LINUX="rootflags=subvol=${rootsubvol} ${GRUB_CMDLINE_LINUX}"
420527
+	fi
420527
+	fi;;
420527
+    xzfs)
420527
+	rpool=`${grub_probe} --device ${GRUB_DEVICE} --target=fs_label 2>/dev/null || true`
420527
+	bootfs="`make_system_path_relative_to_its_root / | sed -e "s,@$,,"`"
420527
+	LINUX_ROOT_DEVICE="ZFS=${rpool}${bootfs}"
420527
+	;;
420527
+esac
420527
+
420527
+mktitle ()
420527
+{
420527
+  local title_type
420527
+  local version
420527
+  local OS_NAME
420527
+  local OS_VERS
420527
+
420527
+  title_type=$1 && shift
420527
+  version=$1 && shift
420527
+
420527
+  OS_NAME="$(eval $(grep ^NAME= /etc/os-release) ; echo ${NAME})"
420527
+  OS_VERS="$(eval $(grep ^VERSION= /etc/os-release) ; echo ${VERSION})"
420527
+
420527
+  case $title_type in
420527
+    recovery)
420527
+      title=$(printf '%s (%s) %s (recovery mode)' \
420527
+                     "${OS_NAME}" "${version}" "${OS_VERS}")
420527
+      ;;
420527
+    *)
420527
+      title=$(printf '%s (%s) %s' \
420527
+                     "${OS_NAME}" "${version}" "${OS_VERS}")
420527
+      ;;
420527
+  esac
420527
+  echo -n ${title}
420527
+}
420527
+
420527
+title_correction_code=
420527
+
420527
+populate_header_warn()
420527
+{
420527
+cat <
420527
+
420527
+# This section was generated by a script. Do not modify the generated file - all changes
420527
+# will be lost the next time file is regenerated. Instead edit the BootLoaderSpec files.
420527
+
420527
+EOF
420527
+}
420527
+
420527
+read_config()
420527
+{
420527
+    config_file=${1}
420527
+    title=""
420527
+    initrd=""
420527
+    options=""
420527
+    linux=""
420527
+
420527
+    while read -r line
420527
+    do
420527
+        record=$(echo ${line} | cut -f 1 -d ' ')
420527
+        value=$(echo ${line} | cut -s -f2- -d ' ')
420527
+        case "${record}" in
420527
+            "title")
420527
+                title=${value}
420527
+                ;;
420527
+            "initrd")
420527
+                initrd=${value}
420527
+                ;;
420527
+            "linux")
420527
+                linux=${value}
420527
+                ;;
420527
+            "options")
420527
+                options=${value}
420527
+                ;;
420527
+        esac
420527
+    done < ${config_file}
420527
+}
420527
+
420527
+populate_menu()
420527
+{
420527
+    entries_path="/boot/loader/entries"
420527
+    gettext_printf "Generating boot entries from BLS files...\n" >&2
420527
+    for config in $(ls -v -r $entries_path/*.conf); do
420527
+        read_config ${config}
420527
+        menu="${menu}menuentry '${title}' {\n"
420527
+        menu="${menu}\t linux ${linux} ${options}\n"
420527
+        if [ -n "${initrd}" ] ; then
420527
+            menu="${menu}\t initrd ${boot_prefix}${initrd}\n"
420527
+        fi
420527
+        menu="${menu}}\n\n"
420527
+    done
420527
+    # The printf command seems to be more reliable across shells for special character (\n, \t) evaluation
420527
+    printf "$menu"
420527
+}
420527
+
420527
+linux_entry ()
420527
+{
420527
+  os="$1"
420527
+  version="$2"
420527
+  type="$3"
420527
+  isdebug="$4"
420527
+  args="$5"
420527
+
420527
+  if [ -z "$boot_device_id" ]; then
420527
+      boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
420527
+  fi
420527
+
420527
+  if [ "x${GRUB_ENABLE_BLSCFG}" = "xtrue" ]; then
420527
+    if [ x$dirname = x/ ]; then
420527
+      if [ -z "${prepare_root_cache}" ]; then
420527
+        prepare_grub_to_access_device ${GRUB_DEVICE}
420527
+      fi
420527
+    else
420527
+      if [ -z "${prepare_boot_cache}" ]; then
420527
+        prepare_grub_to_access_device ${GRUB_DEVICE_BOOT}
420527
+      fi
420527
+    fi
420527
+
420527
+    if [ -d /sys/firmware/efi ]; then
420527
+        bootefi_device="`${grub_probe} --target=device /boot/efi/`"
420527
+        prepare_grub_to_access_device ${bootefi_device} boot
420527
+    else
420527
+        boot_device="`${grub_probe} --target=device /boot/`"
420527
+        prepare_grub_to_access_device ${boot_device} boot
420527
+    fi
420527
+
420527
+    populate_header_warn
420527
+    populate_menu
420527
+
420527
+    ${grub_editenv} - set saved_entry=0
420527
+    ${grub_editenv} - set kernelopts="root=${linux_root_device_thisversion} ro ${args}"
420527
+
420527
+    exit 0
420527
+  fi
420527
+
420527
+  if [ x$type != xsimple ] ; then
420527
+      title=$(mktitle "$type" "$version")
420527
+      if [ x"$title" = x"$GRUB_ACTUAL_DEFAULT" ] || [ x"Previous Linux versions>$title" = x"$GRUB_ACTUAL_DEFAULT" ]; then
420527
+	  replacement_title="$(echo "Advanced options for ${OS}" | sed 's,>,>>,g')>$(echo "$title" | sed 's,>,>>,g')"
420527
+	  quoted="$(echo "$GRUB_ACTUAL_DEFAULT" | grub_quote)"
420527
+	  title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;"
420527
+      fi
420527
+      if [ x$isdebug = xdebug ]; then
420527
+	  title="$title${GRUB_LINUX_DEBUG_TITLE_POSTFIX}"
420527
+      fi
420527
+      echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
420527
+  else
420527
+      echo "menuentry '$(echo "$os" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
420527
+  fi
420527
+  if [ x$type != xrecovery ] ; then
420527
+      save_default_entry | grub_add_tab
420527
+  fi
420527
+
420527
+  # Use ELILO's generic "efifb" when it's known to be available.
420527
+  # FIXME: We need an interface to select vesafb in case efifb can't be used.
420527
+  if [ "x$GRUB_GFXPAYLOAD_LINUX" = x ]; then
420527
+      echo "	load_video" | sed "s/^/$submenu_indentation/"
420527
+      if grep -qx "CONFIG_FB_EFI=y" "${config}" 2> /dev/null \
420527
+	  && grep -qx "CONFIG_VT_HW_CONSOLE_BINDING=y" "${config}" 2> /dev/null; then
420527
+	  echo "	set gfxpayload=keep" | sed "s/^/$submenu_indentation/"
420527
+      fi
420527
+  else
420527
+      if [ "x$GRUB_GFXPAYLOAD_LINUX" != xtext ]; then
420527
+	  echo "	load_video" | sed "s/^/$submenu_indentation/"
420527
+      fi
420527
+      echo "	set gfxpayload=$GRUB_GFXPAYLOAD_LINUX" | sed "s/^/$submenu_indentation/"
420527
+  fi
420527
+
420527
+  echo "	insmod gzio" | sed "s/^/$submenu_indentation/"
420527
+
420527
+  if [ x$dirname = x/ ]; then
420527
+    if [ -z "${prepare_root_cache}" ]; then
420527
+      prepare_root_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE} | grub_add_tab)"
420527
+    fi
420527
+    printf '%s\n' "${prepare_root_cache}" | sed "s/^/$submenu_indentation/"
420527
+  else
420527
+    if [ -z "${prepare_boot_cache}" ]; then
420527
+      prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | grub_add_tab)"
420527
+    fi
420527
+    printf '%s\n' "${prepare_boot_cache}" | sed "s/^/$submenu_indentation/"
420527
+  fi
420527
+  sed "s/^/$submenu_indentation/" << EOF
420527
+	linux	${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro ${args}
420527
+EOF
420527
+  if test -n "${initrd}" ; then
420527
+    initrd_path=
420527
+    for i in ${initrd}; do
420527
+      initrd_path="${initrd_path} ${rel_dirname}/${i}"
420527
+    done
420527
+    sed "s/^/$submenu_indentation/" << EOF
420527
+	initrd	$(echo $initrd_path)
420527
+EOF
420527
+  fi
420527
+  if test -n "${fdt}" ; then
420527
+    sed "s/^/$submenu_indentation/" << EOF
420527
+	devicetree	${rel_dirname}/${fdt}
420527
+EOF
420527
+  fi
420527
+  sed "s/^/$submenu_indentation/" << EOF
420527
+}
420527
+EOF
420527
+}
420527
+
420527
+machine=`uname -m`
420527
+case "x$machine" in
420527
+    xi?86 | xx86_64)
420527
+	list=
420527
+	for i in /boot/vmlinuz-* /vmlinuz-* /boot/kernel-* ; do
420527
+	    if grub_file_is_not_garbage "$i" ; then list="$list $i" ; fi
420527
+	done ;;
420527
+    *)
420527
+	list=
420527
+	for i in /boot/vmlinuz-* /boot/vmlinux-* /vmlinuz-* /vmlinux-* /boot/kernel-* ; do
420527
+                  if grub_file_is_not_garbage "$i" ; then list="$list $i" ; fi
420527
+	done ;;
420527
+esac
420527
+
420527
+if [ "x${GRUB_ENABLE_BLSCFG}" = "xtrue" ]; then
420527
+    for i in /boot/ostree/*/vmlinuz-* ; do
420527
+        if grub_file_is_not_garbage "$i" ; then list="$list $i" ; fi
420527
+    done
420527
+fi
420527
+
420527
+case "$machine" in
420527
+    i?86) GENKERNEL_ARCH="x86" ;;
420527
+    mips|mips64) GENKERNEL_ARCH="mips" ;;
420527
+    mipsel|mips64el) GENKERNEL_ARCH="mipsel" ;;
420527
+    arm*) GENKERNEL_ARCH="arm" ;;
420527
+    *) GENKERNEL_ARCH="$machine" ;;
420527
+esac
420527
+
420527
+prepare_boot_cache=
420527
+prepare_root_cache=
420527
+boot_device_id=
420527
+title_correction_code=
420527
+
420527
+# Extra indentation to add to menu entries in a submenu. We're not in a submenu
420527
+# yet, so it's empty. In a submenu it will be equal to '\t' (one tab).
420527
+submenu_indentation=""
420527
+
420527
+is_top_level=true
420527
+while [ "x$list" != "x" ] ; do
420527
+  linux=`version_find_latest $list`
420527
+  if [ "x${GRUB_ENABLE_BLSCFG}" != "xtrue" ]; then
420527
+    gettext_printf "Found linux image: %s\n" "$linux" >&2
420527
+  fi
420527
+
420527
+  basename=`basename $linux`
420527
+  dirname=`dirname $linux`
420527
+  rel_dirname=`make_system_path_relative_to_its_root $dirname`
420527
+  version=`echo $basename | sed -e "s,^[^0-9]*-,,g"`
420527
+  alt_version=`echo $version | sed -e "s,\.old$,,g"`
420527
+  linux_root_device_thisversion="${LINUX_ROOT_DEVICE}"
420527
+
420527
+  initrd_early=
420527
+  for i in ${GRUB_EARLY_INITRD_LINUX_STOCK} \
420527
+	   ${GRUB_EARLY_INITRD_LINUX_CUSTOM}; do
420527
+    if test -e "${dirname}/${i}" ; then
420527
+      initrd_early="${initrd_early} ${i}"
420527
+    fi
420527
+  done
420527
+
420527
+  initrd_real=
420527
+  for i in "initrd.img-${version}" "initrd-${version}.img" "initrd-${version}.gz" \
420527
+	   "initrd-${version}" "initramfs-${version}.img" \
420527
+	   "initrd.img-${alt_version}" "initrd-${alt_version}.img" \
420527
+	   "initrd-${alt_version}" "initramfs-${alt_version}.img" \
420527
+	   "initramfs-genkernel-${version}" \
420527
+	   "initramfs-genkernel-${alt_version}" \
420527
+	   "initramfs-genkernel-${GENKERNEL_ARCH}-${version}" \
420527
+	   "initramfs-genkernel-${GENKERNEL_ARCH}-${alt_version}"; do
420527
+    if test -e "${dirname}/${i}" ; then
420527
+      initrd_real="${i}"
420527
+      break
420527
+    fi
420527
+  done
420527
+
420527
+  initrd=
420527
+  if test -n "${initrd_early}" || test -n "${initrd_real}"; then
420527
+    initrd="${initrd_early} ${initrd_real}"
420527
+
420527
+    initrd_display=
420527
+    for i in ${initrd}; do
420527
+      initrd_display="${initrd_display} ${dirname}/${i}"
420527
+    done
420527
+    if [ "x${GRUB_ENABLE_BLSCFG}" != "xtrue" ]; then
420527
+      gettext_printf "Found initrd image: %s\n" "$(echo $initrd_display)" >&2
420527
+    fi
420527
+  fi
420527
+
420527
+  fdt=
420527
+  for i in "dtb-${version}" "dtb-${alt_version}"; do
420527
+    if test -f "${dirname}/${i}/${GRUB_DEFAULT_DTB}" ; then
420527
+      fdt="${i}/${GRUB_DEFAULT_DTB}"
420527
+      break
420527
+    fi
420527
+  done
420527
+
420527
+  config=
420527
+  for i in "${dirname}/config-${version}" "${dirname}/config-${alt_version}" "/etc/kernels/kernel-config-${version}" ; do
420527
+    if test -e "${i}" ; then
420527
+      config="${i}"
420527
+      break
420527
+    fi
420527
+  done
420527
+
420527
+  initramfs=
420527
+  if test -n "${config}" ; then
420527
+      initramfs=`grep CONFIG_INITRAMFS_SOURCE= "${config}" | cut -f2 -d= | tr -d \"`
420527
+  fi
420527
+
420527
+  if test -z "${initramfs}" && test -z "${initrd_real}" ; then
420527
+    # "UUID=" and "ZFS=" magic is parsed by initrd or initramfs.  Since there's
420527
+    # no initrd or builtin initramfs, it can't work here.
420527
+    if [ "x${GRUB_DEVICE_PARTUUID}" = "x" ] \
420527
+	|| [ "x${GRUB_DISABLE_LINUX_PARTUUID}" = "xtrue" ]; then
420527
+
420527
+	linux_root_device_thisversion=${GRUB_DEVICE}
420527
+    else
420527
+	linux_root_device_thisversion=PARTUUID=${GRUB_DEVICE_PARTUUID}
420527
+    fi
420527
+  fi
420527
+
420527
+  if [ "x${GRUB_DISABLE_SUBMENU}" = "xyes" ] || [ "x${GRUB_DISABLE_SUBMENU}" = "xy" ]; then
420527
+    GRUB_DISABLE_SUBMENU="true"
420527
+  fi
420527
+
420527
+  if [ "x$is_top_level" = xtrue ] && [ "x${GRUB_DISABLE_SUBMENU}" != xtrue ]; then
420527
+    linux_entry "${OS}" "${version}" simple standard \
420527
+    "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
420527
+    if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then
420527
+      linux_entry "${OS}" "${version}" simple debug \
420527
+        "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} ${GRUB_CMDLINE_LINUX_DEBUG}"
420527
+    fi
420527
+
420527
+    submenu_indentation="$grub_tab"
420527
+
420527
+    if [ -z "$boot_device_id" ]; then
420527
+	boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
420527
+    fi
420527
+    # TRANSLATORS: %s is replaced with an OS name
420527
+    echo "submenu '$(gettext_printf "Advanced options for %s" "${OS}" | grub_quote)' \$menuentry_id_option 'gnulinux-advanced-$boot_device_id' {"
420527
+    is_top_level=false
420527
+  fi
420527
+
420527
+  linux_entry "${OS}" "${version}" advanced standard \
420527
+              "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
420527
+  if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then
420527
+    linux_entry "${OS}" "${version}" advanced debug \
420527
+                "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} ${GRUB_CMDLINE_LINUX_DEBUG}"
420527
+  fi
420527
+
420527
+  if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then
420527
+    linux_entry "${OS}" "${version}" recovery standard \
420527
+                "single ${GRUB_CMDLINE_LINUX}"
420527
+  fi
420527
+
420527
+  list=`echo $list | tr ' ' '\n' | fgrep -vx "$linux" | tr '\n' ' '`
420527
+done
420527
+
420527
+# If at least one kernel was found, then we need to
420527
+# add a closing '}' for the submenu command.
420527
+if [ x"$is_top_level" != xtrue ]; then
420527
+  echo '}'
420527
+fi
420527
+
420527
+echo "$title_correction_code"