· 7 months ago · Mar 05, 2025, 11:20 AM
1#!/bin/bash -u
2
3# fde-blank
4export DEV=""
5export CRYPTNAME="cryptroot"
6export VGNAME="system"
7export LVROOTNAME="root"
8export LVROOTSIZE="128G"
9export WANTSHOME=1
10export LVHOMENAME="home"
11export LVHOMESIZE="100"
12export LVSWAPNAME="swap"
13export LVSWAPSIZE="8G"
14export EFISIZE="1G"
15export TARGETMOUNTPOINT="/mnt"
16export NEWHOSTNAME="summercamp"
17export WANTSSDGRUB=
18export WANTKEY=
19export KEYDEV=""
20export KEYFORMAT=""
21export UKEYNAME="nixos-boot"
22export KEYNAME="nixos-boot.key"
23export KEYMOUNT="/tmp/stick"
24export KEYDIR="/keys"
25export KEYPATH=""
26export ERASEALL=
27export OVERWRITEINSTALL=
28export SYSCHANGE=
29export KEYCHANGE=
30export PASSPHRASE=
31# Do not touch these variables
32export GREPTEST=" \|\!\|@\|#\|%\|\^\|&\|*\|(\|)\|{\|}\|<\|>\|?\|;\|:\|'\||\|\"\|=\|+\|~\|\`"
33export FDECONFIG="fde-config"
34export BLANKCONFIG="fde-blank"
35
36# Detect UEFI or MBR
37if [ -d /sys/firmware/efi ]; then
38 export ISEFI=1
39 export EFIPARTITION=1
40 export CRYPTPARTITION=2
41else
42 export ISEFI=0
43 export CRYPTPARTITION=1
44fi
45
46# Do not touch this parameter, unless you understand what you are doing.
47# This is a paameter value of the --iter-time option for cyrptsetup command.
48# If you specify 1000, that means 1000mSec. 0 means compile default.
49export ITERTIME=0
50
51# Colors for status/error messages
52export RED="\e[0;31m"
53export GREEN="\e[0;32m"
54export END="\e[0m"
55
56# fde-functions
57function format_dev() {
58 if [[ "${ERASEALL}" -eq 1 ]] ; then
59 # UEFI
60 if [[ "${ISEFI}" -eq 1 ]] ; then
61 send_prog "Initializing ${DEV} with GPT"
62 sgdisk --zap-all "${DEV}"
63 if is_error ; then
64 send_prog "Retrying initialization"
65 sgdisk --zap-all "${DEV}"
66 if is_error ; then return 1 ; fi
67 fi
68 send_prog "Creating an EFI partition on ${DEV}"
69 sgdisk --new="${EFIPARTITION}":0:+"${EFISIZE}" --change-name="${EFIPARTITION}":"EFI System" --typecode="${EFIPARTITION}":ef00 "${DEV}"
70 if is_error ; then return 1 ; fi
71 send_prog "Creating boot filesystem"
72 if ! mkfs.vfat -n boot "${DEV}${EFIPARTITION}" ; then send_error "Making boot filesystem" ; return 1 ; fi
73 send_prog "Creating a Linux partition on ${DEV}"
74 sgdisk --new="${CRYPTPARTITION}":0:0 --change-name="${CRYPTPARTITION}":"Linux LUKS" --typecode="${CRYPTPARTITION}":8309 "${DEV}"
75 if is_error ; then return 1 ; fi
76 sgdisk --print "${DEV}"
77 else
78 send_prog "Erasing partition table of ${DEV}"
79 dd if=/dev/zero of="${DEV}" bs=512 count=1
80 if is_error ; then return 1 ; fi
81 send_prog "Creating a Linux partition on ${DEV} with MBR"
82 sfdisk "${DEV}" <<- HEREDOC
832M,,L
84HEREDOC
85 if is_error ; then return 1 ; fi
86 fi
87 fi
88}
89
90function encrypt_dev() {
91 send_prog "Initializing ${DEV}${CRYPTPARTITION} as crypt partition"
92 if [[ "${ISEFI}" -eq 1 ]]; then
93 printf %s "${PASSPHRASE}" | cryptsetup luksFormat --iter-time "${ITERTIME}" --key-file - --batch-mode "${DEV}${CRYPTPARTITION}" >/dev/null 2>&1
94 else
95 printf %s "${PASSPHRASE}" | cryptsetup luksFormat --iter-time "${ITERTIME}" --type=luks1 --key-file - --batch-mode "${DEV}${CRYPTPARTITION}" >/dev/null 2>&1
96 fi
97 send_prog "Opening crypt partition ${DEV}${CRYPTPARTITION} as ${CRYPTNAME}"
98 printf %s "${PASSPHRASE}" | cryptsetup open -d - "${DEV}${CRYPTPARTITION}" "${CRYPTNAME}" >/dev/null 2>&1
99 send_prog "Creating physical volume on ${CRYPTNAME}"
100 if ! pvcreate "/dev/mapper/${CRYPTNAME}" >/dev/null 2>&1; then return 1 ; fi
101 send_prog "Creating volume group ${VGNAME}"
102 if ! vgcreate "${VGNAME}" "/dev/mapper/${CRYPTNAME}" >/dev/null 2>&1; then return 1 ; fi
103 if [[ "${WANTSHOME}" -eq 1 ]]; then
104 send_prog "Creating logical volume for root : ${LVROOTNAME}"
105 if ! lvcreate -n "${LVROOTNAME}" -L "${LVROOTSIZE}" "${VGNAME}" >/dev/null 2>&1; then return 1 ; fi
106 send_prog "Creating logical volume for swap : ${LVSWAPNAME}"
107 if ! lvcreate -n "${LVSWAPNAME}" -L "${LVSWAPSIZE}" "${VGNAME}" >/dev/null 2>&1; then return 1 ; fi
108 send_prog "Creating logical volume for home : ${LVHOMENAME}"
109 if ! lvcreate -n "${LVHOMENAME}" -l "${LVHOMESIZE}%FREE" "${VGNAME}" >/dev/null 2>&1; then return 1 ; fi
110 else
111 send_prog "Creating logical volume for swap : ${LVSWAPNAME}"
112 if ! lvcreate -n "${LVSWAPNAME}" -L "${LVSWAPSIZE}" "${VGNAME}" >/dev/null 2>&1; then return 1 ; fi
113 send_prog "Creating logical volume for root : ${LVROOTNAME}"
114 if ! lvcreate -n "${LVROOTNAME}" -l "${LVROOTSIZE}%FREE" "${VGNAME}" >/dev/null 2>&1; then return 1 ; fi
115 fi
116}
117
118function reformat_key() {
119 if [[ "${KEYFORMAT}" -eq 1 ]]; then
120 send_prog "Reformating ${KEYDEV}"
121 if ! mkfs.vfat -F 32 -n "BOOT_KEY" "${KEYDEV}" >/dev/null 2>&1; then
122 send_error "Reformatting ${KEYDEV} to ${KEYFSTYPE}" ; return 1
123 fi
124 elif [[ "${KEYFORMAT}" =~ ^[2-4]$ ]]; then
125 send_prog "Reformating ${KEYDEV} to ${KEYFSTYPE}"
126 if ! mkfs."${KEYFSTYPE}" -L "BOOT_KEY" "${KEYFLAG}" "${KEYDEV}" >/dev/null 2>&1; then
127 send_error "Reformating ${KEYDEV} to ${KEYFSTYPE}" ; return 1
128 fi
129 else
130 send_error "With key format variable : ${KEYFORMAT}"
131 fi
132}
133
134function luks_add_keyfile() {
135 if [[ ! -d "${KEYMOUNT}" ]] && [[ "${WANTKEY}" -eq 1 ]] ; then
136 send_prog "Making direcotry ${KEYMOUNT}"
137 mkdir -p "${KEYMOUNT}"
138 fi
139 send_prog "Mounting ${KEYDEV} at ${KEYMOUNT}"
140 if ! mount "${KEYDEV}" "${KEYMOUNT}" >/dev/null 2>&1; then send_error "Mounting ${KEYDEV} at ${KEYMOUNT}" ; return 1 ; fi
141 if [[ ! -d "${KEYMOUNT}/${KEYDIR}" ]]; then
142 send_prog "Creating directory ${KEYDIR} on ${KEYDEV}"
143 mkdir -p "${KEYMOUNT}/${KEYDIR}"
144 else
145 send_prog "${KEYDIR} already exists on ${KEYDEV} checking for keyfile"
146 fi
147 if [[ ! -e "${KEYMOUNT}"/"${KEYPATH}" ]]; then
148 send_prog "Creating keyfile ${KEYNAME} on ${KEYDEV}"
149 if ! dd bs=512 count=4 if=/dev/urandom of="${KEYMOUNT}/${KEYPATH}" iflag=fullblock ; then
150 send_error "Creating keyfile : ${KEYNAME}"
151 return 1
152 fi
153 else
154 send_prog "${KEYNAME} already exists, skipping"
155 fi
156 if ! chmod u=rx,go-rwx "${KEYMOUNT}/${KEYDIR}" ; then send_error "Chmoding ${KEYMOUNT}/${KEYDIR}" ; return 1 ; fi
157 if ! chmod u=r,go-rwx "${KEYMOUNT}""${KEYPATH}" ; then send_error "Chmoding ${KEYMOUNT}/${KEYPATH}" ; return 1 ; fi
158 send_prog "Adding keyfile, ${KEYNAME}, to ${DEV}${CRYPTPARTITION}"
159 printf %s "${PASSPHRASE}" | cryptsetup luksAddKey --iter-time "${ITERTIME}" -d - "${DEV}${CRYPTPARTITION}" "${KEYMOUNT}""${KEYPATH}"
160 send_prog "Unmounting ${KEYDEV}"
161 if ! umount -f "${KEYMOUNT}" ; then send_error "Unmounting ${KEYDEV} at ${KEYMOUNT}" ; return 1 ; fi
162}
163
164function make_filesystem() {
165 send_prog "Creating root filesystem"
166 if ! mkfs.ext4 -L root "/dev/${VGNAME}/${LVROOTNAME}" >/dev/null 2>&1; then send_error "Making root filesystem" ; return 1 ; fi
167 send_prog "Creating swap"
168 if ! mkswap -L swap "/dev/${VGNAME}/${LVSWAPNAME}" >/dev/null 2>&1; then send_error "Creating swap" ; return 1 ; fi
169 if [[ "${WANTSHOME}" -eq 1 ]]; then
170 send_prog "Creating home filesystem"
171 if ! mkfs.ext4 -L home "/dev/${VGNAME}/${LVHOMENAME}" >/dev/null 2>&1; then send_error "Making home filesystem" ; return 1 ; fi
172 fi
173}
174
175function mount_filesystem() {
176 send_prog "Mounting root file system"
177 if ! mount "/dev/${VGNAME}/${LVROOTNAME}" "${TARGETMOUNTPOINT}" ; then return 1 ; fi
178 if [[ "${WANTSHOME}" -eq 1 ]]; then
179 send_prog "Creating /home"
180 if ! mkdir -p "${TARGETMOUNTPOINT}/home" ; then return 1 ; fi
181 send_prog "Mounting /home"
182 if ! mount "/dev/${VGNAME}/${LVHOMENAME}" "${TARGETMOUNTPOINT}/home" ; then return 1 ; fi
183 fi
184 if [[ "${ISEFI}" -eq 1 ]]; then
185 send_prog "Creating /boot"
186 if ! mkdir -p "${TARGETMOUNTPOINT}/boot" ; then return 1 ; fi
187 send_prog "Mounting /boot"
188 if ! mount -o umask=0077 "${DEV}${EFIPARTITION}" "${TARGETMOUNTPOINT}/boot" ; then return 1 ; fi
189 fi
190 send_prog "Turning swap on"
191 if ! swapon "/dev/${VGNAME}/${LVSWAPNAME}" ; then return 1 ; fi
192}
193
194function generate_config() {
195 send_prog "Generate NixOS base config"
196 nixos-generate-config --root "${TARGETMOUNTPOINT}"
197}
198
199function edit_config() {
200 send_prog "Edit hardware.config"
201 sudoedit "${TARGETMOUNTPOINT}/etc/nixos/hardware-configuration.nix"
202 send_prog "Edit base.config"
203 sudoedit "${TARGETMOUNTPOINT}/etc/nixos/configuration.nix"
204}
205
206function start_install() {
207 send_prog "Start base installation"
208 nixos-install
209}
210
211
212function is_error() {
213if [[ $? -eq 0 ]] ; then
214 return 1
215else
216 term_message
217 return 0
218fi;
219}
220
221function send_prog() {
222 echo -e "${GREEN}...${1}${END}"
223}
224
225function send_error() {
226 echo -e "${RED}***** ERROR : ${1} *****${END}"
227}
228
229function term_message() {
230 echo -e "${RED}***** Installation process terminated *****${END}"
231}
232
233function remove_key() {
234 if ! mount "${KEYDEV}" "${KEYMOUNT}" ; then
235 send_error "Failed to mount ${KEYDEV} at ${KEYMOUNT}"
236 fi
237 if ! rm -f -- "${KEYMOUNT}"/"${KEYPATH}" ; then
238 send_error "Failed to remove keyfile at ${KEYMOUNT}${KEYPATH}"
239 fi
240 if ! umount "${KEYMOUNT}" ; then return 1 ; fi
241}
242
243function close_and_unmount() {
244 echo -e "${RED}***** CLOSING AND UNMOUNTING FILE SYSTEM *****${END}"
245 umount "${TARGETMOUNTPOINT}/home"
246 umount "${TARGETMOUNTPOINT}/boot"
247 swapoff "/dev/mapper/${VGNAME}-${LVSWAPNAME}"
248 umount "${TARGETMOUNTPOINT}"
249 umount "${KEYMOUNT}"
250 vgchange -an
251 cryptsetup close "${CRYPTNAME}"
252}
253
254function usage() {
255 cat <<EOF
256Usage : fde-install [options]
257
258Options:
259 -c [file] Uses a config file instead of the user being queried
260 for script options. If no config file is provided
261 then ${FDECONFIG} will be used if present in the
262 working directory. Any var not set or set improperly
263 will result in the user being queried for said var.
264
265 --no-home A logical volume for /home will be not be created
266 during the installation process.
267
268 -h, --help Show this help message and exit.
269EOF
270}
271
272function get_opts() {
273while : ; do
274 if [[ $# -ge 1 ]]; then
275 case $1 in
276 -h | --help) usage ; return 1 ; break ;;
277 --no-home) export WANTSHOME=0
278 export ROOTSIZE=100
279 shift ;;
280 -c) shift
281 if [[ $# -ge 1 ]] && [[ "$1" != -* ]]; then
282 FDECONFIG="$1"
283 if [[ -e "${FDECONFIG}" ]]; then
284 source "${FDECONFIG}"
285 export CONFIGUSED=1
286 shift
287 else
288 echo -e "${RED}Config file does not exist : ${FDECONFIG}${END}"
289 return 1
290 fi
291 elif [[ $# -ge 1 ]] && [[ "$1" == -* ]]; then
292 if [[ -e "${FDECONFIG}" ]]; then
293 source "${FDECONFIG}"
294 export CONFIGUSED=1
295 continue
296 fi
297 else
298 if [[ -e "${FDECONFIG}" ]]; then
299 source "${FDECONFIG}"
300 export CONFIGUSED=1
301 break
302 else
303 echo -e "${RED}Config file does not exist : ${FDECONFIG}${END}"
304 return 1
305 break
306 fi
307 fi
308 ;;
309 -*) echo -e "${RED}Unrecognized option: ${END}${1}" >&2
310 usage
311 return 1
312 break
313 ;;
314 *)
315 break ;;
316 esac
317 else
318 break
319 fi
320done
321}
322
323# fde-prompts
324function system_prompts() {
325
326 # ERASEALL prompt
327 while [[ -z "${ERASEALL}" ]] || [[ ! "${ERASEALL}" =~ ^[0-1]$ ]]; do
328 clear
329 echo -e "${RED}\
330This script will erase all the data on the install target${END}
3310 : Do not proceed, I don't want to erase anything
3321 : Yes, I want to erase the contents of my device"
333 read -rp "Proceed? " ERASEALL
334 export ERASEALL
335 done
336
337 if [[ "${ERASEALL}" -eq 0 ]]; then return 1 ; fi
338
339 # LUKS passphrase prompt
340 while [[ -z "${PASSPHRASE}" ]]; do
341 clear
342 echo -e "${GREEN}Type LUKS encryption passprhase${END}"
343 read -sr PASSPHRASE
344 export PASSPHRASE
345 echo -e "${GREEN}Type LUKS passprhase again${END}"
346 read -sr PASSPHRASE_C
347 export PASSPHRASE_C
348 while [[ "${PASSPHRASE}" != "${PASSPHRASE_C}" ]]; do
349 clear
350 echo -e "${RED}Passphrases did not match, try again${END}"
351 read -sr PASSPHRASE
352 export PASSPHRASE
353 echo -e "${GREEN}Type passprhase again${END}"
354 read -sr PASSPHRASE_C
355 export PASSPHRASE_C
356 done
357 done
358
359 # ROOTPASS prompt
360 while [[ -z "${ROOTPASS}" ]] ; do
361 clear
362 echo -e "${GREEN}Please specify your root password for your new system${END}"
363 read -sr ROOTPASS
364 export ROOTPASS
365 echo -e "${GREEN}Type password again${END}"
366 read -sr ROOTPASS_C
367 export ROOTPASS_C
368 while [[ "${ROOTPASS}" != "${ROOTPASS_C}" ]]; do
369 clear
370 echo -e "${RED}Passphrases did not match, try again${END}"
371 read -sr ROOTPASS
372 export ROOTPASS
373 echo -e "${GREEN}Type passprhase again${END}"
374 read -sr ROOTPASS_C
375 export ROOTPASS_C
376 done
377 done
378
379 # DEV prompt
380 while [[ -z "${DEV}" ]] || [[ ! -e "${DEV}" ]] || ! echo "${DEV}" | grep -q -v "[0-9]$" ; do
381 clear
382 lsblk
383 echo -e "${GREEN}\
384Please choose a target for installation${END}
385i.e. ${GREEN}/dev/sda${END} and not ${RED}/dev/sda1${END}"
386 read -rp "Use dev: " DEV
387 export DEV
388 done
389
390 # TARGETMOUNTPOINT prompt
391 while [[ -z "${TARGETMOUNTPOINT}" ]] || ! echo "${TARGETMOUNTPOINT}" | grep -q "^/" || grep -sq " ${TARGETMOUNTPOINT}" /proc/mounts || echo "${TARGETMOUNTPOINT}" | grep -q "${GREPTEST}"; do
392 clear
393 if [[ -n "${TARGETMOUNTPOINT}" ]] && grep -sq " ${TARGETMOUNTPOINT}" /proc/mounts ; then
394 echo -e "${RED}The given directory is occupied. Please select a free mount point.${END}"
395 fi
396 echo -e "${GREEN}\
397Please specify a mount point for /dev/${VGNAME}/${LVROOTNAME}${END}
398If the directory does not exist, it will be created"
399 read -rp "Target mount point: " TARGETMOUNTPOINT
400 export TARGETMOUNTPOINT
401 done
402
403 # CRYPTNAME prompt
404 while [[ -z "${CRYPTNAME}" ]] || echo "${CRYPTNAME}" | grep -q "${GREPTEST}\|/" ; do
405 clear
406 echo -e "${GREEN}\
407Please choose a sane name for your encrypted drive i.e. arch-crypt${END}
408Do not include spaces, or special characters"
409 read -rp "Crypt name: " CRYPTNAME
410 export CRYPTNAME
411 done
412
413 # NEWHOSTNAME prompt
414 while [[ -z "${NEWHOSTNAME}" ]] || echo "${NEWHOSTNAME}" | grep -q "${GREPTEST}\|/"; do
415 clear
416 echo -e "${GREEN}\
417Please specify the hostname of the new system${END}
418Do not include spaces, or special characters"
419 read -rp "New hostname: " NEWHOSTNAME
420 export NEWHOSTNAME
421 done
422
423 # VGNAME prompt
424 while [[ -z "${VGNAME}" ]] || echo "${VGNAME}" | grep -q "${GREPTEST}\|-\|/" -i ; do
425 clear
426 echo -e "${GREEN}\
427Please choose a volume group name${END}
428Do not include spaces, special characters, or a minus"
429 read -rp "Volume group name: " VGNAME
430 export VGNAME
431 done
432
433 # WANTSHOME prompt
434 while [[ -z "${WANTSHOME}" ]] || [[ ! "${WANTSHOME}" =~ ^[0-1]$ ]] ; do
435 clear
436 echo -e "${GREEN}\
437Would you like to create a seprate logical volume for home?${END}
4380 : Do not create a separate LV for home
4391 : Create a separate LV for home"
440 read -rp "Create LV for home? " WANTSHOME
441 export WANTSHOME
442 done
443
444 # LVROOTNAME prompt
445 while [[ -z "${LVROOTNAME}" ]] || echo "${LVROOTNAME}" | grep -q "${GREPTEST}\|-\|/" -i ; do
446 clear
447 echo -e "${GREEN}\
448Please choose a root name${END}
449Do not include spaces, special characters, or a minus"
450 read -rp "Root name: " LVROOTNAME
451 export LVROOTNAME
452 done
453
454 if [[ "${WANTSHOME}" -eq 1 ]]; then
455 # LVROOTSIZE prompt
456 while [[ -z "${LVROOTSIZE}" ]] || ! echo "${LVROOTSIZE}" | grep -E '^[0-9]+[G|T]$' | grep -q -v "${GREPTEST}\|-\|/" ; do
457 clear
458 echo -e "${GREEN}\
459 Please specify the size of your root volume i.e. 10G${END}
460 Must end with a \"${RED}G${END}\", or \"${RED}T${END}\""
461 read -rp "Root size: " LVROOTSIZE
462 export LVROOTSIZE
463 done
464 else
465 # LVROOTSIZE prompt
466 while [[ -z "${LVROOTSIZE}" ]] || ! echo "${LVROOTSIZE}" | grep -E '^100$|^[1-9][0-9]$|^[1-9]$' ; do
467 clear
468 echo -e "${GREEN}\
469Please specify the size of your root volume between 1 and 100${END}
470enter 100 to use 100% of the remaining storage on ${DEV}${CRYPTPARTITION}
471Do not include the \"${RED}%${END}\""
472 read -rp "Root size: " LVROOTSIZE
473 export LVROOTSIZE
474 done
475 fi
476
477 # LVSWAPNAME prompt
478 while [[ -z "${LVSWAPNAME}" ]] || echo "${LVSWAPNAME}" | grep -q "${GREPTEST}\|-\|/" -i ; do
479 clear
480 echo -e "${GREEN}\
481Please choose a swap name${END}
482Do not include spaces, special characters, or a minus"
483 read -rp "Swap name: " LVSWAPNAME
484 export LVSWAPNAME
485 done
486
487 # LVSWAPSIZE prompt
488 while [[ -z "${LVSWAPSIZE}" ]] || ! echo "${LVSWAPSIZE}" | grep -E '^[0-9]+[M|G]$' | grep -q -v "${GREPTEST}\|-\|/" ; do
489 clear
490 echo -e "${GREEN}\
491Please specify the size of your swap volume i.e. 2G${END}
492Do not include a \"${RED}+${END}\"
493Must end with an \"${RED}M${END}\", or \"${RED}G${END}\""
494 read -rp "Swap size: " LVSWAPSIZE
495 export LVSWAPSIZE
496 done
497
498 if [[ "${WANTSHOME}" -eq 1 ]]; then
499 # LVHOMENAME prompt
500 while [[ -z "${LVHOMENAME}" ]] || echo "${LVHOMENAME}" | grep -q "${GREPTEST}\|-\|/" -i ; do
501 clear
502 echo -e "${GREEN}\
503Please choose a home name${END}
504Do not include spaces, special characters, or a minus"
505 read -rp "Home name: " LVHOMENAME
506 export LVHOMENAME
507 done
508
509 # LVHOMESIZE prompt
510 while [[ -z "${LVHOMESIZE}" ]] || ! echo "${LVHOMESIZE}" | grep -E '^100$|^[1-9][0-9]$|^[1-9]$' ; do
511 clear
512 echo -e "${GREEN}\
513Please specify the size of your home volume between 1 and 100${END}
514enter 100 to use 100% of the remaining storage on ${DEV}${CRYPTPARTITION}
515Do not include the \"${RED}%${END}\""
516 read -rp "Home size: " LVHOMESIZE
517 export LVHOMESIZE
518 done
519 fi
520
521 # EFISIZE prompt
522 if [[ "${ISEFI}" -eq 1 ]]; then
523 while [[ -z "${EFISIZE}" ]] || ! echo "${EFISIZE}" | grep -E '^[0-9]+[M|G]$' | grep -q -v "${GREPTEST}\|/\|^0[M\|G]$" ; do
524 clear
525 echo -e "${GREEN}\
526Please specify the size of your EFI partition${END}
527Do not include a \"${RED}+${END}\"
528Must end with an \"${RED}M${END}\", or \"${RED}G${END}\""
529 read -rp "EFI size: " EFISIZE
530 export EFISIZE
531 done
532 fi
533
534 # SSDGRUB prompt
535 while [[ -z "${WANTSSDGRUB}" ]] || [[ ! "${WANTSSDGRUB}" =~ ^[0-1]$ ]] && lsblk --discard "${DEV}" | grep -q "[1-9]" ; do
536 clear
537 echo -e "${RED}\
538***** PLEASE MAKE SURE YOU UNDERSTAND THE *****
539***** PROS AND CONS OF ENABLING DISCARDS *****${END}
540${GREEN}${DEV} supports TRIM, do you want to enable discards?${END}
5410 : do not enable discards
5421 : enable discards"
543 read -rp "Enable discards? " WANTSSDGRUB
544 export WANTSSDGRUB
545 done
546
547 if [[ "${WANTSSDGRUB}" -eq 1 ]]; then
548 export SSDGRUB=":allow-discards"
549 else
550 export SSDGRUB=""
551 fi
552}
553
554function key_prompts() {
555 # WANTKEY prompt
556 while [[ ! "${WANTKEY}" =~ ^[0-1]$ ]]; do
557 clear
558 echo -e "${GREEN}\
559Would you like to use a keyfile on an external drive to unlock LUKS at boot?${END}
5600 : Do not create a keyfile
5611 : I want a keyfile and I have an external drive to put it on"
562 read -rp "Add keyfile?: " WANTKEY
563 export WANTKEY
564 done
565
566 # Key prompts if user wants a keyfile
567 if [[ "${WANTKEY}" -eq 0 ]]; then export KEYCHANGE=0 ; return 1 ; fi
568
569 # KEYDEV prompt
570 while [[ ! -e "${KEYDEV}" ]] || [[ -z "${KEYDEV}" ]] || echo "${KEYDEV}" | grep -q "${DEV}" || ! echo "${KEYDEV}" | grep -q -E ".*[0-9]+$" || echo "${KEYDEV}" | grep -q "${GREPTEST}"; do
571 clear
572 lsblk
573 echo -e "${GREEN}\
574Please choose a device to store your keyfile on${END}
575i.e. /dev/sdb1
576Choose an external drive and not ${DEV}"
577 read -rp "Select device: " KEYDEV
578 export KEYDEV
579 done
580
581 # KEYNAME prompt
582 while [[ -z "${UKEYNAME}" ]] || echo "${UKEYNAME}" | grep -q "${GREPTEST}\|\.key\|/" || [[ -z "${KEYNAME}" ]]; do
583 clear
584 echo -e "${GREEN}Please enter a reasonable name for your keyfile${END}\nDo not include the \"${RED}.key${END}\" extension in the name."
585 read -rp "Keyname: " UKEYNAME
586 export KEYNAME="${UKEYNAME}.key"
587 done
588
589 # KEYMOUNT prompt
590 while [[ -z "${KEYMOUNT}" ]] || grep -sq " ${KEYMOUNT}" /proc/mounts || ! echo "${KEYMOUNT}" | grep -q "^/" || [[ "$TARGETMOUNTPOINT" == "$KEYMOUNT" ]] || echo "${KEYMOUNT}" | grep -q "${GREPTEST}\|^${TARGETMOUNTPOINT}" ; do
591 clear
592 if [[ -n "${KEYMOUNT}" ]] && grep -sq " ${KEYMOUNT}" /proc/mounts ; then
593 echo -e "${RED}The given directory is occupied. Please select a free mount point.${END}"
594 fi
595 echo -e "${GREEN}Please specify the directory, starting at root${END} \"${RED}/${END}\" ${GREEN}to mount ${KEYDEV}.${END}
596/dev/${VGNAME}/${LVROOTNAME} will be mounted at ${TARGETMOUNTPOINT}"
597 read -rp "Mount at: " KEYMOUNT
598 export KEYMOUNT
599 done
600
601 # KEYDIR prompt
602 while [[ -z "${KEYDIR}" ]] || ! echo "${KEYDIR}" | grep -q "^/" || echo "${KEYDIR}" | grep -q "${GREPTEST}"; do
603 clear
604 echo -e "${GREEN}Please specify the directory on ${KEYDEV} to store your keyfile.${END}
605If the directory does not exist it will be created.
606If ${KEYNAME} exists in this directory then it will
607be used to encrypt ${DEV}${CRYPTPARTITION}"
608 read -rp "Keyfile directory: " KEYDIR
609 export KEYDIR
610 done
611
612 # KEYFORMAT prompt
613 while [[ -z "${KEYFORMAT}" ]] || [[ ! "${KEYFORMAT}" =~ ^[0-4]$ ]]; do
614 clear
615 echo -e "${GREEN}\
616Detected ${KEYDEV} filesystem as : $(lsblk -dno FSTYPE ${KEYDEV})${END}
617Would you like to reformat to another filesystem?
6180 : Do not reformat ${KEYDEV}
619***** THE FOLLOWING WILL ERASE DATA ON ${KEYDEV} *****
6201 : vfat
6212 : btrfs
6223 : ext4
6234 : xfs"
624 read -rp "Format ${KEYDEV} ? " KEYFORMAT
625 export KEYFORMAT
626 done
627
628 # Format Key based on selection
629 if [[ "$KEYFORMAT" =~ ^[1-4]$ ]] ; then
630 case "$KEYFORMAT" in
631 "1") export KEYFSTYPE="vfat" ; export KEYFLAG= ;;
632 "2") export KEYFSTYPE="btrfs" ; export KEYFLAG="-f" ;;
633 "3") export KEYFSTYPE="ext4" ; export KEYFLAG="-F" ;;
634 "4") export KEYFSTYPE="xfs" ; export KEYFLAG="-f" ;;
635 *) ;;
636 esac
637 fi
638
639 export KEYPATH="${KEYDIR}/${KEYNAME}"
640}
641
642function system_var_check() {
643 while : ; do
644 clear
645 echo -e "${GREEN}\
646Please review your new system settings${END}
64701 - Install device : ${DEV}
64802 - Target mount : ${TARGETMOUNTPOINT}
64903 - Crypt name : ${CRYPTNAME}
65004 - System Hostname : ${NEWHOSTNAME}
65105 - LV Group name : ${VGNAME}
65206 - LV Root name : ${LVROOTNAME}
65307 - LV Root size : ${LVROOTSIZE}
65408 - LV Swap name : ${LVSWAPNAME}
65509 - LV Swap size : ${LVSWAPSIZE}"
656 if [[ "${WANTSHOME}" -eq 1 ]]; then
657 echo -e "\
65810 - LV Home name : ${LVHOMENAME}
65911 - LV Home size (%) : ${LVHOMESIZE}"
660 elif [[ "${WANTSHOME}" -eq 0 ]]; then
661 echo -e "\
66210 - Home wanted : No"
663 elif [[ -z "${WANTSHOME}" ]]; then
664 echo -e "\
66510 - Home wanted : NULL"
666 fi
667 if [[ "${WANTSSDGRUB}" -eq 1 ]]; then
668 echo -e "\
66912 - Discards enabled : Yes"
670 else
671 echo -e "\
67212 - Discards enabled : No"
673 fi
674 if [[ "${ISEFI}" -eq 1 ]]; then
675 echo -e "\
67613 - EFI boot size : ${EFISIZE}"
677 fi
678
679 if [[ "${SYSCHANGE}" -ne 1 ]]; then
680 read -rp "Do you wish to change any options? [y/N] " ans
681 case "${ans}" in
682 "n"|"N"|"") unset ans ; export SYSCHANGE=0 ; break ;;
683 "y"|"Y") unset ans ; export SYSCHANGE=1 ; continue ;;
684 *) unset ans ; continue ;;
685 esac
686 fi
687
688 echo -e "${RED}\
689Enter the option number to change${END}
690i.e. 01 to change install device
691Leave blank or enter 0 when done"
692 read -rp "Option number: " ans
693
694 case "${ans}" in
695 ""|"0") unset ans ; break ;;
696 "01") export DEV= ;;
697 "02") export TARGETMOUNTPOINT= ;;
698 "03") export CRYPTNAME= ;;
699 "04") export NEWHOSTNAME= ;;
700 "05") export VGNAME= ;;
701 "06") export LVROOTNAME= ;;
702 "07") export LVROOTSIZE= ;;
703 "08") export LVSWAPNAME= ;;
704 "09") export LVSWAPSIZE= ;;
705 "10")
706 if [[ "${WANTSHOME}" -eq 0 ]]; then
707 export WANTSHOME=
708 elif [[ "${WANTSHOME}" -eq 1 ]]; then
709 export LVHOMENAME=
710 fi ;;
711 "11") export LVHOMESIZE= ;;
712 "12") export WANTSSDGRUB= ;;
713 "13") export EFISIZE= ;;
714 *) clear
715 echo -e "${RED}Unrecognized option${END}\nDon't forget to include the zero for 01-09"
716 sleep 2 ;;
717 esac
718
719 done
720}
721
722function key_var_check() {
723 while : ; do
724 clear
725 echo -e "${GREEN}\
726Please review your keyfile settings${END}
72701 - Key device : ${KEYDEV}
72802 - Key name : ${KEYNAME}
72903 - Key mountpoint : ${KEYMOUNT}
73004 - Key directory : ${KEYDIR}"
731 if [[ "${KEYFORMAT}" -ne 0 ]]; then
732 echo -e "\
73305 - New filesystem : ${KEYFSTYPE}"
734 fi
735
736 if [[ "${KEYCHANGE}" -ne 1 ]]; then
737 read -rp "Do you wish to change any options? [y/N] " ans
738 case "${ans}" in
739 "n"|"N"|"") unset ans ; export KEYCHANGE=0 ; break ;;
740 "y"|"Y") unset ans ; export KEYCHANGE=1 ; continue ;;
741 *) unset ans ; continue ;;
742 esac
743 fi
744
745 echo -e "${RED}\
746Enter the option number to change${END}
747i.e. 01 to change key device
748Leave blank or enter 0 when done"
749 read -rp "Option number: " ans
750
751 case "${ans}" in
752 ""|"0") unset ans ; break ;;
753 "01") export KEYDEV= ;;
754 "02") export KEYNAME= ;;
755 "03") export KEYMOUNT= ;;
756 "04") export KEYDIR= ;;
757 "05") export KEYFSTYPE= ; export KEYFORMAT= ;;
758 *) clear
759 echo -e "${RED}Unrecognized option${END}\nDon't forget to include the zero for 01-05"
760 sleep 2 ;;
761 esac
762
763 done
764}
765
766function confirm_install() {
767 while : ; do
768 clear
769 echo -e "${RED}\
770***** INSTALLTION CONFIRMATION *****${END}
771${DEV} is about to be wiped clean and
772a new Arch Linux system will be installed"
773 read -rp "Please enter YES to continue: " ans
774 case "${ans}" in
775 "YES") unset ans ; return 0 ; break ;;
776 *) unset ans ; return 1 ; break ;;
777 esac
778 done
779}
780
781# fde-install
782
783function main() {
784
785 if ! get_opts "$@" ; then
786 return 1
787 fi
788
789 while [[ -z "${SYSCHANGE}" ]] || [[ "${SYSCHANGE}" -eq 1 ]]; do
790 export SYSCHANGE=
791 if ! system_prompts ; then
792 echo -e "${RED}\
793***** ERROR : Configuring installation settings *****${END}
794Please either review your config or report this issue at
795https://github.com/johndovern/FDE-Arch"
796 return 1
797 fi
798 system_var_check
799 done
800
801 while [[ -z "${KEYCHANGE}" ]] || [[ "${KEYCHANGE}" -eq 1 ]]; do
802 export KEYCHANGE=
803 if ! key_prompts ; then
804 if [[ ! "${WANTKEY}" =~ ^[0-1]$ ]]; then
805 echo -e "${RED}\
806***** ERROR : Configuring keyfile settings *****${END}
807Please either review your config or report this issue at
808https://github.com/johndovern/FDE-Arch"
809 return 1
810 fi
811 fi
812 if [[ "${WANTKEY}" -eq 1 ]]; then
813 key_var_check
814 fi
815 done
816
817 if ! confirm_install ; then
818 send_error "User terminated installation"
819 return 1
820 fi
821
822 if [[ ! -d "${TARGETMOUNTPOINT}" ]]; then send_prog "Making direcotry ${TARGETMOUNTPOINT}" ; mkdir -p "${TARGETMOUNTPOINT}" ; fi
823
824 if ! format_dev ; then
825 send_error "Unable to format ${DEV}"
826 close_and_unmount
827 return 1
828 fi
829
830 if ! encrypt_dev ; then
831 send_error "Failed to encrypt ${DEV}${CRYPTPARTITION}"
832 close_and_unmount
833 return 1
834 fi
835
836 if [[ "${WANTKEY}" -eq 1 ]]; then
837 if [[ "${KEYFORMAT}" -ne 0 ]]; then
838 if ! reformat_key ; then
839 send_error "Failed to reformat ${KEYDEV} to ${KEYFSTYPE}"
840 close_and_unmount
841 return 1
842 fi
843 fi
844 if ! luks_add_keyfile ; then
845 send_error "Failed to add a keyfile to ${DEV}${CRYPTPARTITION}"
846 close_and_unmount
847 return 1
848 fi
849 fi
850
851 if ! make_filesystem ; then
852 send_error "Failed to create filesystem"
853 close_and_unmount
854 return 1
855 fi
856
857 if ! mount_filesystem ; then
858 send_error "Failed to mount filesystem"
859 close_and_unmount
860 return 1
861 fi
862
863 echo -e "${GREEN}Encrypted installation completed successfully. Enjoy your new system!${END}"
864
865}
866
867main "$@"
868
869exit
870