summaryrefslogtreecommitdiff
path: root/mkinitramfs
blob: 70802a2135ab10806efbb66e8fd67c40d5ecfdcd (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 function resolve_bins {
   35   local args=${@}
   36 
   37   for i in ${args[@]}; do
   38     local path=$(type -p ${i} 2>/dev/null)
   39 
   40     if [[ $? -gt 0 ]]; then
   41       echo "Could not find binary ${i}. Is it installed?"
   42       exit 1
   43     fi
   44 
   45     echo "Located ${i} at ${path}"
   46     fqbins+=("${path}")
   47   done
   48 }
   49 
   50 
   51 #
   52 # Gets first path locatable in a string
   53 #
   54 function get_first_path {
   55   local str=${1}
   56 
   57   local out=''
   58   local cursor=''
   59 
   60   for ((i=0; i<${#str}; i++)); do
   61     if [[ ${str:$i:1} == '/' ]]; then
   62       cursor=${i}
   63       break
   64     fi
   65   done
   66 
   67   # Exit if no path found
   68   [[ ${cursor} == '' ]] && return
   69 
   70   while [[ ${str:$cursor:1} != ' ' ]] && [[ ${cursor} -lt ${#str} ]]; do
   71     out="${out}${str:$cursor:1}"
   72     cursor=$((${cursor} + 1))
   73   done
   74 
   75   echo "${out}"
   76 }
   77 
   78 
   79 function get_deps {
   80   local bin=${1}
   81 
   82   for dep in $(ldd ${bin}); do
   83      get_first_path "${dep}"
   84   done
   85 }
   86 
   87 
   88 #
   89 # Creates cpio file for specified initrd cache directory.
   90 # Outputs to /boot/initrd-${version}.
   91 #
   92 # @param cache   Path to the uncompressed source directory to be archived
   93 # @param version Version of initrd archive
   94 #
   95 function mkcpio {
   96   [[ -z ${1} ]] && echo "Initramfs cache path required." && exit 1
   97   [[ -z ${2} ]] && echo "Kernel version required." && exit 1
   98 
   99   local cache=${1}
  100   local version=${2}
  101 
  102   cd ${cache}
  103   fspath="/boot/initrd-${version}"
  104 
  105   # Notify user of initrd overwriting
  106   [[ -f ${fspath} ]] && echo -e "\n\n${fspath} exists. Overwriting.\n"
  107 
  108   # Create the initrd
  109   echo "Building initrd to ${fspath}"
  110   find . -print0 | cpio --null -o --format=newc | xz -C crc32 -9 -c > ${fspath}
  111 }
  112 
  113 
  114 #
  115 # Sets up cache dir for later writing to an archive (via cpio).
  116 # Performs simple operations like creating a basic directory structure,
  117 #
  118 # @param cache Path to the cache directory. Will be created if not exists
  119 #
  120 function cache_dir_setup {
  121   [[ -z ${1} ]] && echo "Please specify a cache dir." && exit 1
  122   local cache=${1}
  123 
  124   # Clean the cache so we start fresh
  125   rm -rf ${cache} && mkdir ${cache}
  126 
  127   local dirs=(bin dev etc lib lib32 lib64 mnt/root proc root run sbin sys usr)
  128 
  129   # Create the temporary directory structure
  130   for i in ${dirs[*]}; do
  131     mkdir -p ${cache}/${i}
  132   done
  133 
  134   # Copy in terminals database
  135   mkdir -p "${cache}/usr/share"
  136   cp -r /usr/share/terminfo "${cache}/usr/share/terminfo"
  137 }
  138 
  139 
  140 #
  141 # Checks installed kernel modules for the specified version to see if the
  142 # corresponding kernel has encryption support statically compiled in.
  143 #
  144 # @param version Version of kernel modules to check
  145 #
  146 function check_crypto_support {
  147   [[ -z ${1} ]] && echo "Kernel version required." && exit 1
  148   local version=${1}
  149   local buf=''
  150 
  151   builtinpath=/lib/modules/${version}/modules.builtin
  152 
  153   mkdir -p ${cache}/lib/modules/
  154   cp -vr "/lib/modules/${version}/" "${cache}/lib/modules/${version}"
  155 
  156   # Strip out kernel modules not required for bootstrapping
  157   for i in virt net sound drivers/gpu drivers/bluetooth drivers/video; do
  158     buf="${cache}/lib/modules/${version}/kernel/${i}"
  159     if [ -d "${buf}" ]; then
  160       printf 'Stripping %s from initramfs\n' "${buf}"
  161       rm -r "${buf:?}"
  162     fi
  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 function check_kernel_version {
  174   [[ -z ${1} ]] && echo "Kernel version required." && exit 1
  175   local version=${1}
  176 
  177   modulespath=/lib/modules/${version}
  178   if [[ ! -d ${modulespath} ]]; then
  179     echo "Error: Could not find ${modulespath}."
  180     echo "Has kernel version ${version} been comiled?"
  181     exit 1
  182   fi
  183 }
  184 
  185 
  186 function main {
  187   [[ -z ${1} ]] && echo "Please specify a kernel version" && 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