summaryrefslogtreecommitdiff
path: root/mkinitramfs
blob: 27998389d69be98c1a411f8271f4c33647d48604 (plain)
    1 #!/usr/bin/env bash
    2 # Mkinitramfs creates a basic init ram fs with encryption support.
    3 # Copyright (C)  2023  Aaron Ball <nullspoon@oper.io>
    4 #
    5 # This program is free software: you can redistribute it and/or modify
    6 # it under the terms of the GNU General Public License as published by
    7 # the Free Software Foundation, either version 3 of the License, or
    8 # (at your option) any later version.
    9 #
   10 # This program is distributed in the hope that it will be useful,
   11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
   12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13 # GNU General Public License for more details.
   14 #
   15 # You should have received a copy of the GNU General Public License
   16 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
   17 
   18 
   19 # Hash of fully-qualified binaries
   20 declare -a fqbins
   21 
   22 #
   23 # Searches PATH for all binaries listed as function arguments. Each found
   24 # binary is then put into the global "bins" array.
   25 #
   26 # This function also serves to ensure all specified binaries are present and
   27 # in PATH. It will exit code 1 with an error message if any binaries are not
   28 # found.
   29 #
   30 # Note: To use this function, insert "declare -a fqbins" at top of script).
   31 #
   32 # @param bins All function arguments are the names of binaries to locate.
   33 #
   34 resolve_bins() {
   35   local args=${@}
   36   local path=''
   37 
   38   for i in ${args[@]}; do
   39     if ! path="$(type -p ${i} 2>/dev/null)"; then
   40       printf 'Could not find binary %s. Is it installed?\n' "${i}"
   41       exit 1
   42     fi
   43 
   44     printf 'Located %s at %s\n' "${i}" "${path}"
   45     fqbins+=("${path}")
   46   done
   47 }
   48 
   49 
   50 #
   51 # Gets first path locatable in a string
   52 #
   53 get_first_path() {
   54   local str="${1:-}"
   55   local out=''
   56 
   57   # Find the first occurrence of `/`
   58   for ((i=0; i<${#str}; i++)); do
   59     [ "${str:$i:1}" = '/' ] && break
   60   done
   61 
   62   # Exit if no path found
   63   [ "${i}" -eq "${#str}" ] && return 2
   64 
   65   # Find end of string by looking for space
   66   while [ "${str:$i:1}" != ' ' ] && [ "${i}" -lt "${#str}" ]; do
   67     out="${out}${str:$i:1}"
   68     (( i += 1 ))
   69   done
   70   printf '%s\n' "${out}"
   71 }
   72 
   73 
   74 get_deps() {
   75   local bin="${1:-}"
   76   for dep in $(ldd ${bin}); do
   77      get_first_path "${dep}"
   78   done
   79 }
   80 
   81 
   82 #
   83 # Creates cpio file for specified initrd cache directory.
   84 # Outputs to /boot/initrd-${version}.
   85 #
   86 # @param cache   Path to the uncompressed source directory to be archived
   87 # @param version Version of initrd archive
   88 #
   89 mkcpio() {
   90   [ -z "${1:-}" ] && printf 'Initramfs cache path required.\n' && exit 1
   91   [ -z "${2:-}" ] && printf 'Kernel version required.\n' && exit 1
   92 
   93   local cache="${1}"
   94   local version="${2}"
   95 
   96   cd "${cache}"
   97   fspath="/boot/initrd-${version}"
   98 
   99   # Notify user of initrd overwriting
  100   [ -f "${fspath}" ] && printf "\n\n%s exists. Overwriting.\n" "${fspath}"
  101 
  102   # Create the initrd
  103   printf 'Building initrd to %s\n' "${fspath}"
  104   find . -print0 | cpio --null -o --format=newc | xz -C crc32 -9 -c > "${fspath}"
  105 }
  106 
  107 
  108 #
  109 # Sets up cache dir for later writing to an archive (via cpio).
  110 # Performs simple operations like creating a basic directory structure,
  111 #
  112 # @param cache Path to the cache directory. Will be created if not exists
  113 #
  114 cache_dir_setup() {
  115   [ -z "${1}" ] && printf 'Please specify a cache dir.\n' && exit 1
  116   local cache="${1:-}"
  117 
  118   # Clean the cache so we start fresh
  119   rm -r "${cache:?}" && mkdir "${cache}"
  120 
  121   # Create the temporary directory structure
  122   for i in bin dev etc lib lib32 lib64 mnt/root proc root run sbin sys usr/share; do
  123     mkdir -p "${cache}/${i}"
  124   done
  125 
  126   # Copy in terminals database for `l` (linux - stock tty)
  127   mkdir -p "${cache}/usr/share/terminfo"
  128   cp -r /usr/share/terminfo/l "${cache}/usr/share/terminfo/l"
  129 }
  130 
  131 
  132 #
  133 # Checks installed kernel modules for the specified version to see if the
  134 # corresponding kernel has encryption support statically compiled in.
  135 #
  136 # @param version Version of kernel modules to check
  137 #
  138 check_crypto_support() {
  139   [ -z "${1:-}" ] && printf 'Kernel version required.\n' && exit 1
  140   local version="${1}"
  141   local buf=''
  142   local -a copy=(
  143     arch/x86/crypto
  144     crypto
  145     drivers/input/{keyboard,serio,*.ko}
  146     drivers/{crypto,usb,platform,md}
  147     lib
  148     fs/{btrfs,xfs,ext4}
  149   )
  150 
  151   mkdir -p "${cache}/lib/modules/${version}"
  152   cp -v /lib/modules/${version}/modules*.bin "${cache}/lib/modules/${version}/"
  153 
  154   # Copy in all the rewuired kernel modules
  155   for i in ${copy[@]}; do
  156     buf=(/lib/modules/${version}/kernel/${i})
  157     # For globbing in the array
  158     for ent in ${buf[@]}; do
  159       printf 'Copying in %s\n' "${ent}"
  160       mkdir -p "$(dirname ${cache}/${ent})"
  161       cp -r "${ent}" "${cache}/${ent}"
  162     done
  163   done
  164 }
  165 
  166 
  167 #
  168 # Checks to see if kernel modules for the specified version have been
  169 # installed.
  170 #
  171 # @param version Version to check for installation status
  172 #
  173 check_kernel_version() {
  174   [ -z ${1} ] && printf 'Kernel version required.\n' && exit 1
  175   local version="${1}"
  176   local modulespath="/lib/modules/${version}"
  177 
  178   if [ ! -d ${modulespath} ]; then
  179     printf 'Error: Could not find %s.\n' "${modulespath}"
  180     printf 'Has kernel version %s been comiled?' "${version}"
  181     exit 1
  182   fi
  183 }
  184 
  185 
  186 main() {
  187   [ -z "${1:-}" ] && printf 'Please specify a kernel version\n' && exit 1
  188 
  189   local version=${1}
  190 
  191   check_kernel_version ${version}
  192 
  193   local cache='/tmp/initrd'
  194   local res_path=/usr/share/mkinitramfs/
  195 
  196   # Ensure init script has no syntax errors (linting process)
  197   if ! bash -n ${res_path}/init; then
  198     printf '\n\nERROR: Syntax errors were found in the init script.\n'
  199     printf 'Please resolve the above issues and try again.\n'
  200     printf 'Exiting to avoid creating an unbootable initramfs.\n\n'
  201     return 1
  202   fi
  203 
  204   # List of binaries to exist in the new initramfs
  205   # Standard shell binaries
  206   resolve_bins bash pidof ps ls grep less switch_root kill
  207   # Module management
  208   resolve_bins udevadm udevd modprobe rmmod
  209   # For encrypted and block device support
  210   resolve_bins partprobe dmsetup mount umount cryptsetup
  211 
  212   # For debugging
  213   #resolve_bins sleep mkdir chmod chown tr clear cat
  214 
  215   # Set up the archive source dir.
  216   cache_dir_setup ${cache}
  217 
  218   # Ensure static crypto support exists in kernel
  219   check_crypto_support ${version}
  220 
  221   # Copy in libgcc_s for newer cryptsetup
  222   install -v -D /usr/lib/libgcc_s.so   "${cache}/usr/lib/libgcc_s.so"
  223   install -v -D /usr/lib/libgcc_s.so.1 "${cache}/usr/lib/libgcc_s.so.1"
  224 
  225   # Install udev rules for block devices
  226   mkdir -p "${cache}/lib/udev"
  227   cp -rv /lib/udev/rules.d "${cache}/lib/udev/rules.d"
  228 
  229   # Copy binary and dependencies to cache dir
  230   for bin in ${fqbins[@]}; do
  231     # Copy the binary of interest
  232     install -v -D "${bin}" "${cache}/${bin}"
  233 
  234     local deps=$(get_deps ${bin})
  235     # Copy each of the binary's deps
  236     for dep in ${deps[@]}; do
  237       install -v -D ${dep} "${cache}/${dep}"
  238     done
  239   done
  240 
  241   # Copy in message file
  242   [ -f "/etc/msg" ] && install -v -D "/etc/msg" "${cache}/etc/msg"
  243   # Copy in init script and add execute
  244   install -v -D -m 755 "${res_path}/init" "${cache}/init"
  245   # Copy in the system shell profile
  246   install -v -D "/etc/profile" "${cache}/etc/profile"
  247 
  248   # Create archive image
  249   mkcpio ${cache} ${version}
  250 }
  251 
  252 main ${@}

Generated by cgit