blob: 52e01650df36c9e15e232af857be4a022fa1926a (
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=$(which ${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 resolve_bins \
207 bash cat echo ls cryptsetup chmod chown mount sleep umount clear cut \
208 grep less tr which blkid partprobe reboot shutdown switch_root modprobe \
209 rmmod
210
211 # Set up the archive source dir.
212 cache_dir_setup ${cache}
213
214 # Ensure static crypto support exists in kernel
215 check_crypto_support ${version}
216
217 # Copy in libgcc_s for newer cryptsetup
218 install -v -D /usr/lib/libgcc_s.so "${cache}/usr/lib/libgcc_s.so"
219 install -v -D /usr/lib/libgcc_s.so.1 "${cache}/usr/lib/libgcc_s.so.1"
220
221 # Copy binary and dependencies to cache dir
222 for bin in ${fqbins[@]}; do
223 # Copy the binary of interest
224 install -v -D "${bin}" "${cache}/${bin}"
225
226 local deps=$(get_deps ${bin})
227 # Copy each of the binary's deps
228 for dep in ${deps[@]}; do
229 install -v -D ${dep} "${cache}/${dep}"
230 done
231 done
232
233 # Copy in message file
234 [ -f "/etc/msg" ] && install -v -D "/etc/msg" "${cache}/etc/msg"
235 # Copy in init script and add execute
236 install -v -D -m 755 "${res_path}/init" "${cache}/init"
237 # Copy in the system shell profile
238 install -v -D "/etc/profile" "${cache}/etc/profile"
239
240 # Create archive image
241 mkcpio ${cache} ${version}
242 }
243
244 main ${@}
|