summaryrefslogtreecommitdiff
path: root/mkinitramfs
blob: 5d35386e89c0a7cfa7eaae674645225c723f3e0d (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 #
   24 # Searches PATH for all binaries listed as function arguments. Each found
   25 # binary is then put into the global "bins" array.
   26 #
   27 # This function also serves to ensure all specified binaries are present and
   28 # in PATH. It will exit code 1 with an error message if any binaries are not
   29 # found.
   30 #
   31 # Note: To use this function, insert "declare -a fqbins" at top of script).
   32 #
   33 # @param bins All function arguments are the names of binaries to locate.
   34 #
   35 function resolve_bins {
   36   local args=${@}
   37 
   38   for i in ${args[@]}; do
   39     local path=$(type -p ${i} 2>/dev/null)
   40 
   41     if [[ $? -gt 0 ]]; then
   42       echo "Could not find binary ${i}. Is it installed?"
   43       exit 1
   44     fi
   45 
   46     echo "Located ${i} at ${path}"
   47     fqbins+=("${path}")
   48   done
   49 }
   50 
   51 
   52 #
   53 # Gets first path locatable in a string
   54 #
   55 function get_first_path {
   56   local str=${1}
   57 
   58   local out=''
   59   local cursor=''
   60 
   61   for ((i=0; i<${#str}; i++)); do
   62     if [[ ${str:$i:1} == '/' ]]; then
   63       cursor=${i}
   64       break
   65     fi
   66   done
   67 
   68   # Exit if no path found
   69   [[ ${cursor} == '' ]] && return
   70 
   71   while [[ ${str:$cursor:1} != ' ' ]] && [[ ${cursor} -lt ${#str} ]]; do
   72     out="${out}${str:$cursor:1}"
   73     cursor=$((${cursor} + 1))
   74   done
   75 
   76   echo "${out}"
   77 }
   78 
   79 
   80 function get_deps {
   81   local bin=${1}
   82 
   83   for dep in $(ldd ${bin}); do
   84      get_first_path "${dep}"
   85   done
   86 }
   87 
   88 
   89 #
   90 # Creates cpio file for specified initrd cache directory.
   91 # Outputs to /boot/initrd-${version}.
   92 #
   93 # @param cache   Path to the uncompressed source directory to be archived
   94 # @param version Version of initrd archive
   95 #
   96 function mkcpio {
   97   [[ -z ${1} ]] && echo "Initramfs cache path required." && exit 1
   98   [[ -z ${2} ]] && echo "Kernel version required." && exit 1
   99 
  100   local cache=${1}
  101   local version=${2}
  102 
  103   cd ${cache}
  104   fspath="/boot/initrd-${version}"
  105 
  106   # Notify user of initrd overwriting
  107   [[ -f ${fspath} ]] && echo -e "\n\n${fspath} exists. Overwriting.\n"
  108 
  109   # Create the initrd
  110   echo "Building initrd to ${fspath}"
  111   find . -print0 | cpio --null -o --format=newc | xz -C crc32 -9 -c > ${fspath}
  112 }
  113 
  114 
  115 #
  116 # Sets up cache dir for later writing to an archive (via cpio).
  117 # Performs simple operations like creating a basic directory structure,
  118 #
  119 # @param cache Path to the cache directory. Will be created if not exists
  120 #
  121 function cache_dir_setup {
  122   [[ -z ${1} ]] && echo "Please specify a cache dir." && exit 1
  123   local cache=${1}
  124 
  125   # Clean the cache so we start fresh
  126   rm -rf ${cache} && mkdir ${cache}
  127 
  128   local dirs=(bin dev etc lib lib32 lib64 mnt/root proc root run sbin sys usr)
  129 
  130   # Create the temporary directory structure
  131   for i in ${dirs[*]}; do
  132     mkdir -p ${cache}/${i}
  133   done
  134 
  135   # Copy in terminals database
  136   mkdir -p "${cache}/usr/share"
  137   cp -r /usr/share/terminfo "${cache}/usr/share/terminfo"
  138 }
  139 
  140 
  141 #
  142 # Checks installed kernel modules for the specified version to see if the
  143 # corresponding kernel has encryption support statically compiled in.
  144 #
  145 # @param version Version of kernel modules to check
  146 #
  147 function check_crypto_support {
  148   [[ -z ${1} ]] && echo "Kernel version required." && exit 1
  149   local version=${1}
  150   local buf=''
  151 
  152   builtinpath=/lib/modules/${version}/modules.builtin
  153 
  154   mkdir -p ${cache}/lib/modules/
  155   cp -vr "/lib/modules/${version}/" "${cache}/lib/modules/${version}"
  156 
  157   # Strip out kernel modules not required for bootstrapping
  158   for i in virt net sound drivers/gpu drivers/bluetooth drivers/video; do
  159     buf="${cache}/lib/modules/${version}/kernel/${i}"
  160     if [ -d "${buf}" ]; then
  161       printf 'Stripping %s from initramfs\n' "${buf}"
  162       rm -r "${buf:?}"
  163     fi
  164   done
  165 }
  166 
  167 
  168 #
  169 # Checks to see if kernel modules for the specified version have been
  170 # installed.
  171 #
  172 # @param version Version to check for installation status
  173 #
  174 function check_kernel_version {
  175   [[ -z ${1} ]] && echo "Kernel version required." && exit 1
  176   local version=${1}
  177 
  178   modulespath=/lib/modules/${version}
  179   if [[ ! -d ${modulespath} ]]; then
  180     echo "Error: Could not find ${modulespath}."
  181     echo "Has kernel version ${version} been comiled?"
  182     exit 1
  183   fi
  184 }
  185 
  186 
  187 function main {
  188   [[ -z ${1} ]] && echo "Please specify a kernel version" && exit 1
  189 
  190   local version=${1}
  191 
  192   check_kernel_version ${version}
  193 
  194   local cache='/tmp/initrd'
  195   local res_path=/usr/share/mkinitramfs/
  196 
  197   # Ensure init script has no syntax errors (linting process)
  198   if ! bash -n ${res_path}/init; then
  199     printf '\n\nERROR: Syntax errors were found in the init script.\n'
  200     printf 'Please resolve the above issues and try again.\n'
  201     printf 'Exiting to avoid creating an unbootable initramfs.\n\n'
  202     return 1
  203   fi
  204 
  205   # List of binaries to exist in the new initramfs
  206   # Standard shell binaries
  207   resolve_bins bash cat pidof ps ls clear cut grep less blkid switch_root kill
  208   # Module management
  209   resolve_bins udevadm udevd modprobe rmmod
  210   # For encrypted and block device support
  211   resolve_bins partprobe dmsetup mount umount cryptsetup
  212 
  213   # For debugging
  214   #resolve_bins sleep mkdir chmod chown tr
  215 
  216   # Set up the archive source dir.
  217   cache_dir_setup ${cache}
  218 
  219   # Ensure static crypto support exists in kernel
  220   check_crypto_support ${version}
  221 
  222   # Copy in libgcc_s for newer cryptsetup
  223   install -v -D /usr/lib/libgcc_s.so   "${cache}/usr/lib/libgcc_s.so"
  224   install -v -D /usr/lib/libgcc_s.so.1 "${cache}/usr/lib/libgcc_s.so.1"
  225 
  226   # Install udev rules for block devices
  227   mkdir -p "${cache}/lib/udev"
  228   cp -rv /lib/udev/rules.d "${cache}/lib/udev/rules.d"
  229 
  230   # Copy binary and dependencies to cache dir
  231   for bin in ${fqbins[@]}; do
  232     # Copy the binary of interest
  233     install -v -D "${bin}" "${cache}/${bin}"
  234 
  235     local deps=$(get_deps ${bin})
  236     # Copy each of the binary's deps
  237     for dep in ${deps[@]}; do
  238       install -v -D ${dep} "${cache}/${dep}"
  239     done
  240   done
  241 
  242   # Copy in message file
  243   [ -f "/etc/msg" ] && install -v -D "/etc/msg" "${cache}/etc/msg"
  244   # Copy in init script and add execute
  245   install -v -D -m 755 "${res_path}/init" "${cache}/init"
  246   # Copy in the system shell profile
  247   install -v -D "/etc/profile" "${cache}/etc/profile"
  248 
  249   # Create archive image
  250   mkcpio ${cache} ${version}
  251 }
  252 
  253 main ${@}

Generated by cgit