You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
manjaro-architect/lib/util-disk.sh

1684 lines
65 KiB
Bash

# !/bin/bash
#
# Architect Installation Framework (2016-2017)
#
# Written by Carl Duff and @mandog for Archlinux
# Heavily modified and re-written by @Chrysostomus to install Manjaro instead
# Contributors: @papajoker, @oberon and the Manjaro-Community.
#
# This program is free software, provided under the GNU General Public License
# as published by the Free Software Foundation. So feel free to copy, distribute,
# or modify it as you wish.
# Unmount partitions.
umount_partitions() {
MOUNTED=""
MOUNTED=$(mount | grep "${MOUNTPOINT}" | awk '{print $3}' | sort -r)
swapoff -a
for i in ${MOUNTED[@]}; do
umount $i >/dev/null 2>$ERR
check_for_error "unmount $i" $?
# local err=$(umount $i >/dev/null 2>$ERR)
# (( err !=0 )) && check_for_error "$FUNCNAME $i" $err
done
}
# This function does not assume that the formatted device is the Root installation device as
# more than one device may be formatted. Root is set in the mount_partitions function.
select_device() {
DEVICE=""
devices_list=$(lsblk -lno NAME,SIZE,TYPE | grep 'disk' | awk '{print "/dev/" $1 " " $2}' | sort -u);
for i in ${devices_list[@]}; do
DEVICE="${DEVICE} ${i}"
done
DIALOG " $_DevSelTitle " --menu "\n$_DevSelBody\n " 20 60 4 ${DEVICE} 2>${ANSWER} || return 1
DEVICE=$(cat ${ANSWER})
}
create_partitions() {
# Partitioning Menu
DIALOG " $_PrepPartDisk " --menu "\n$_PartToolBody\n " 0 0 7 \
"$_PartOptWipe" "BIOS & UEFI" \
"$_PartOptAuto" "BIOS & UEFI" \
"cfdisk" "BIOS" \
"cgdisk" "UEFI" \
"fdisk" "BIOS & UEFI" \
"gdisk" "UEFI" \
"parted" "BIOS & UEFI" 2>${ANSWER} || return 0
clear
# If something selected
if [[ $(cat ${ANSWER}) != "" ]]; then
if ([[ $(cat ${ANSWER}) != "$_PartOptWipe" ]] && [[ $(cat ${ANSWER}) != "$_PartOptAuto" ]]); then
$(cat ${ANSWER}) ${DEVICE}
else
[[ $(cat ${ANSWER}) == "$_PartOptWipe" ]] && secure_wipe && create_partitions
[[ $(cat ${ANSWER}) == "$_PartOptAuto" ]] && auto_partition
fi
fi
}
# Securely destroy all data on a given device.
secure_wipe() {
# Warn the user. If they proceed, wipe the selected device.
DIALOG " $_PartOptWipe " --yesno "\n$_AutoPartWipeBody1 ${DEVICE} $_AutoPartWipeBody2\n " 0 0
if [[ $? -eq 0 ]]; then
# Install wipe where not already installed. Much faster than dd
inst_needed wipe
wipe -Ifre ${DEVICE} 2>$ERR
check_for_error "wipe ${DEVICE}" $?
# Alternate dd command - requires pv to be installed
#dd if=/dev/zero | pv | dd of=${DEVICE} iflag=nocache oflag=direct bs=4096 2>$ERR
fi
}
# BIOS and UEFI
auto_partition() {
# Provide warning to user
DIALOG " $_PrepPartDisk " --yesno "\n$_AutoPartBody1 $DEVICE $_AutoPartBody2 $_AutoPartBody3\n " 0 0
if [[ $? -eq 0 ]]; then
# Find existing partitions (if any) to remove
parted -s ${DEVICE} print | awk '/^ / {print $1}' > /tmp/.del_parts
for del_part in $(tac /tmp/.del_parts); do
parted -s ${DEVICE} rm ${del_part} 2>$ERR
check_for_error "rm ${del_part} on ${DEVICE}" $?
done
# Identify the partition table
part_table=$(parted -s ${DEVICE} print | grep -i 'partition table' | awk '{print $3}' >/dev/null 2>&1)
check_for_error "${DEVICE} is $part_table"
# Create partition table if one does not already exist
if [[ $SYSTEM == "BIOS" ]] && [[ $part_table != "msdos" ]] ; then
parted -s ${DEVICE} mklabel msdos 2>$ERR
check_for_error "${DEVICE} mklabel msdos" $?
fi
if [[ $SYSTEM == "UEFI" ]] && [[ $part_table != "gpt" ]] ; then
parted -s ${DEVICE} mklabel gpt 2>$ERR
check_for_error "${DEVICE} mklabel gpt" $?
fi
# Create partitions (same basic partitioning scheme for BIOS and UEFI)
if [[ $SYSTEM == "BIOS" ]]; then
parted -s ${DEVICE} mkpart primary ext3 1MiB 513MiB 2>$ERR
check_for_error "create ext3 513MiB on ${DEVICE}" $?
else
parted -s ${DEVICE} mkpart ESP fat32 1MiB 513MiB 2>$ERR
check_for_error "create ESP on ${DEVICE}" $?
fi
parted -s ${DEVICE} set 1 boot on 2>$ERR
check_for_error "set boot flag for ${DEVICE}" $?
parted -s ${DEVICE} mkpart primary ext3 513MiB 100% 2>$ERR
check_for_error "create ext3 100% on ${DEVICE}" $?
# Show created partitions
lsblk ${DEVICE} -o NAME,TYPE,FSTYPE,SIZE > /tmp/.devlist
DIALOG "" --textbox /tmp/.devlist 0 0
fi
}
# Finds all available partitions according to type(s) specified and generates a list
# of them. This also includes partitions on different devices.
find_partitions() {
PARTITIONS=""
NUMBER_PARTITIONS=0
# get the list of partitions and also include the zvols since it is common to mount filesystems directly on them. It should be safe to include them here since they present as block devices.
partition_list=$(lsblk -lno NAME,SIZE,TYPE | grep $INCLUDE_PART | sed 's/part$/\/dev\//g' | sed 's/lvm$\|crypt$/\/dev\/mapper\//g' | \
awk '{print $3$1 " " $2}' | awk '!/mapper/{a[++i]=$0;next}1;END{while(x<length(a))print a[++x]}' ; zfs list -Ht volume -o name,volsize 2>/dev/null | awk '{printf "/dev/zvol/%s %s\n", $1, $2}')
# create a raid partition list
old_ifs="$IFS"
IFS=$'\n'
raid_partitions=($(lsblk -lno NAME,SIZE,TYPE | grep raid | awk '{print $1,$2}' | uniq))
IFS="$old_ifs"
# add raid partitions to partition_list
for i in "${raid_partitions[@]}"
do
partition_list="${partition_list} /dev/md/${i}"
done
for i in ${partition_list}; do
PARTITIONS="${PARTITIONS} ${i}"
NUMBER_PARTITIONS=$(( NUMBER_PARTITIONS + 1 ))
done
# Double-partitions will be counted due to counting sizes, so fix
NUMBER_PARTITIONS=$(( NUMBER_PARTITIONS / 2 ))
check_for_error "--------- [lsblk] ------------"
local parts=($PARTITIONS)
for i in ${!parts[@]}; do
(( $i % 2 == 0 )) || continue
local j=$((i+1))
check_for_error "${parts[i]} ${parts[j]}"
done
#for test delete /dev:sda8
#delete_partition_in_list "/dev/sda8"
# Deal with partitioning schemes appropriate to mounting, lvm, and/or luks.
case $INCLUDE_PART in
'part\|lvm\|crypt')
# Deal with incorrect partitioning for main mounting function
if ([[ $SYSTEM == "UEFI" ]] && [[ $NUMBER_PARTITIONS -lt 2 ]]) || ([[ $SYSTEM == "BIOS" ]] && [[ $NUMBER_PARTITIONS -eq 0 ]]); then
DIALOG " $_ErrTitle " --msgbox "\n$_PartErrBody\n " 0 0
create_partitions
fi
;;
'part\|crypt')
# Ensure there is at least one partition for LVM
if [[ $NUMBER_PARTITIONS -eq 0 ]]; then
DIALOG " $_ErrTitle " --msgbox "\n$_LvmPartErrBody\n " 0 0
create_partitions
fi
;;
'part\|lvm') # Ensure there are at least two partitions for LUKS
if [[ $NUMBER_PARTITIONS -lt 2 ]]; then
DIALOG " $_ErrTitle " --msgbox "\n$_LuksPartErrBody\n " 0 0
create_partitions
fi
;;
esac
}
## List partitions to be hidden from the mounting menu
list_mounted() {
lsblk -l | awk '$7 ~ /mnt/ {print $1}' > /tmp/.mounted
check_for_error "already mounted: $(cat /tmp/.mounted)"
echo /dev/* /dev/mapper/* | xargs -n1 2>/dev/null | grep -f /tmp/.mounted
}
list_containing_crypt() {
blkid | awk '/TYPE="crypto_LUKS"/{print $1}' | sed 's/.$//'
}
list_non_crypt() {
blkid | awk '!/TYPE="crypto_LUKS"/{print $1}' | sed 's/.$//'
}
# delete partition in list $PARTITIONS
# param: partition to delete
delete_partition_in_list() {
[ -z "$1" ] && return 127
local parts=($PARTITIONS)
for i in ${!parts[@]}; do
(( $i % 2 == 0 )) || continue
if [[ "${parts[i]}" = "$1" ]]; then
local j=$((i+1))
unset parts[$j]
unset parts[$i]
check_for_error "in partitions delete item $1 no: $i / $j"
PARTITIONS="${parts[*]}"
check_for_error "partitions: $PARTITIONS"
NUMBER_PARTITIONS=$(( "${#parts[*]}" / 2 ))
return 0
fi
done
return 0
}
# Revised to deal with partion sizes now being displayed to the user
confirm_mount() {
if [[ $(mount | grep $1) ]]; then
DIALOG " $_MntStatusTitle " --infobox "\n$_MntStatusSucc\n " 0 0
sleep 2
PARTITIONS=$(echo $PARTITIONS | sed "s~${PARTITION} [0-9]*[G-M]~~" | sed "s~${PARTITION} [0-9]*\.[0-9]*[G-M]~~" | sed s~${PARTITION}$' -'~~)
NUMBER_PARTITIONS=$(( NUMBER_PARTITIONS - 1 ))
else
DIALOG " $_MntStatusTitle " --infobox "\n$_MntStatusFail\n " 0 0
sleep 2
return 1
fi
}
# Set static list of filesystems rather than on-the-fly. Partially as most require additional flags, and
# partially because some don't seem to be viable.
# Set static list of filesystems rather than on-the-fly.
select_filesystem() {
# prep variables
fs_opts=""
CHK_NUM=0
# zfs legacy filesystems can't be formatted, always have a zfs filesystem and store their mount options in metadata
[[ $(zfs_list_datasets legacy | grep "^${PARTITION}$") ]] && return
DIALOG " $_FSTitle " --menu "\n$_FSBody\n " 0 0 10 \
"$_FSSkip" "-" \
"btrfs" "mkfs.btrfs -f" \
"ext2" "mkfs.ext2 -q" \
"ext3" "mkfs.ext3 -q" \
"ext4" "mkfs.ext4 -q" \
"f2fs" "mkfs.f2fs -q" \
"jfs" "mkfs.jfs -q" \
"nilfs2" "mkfs.nilfs2 -fq" \
"ntfs" "mkfs.ntfs -q" \
"reiserfs" "mkfs.reiserfs -q" \
"vfat" "mkfs.vfat -F32" \
"xfs" "mkfs.xfs -f" 2>${ANSWER} || return 1
case $(cat ${ANSWER}) in
"$_FSSkip") FILESYSTEM="$_FSSkip"
;;
"btrfs") FILESYSTEM="mkfs.btrfs -f"
CHK_NUM=16
fs_opts="autodefrag compress=zlib compress=lzo compress=zstd compress=no compress-force=zlib compress-force=lzo compress-force=zstd discard \
noacl noatime nodatasum nospace_cache recovery skip_balance space_cache nossd ssd ssd_spread commit=120"
modprobe btrfs
;;
"ext2") FILESYSTEM="mkfs.ext2 -q"
;;
"ext3") FILESYSTEM="mkfs.ext3 -q"
;;
"ext4") FILESYSTEM="mkfs.ext4 -q"
CHK_NUM=8
fs_opts="data=journal data=writeback dealloc discard noacl noatime nobarrier nodelalloc"
;;
"f2fs") FILESYSTEM="mkfs.f2fs -q"
fs_opts="data_flush disable_roll_forward disable_ext_identify discard fastboot flush_merge \
inline_xattr inline_data inline_dentry no_heap noacl nobarrier noextent_cache noinline_data norecovery"
CHK_NUM=16
modprobe f2fs
;;
"jfs") FILESYSTEM="mkfs.jfs -q"
CHK_NUM=4
fs_opts="discard errors=continue errors=panic nointegrity"
;;
"nilfs2") FILESYSTEM="mkfs.nilfs2 -fq"
CHK_NUM=7
fs_opts="discard nobarrier errors=continue errors=panic order=relaxed order=strict norecovery"
;;
"ntfs") FILESYSTEM="mkfs.ntfs -q"
;;
"reiserfs") FILESYSTEM="mkfs.reiserfs -q"
CHK_NUM=5
fs_opts="acl nolog notail replayonly user_xattr"
;;
"vfat") FILESYSTEM="mkfs.vfat -F32"
;;
"xfs") FILESYSTEM="mkfs.xfs -f"
CHK_NUM=9
fs_opts="discard filestreams ikeep largeio noalign nobarrier norecovery noquota wsync"
;;
*) return 1
;;
esac
# Warn about formatting!
if [[ $FILESYSTEM != $_FSSkip ]]; then
DIALOG " $_FSTitle " --yesno "\n$_FSMount $FILESYSTEM\n\n! $_FSWarn1 $PARTITION $_FSWarn2 !\n " 0 0
if (( $? != 1 )); then
${FILESYSTEM} ${PARTITION} >/dev/null 2>$ERR
check_for_error "mount ${PARTITION} as ${FILESYSTEM}." $? || return 1
ini "mount.${PARTITION}" $(echo "${FILESYSTEM:5}|cut -d' ' -f1")
fi
fi
}
# This subfunction allows for special mounting options to be applied for relevant fs's.
# Seperate subfunction for neatness.
mount_opts() {
FS_OPTS=""
for i in ${fs_opts}; do
FS_OPTS="${FS_OPTS} ${i} - off"
done
echo ${FS_OPTS} > /tmp/.fs_options
format_name=$(echo ${PARTITION} | rev | cut -d/ -f1 | rev)
format_device=$(lsblk -i | tac | sed -r 's/^[^[:alnum:]]+//' | sed -n -e "/$format_name/,/disk/p" | awk '/disk/ {print $1}')
if [[ "$(cat /sys/block/${format_device}/queue/rotational)" == 1 ]]; then
sed -i 's/autodefrag - off/autodefrag - on/' /tmp/.fs_options
sed -i 's/compress=zlip - off/compress=zlip - on/' /tmp/.fs_options
sed -i 's/nossd - off/nossd - on/' /tmp/.fs_options
else
sed -i 's/compress=lzo - off/compress=lzo - on/' /tmp/.fs_options
sed -i 's/ space_cache - off/ space_cache - on/' /tmp/.fs_options
sed -i 's/commit=120 - off/commit=120 - on/' /tmp/.fs_options
sed -i 's/ ssd - off/ ssd - on/' /tmp/.fs_options
fi
sed -i 's/noatime - off/noatime - on/' /tmp/.fs_options
FS_OPTS=$(cat /tmp/.fs_options)
DIALOG " $(echo $FILESYSTEM | sed "s/.*\.//g;s/-.*//g") " --checklist "\n$_btrfsMntBody\n " 0 0 \
$CHK_NUM $FS_OPTS 2>${MOUNT_OPTS}
# Now clean up the file
sed -i 's/ /,/g' ${MOUNT_OPTS}
sed -i '$s/,$//' ${MOUNT_OPTS}
# If mount options selected, confirm choice
if [[ $(cat ${MOUNT_OPTS}) != "" ]]; then
DIALOG " $_MntStatusTitle " --yesno "\n${_btrfsMntConfBody}$(cat ${MOUNT_OPTS})\n " 10 75
[[ $? -eq 1 ]] && echo "" > ${MOUNT_OPTS}
fi
}
mount_current_partition() {
# Make the mount directory
mkdir -p ${MOUNTPOINT}${MOUNT} 2>$ERR
check_for_error "create mountpoint ${MOUNTPOINT}${MOUNT}" "$?"
echo "" > ${MOUNT_OPTS}
# Get mounting options for appropriate filesystems
[[ $fs_opts != "" ]] && mount_opts
# Check for zfs, use special mounting options if selected, else standard mount
if [[ $(zfs_list_datasets legacy | grep "^${PARTITION}$") ]]; then
check_for_error "mount ${PARTITION}"
mount -t zfs ${PARTITION} ${MOUNTPOINT}${MOUNT} 2>>$LOGFILE
elif [[ $(cat ${MOUNT_OPTS}) != "" ]]; then
check_for_error "mount ${PARTITION} $(cat ${MOUNT_OPTS})"
mount -o $(cat ${MOUNT_OPTS}) ${PARTITION} ${MOUNTPOINT}${MOUNT} 2>>$LOGFILE
else
check_for_error "mount ${PARTITION}"
mount ${PARTITION} ${MOUNTPOINT}${MOUNT} 2>>$LOGFILE
fi
confirm_mount ${MOUNTPOINT}${MOUNT}
# Identify if mounted partition is type "crypt" (LUKS on LVM, or LUKS alone)
if [[ $(lsblk -lno TYPE ${PARTITION} | grep "crypt") != "" ]]; then
# cryptname for bootloader configuration either way
LUKS=1
LUKS_NAME=$(echo ${PARTITION} | sed "s~^/dev/mapper/~~g")
# Check if LUKS on LVM (parent = lvm /dev/mapper/...)
cryptparts=$(lsblk -lno NAME,FSTYPE,TYPE | grep "lvm" | grep -i "crypto_luks" | uniq | awk '{print "/dev/mapper/"$1}')
for i in ${cryptparts}; do
if [[ $(lsblk -lno NAME ${i} | grep $LUKS_NAME) != "" ]]; then
LUKS_DEV="$LUKS_DEV cryptdevice=${i}:$LUKS_NAME"
LVM=1
return 0;
fi
done
# Check if LVM on LUKS
cryptparts=$(lsblk -lno NAME,FSTYPE,TYPE | grep " crypt$" | grep -i "LVM2_member" | uniq | awk '{print "/dev/mapper/"$1}')
for i in ${cryptparts}; do
if [[ $(lsblk -lno NAME ${i} | grep $LUKS_NAME) != "" ]]; then
LUKS_DEV="$LUKS_DEV cryptdevice=${i}:$LUKS_NAME"
LVM=1
return 0;
fi
done
# Check if LUKS alone (parent = part /dev/...)
cryptparts=$(lsblk -lno NAME,FSTYPE,TYPE | grep "part" | grep -i "crypto_luks" | uniq | awk '{print "/dev/"$1}')
for i in ${cryptparts}; do
if [[ $(lsblk -lno NAME ${i} | grep $LUKS_NAME) != "" ]]; then
LUKS_UUID=$(lsblk -lno UUID,TYPE,FSTYPE ${i} | grep "part" | grep -i "crypto_luks" | awk '{print $1}')
LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
return 0;
fi
done
# If LVM logical volume....
elif [[ $(lsblk -lno TYPE ${PARTITION} | grep "lvm") != "" ]]; then
LVM=1
# First get crypt name (code above would get lv name)
cryptparts=$(lsblk -lno NAME,TYPE,FSTYPE | grep "crypt" | grep -i "lvm2_member" | uniq | awk '{print "/dev/mapper/"$1}')
for i in ${cryptparts}; do
if [[ $(lsblk -lno NAME ${i} | grep $(echo $PARTITION | sed "s~^/dev/mapper/~~g")) != "" ]]; then
LUKS_NAME=$(echo ${i} | sed s~/dev/mapper/~~g)
return 0;
fi
done
# Now get the device (/dev/...) for the crypt name
cryptparts=$(lsblk -lno NAME,FSTYPE,TYPE | grep "part" | grep -i "crypto_luks" | uniq | awk '{print "/dev/"$1}')
for i in ${cryptparts}; do
if [[ $(lsblk -lno NAME ${i} | grep $LUKS_NAME) != "" ]]; then
# Create UUID for comparison
LUKS_UUID=$(lsblk -lno UUID,TYPE,FSTYPE ${i} | grep "part" | grep -i "crypto_luks" | awk '{print $1}')
# Check if not already added as a LUKS DEVICE (i.e. multiple LVs on one crypt). If not, add.
if [[ $(echo $LUKS_DEV | grep $LUKS_UUID) == "" ]]; then
LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
LUKS=1
fi
return 0;
fi
done
fi
}
make_swap() {
# Ask user to select partition or create swapfile if swapfiles are valid for the root filesystem
if [[ $(findmnt -ln -o FSTYPE ${MOUNTPOINT}) == "zfs" || $(findmnt -ln -o FSTYPE ${MOUNTPOINT}) == "btrfs" ]]; then
DIALOG " $_PrepMntPart " --menu "\n$_SelSwpBody\n " 0 0 12 "$_SelSwpNone" $"-" ${PARTITIONS} 2>${ANSWER} || return 0
else
DIALOG " $_PrepMntPart " --menu "\n$_SelSwpBody\n " 0 0 12 "$_SelSwpNone" $"-" "$_SelSwpFile" $"-" ${PARTITIONS} 2>${ANSWER} || return 0
fi
if [[ $(cat ${ANSWER}) != "$_SelSwpNone" ]]; then
PARTITION=$(cat ${ANSWER})
if [[ $PARTITION == "$_SelSwpFile" ]]; then
total_memory=$(grep MemTotal /proc/meminfo | awk '{print $2/1024}' | sed 's/\..*//')
DIALOG " $_SelSwpFile " --inputbox "\nM = MB, G = GB\n " 9 30 "${total_memory}M" 2>${ANSWER} || return 0
m_or_g=$(cat ${ANSWER})
while [[ $(echo ${m_or_g: -1} | grep "M\|G") == "" ]]; do
DIALOG " $_SelSwpFile " --msgbox "\n$_SelSwpFile $_ErrTitle: M = MB, G = GB\n " 0 0
DIALOG " $_SelSwpFile " --inputbox "\nM = MB, G = GB\n " 9 30 "${total_memory}M" 2>${ANSWER} || return 0
m_or_g=$(cat ${ANSWER})
done
fallocate -l ${m_or_g} ${MOUNTPOINT}/swapfile 2>$ERR
check_for_error "Swapfile fallocate" "$?"
chmod 600 ${MOUNTPOINT}/swapfile 2>$ERR
check_for_error "Swapfile chmod" "$?"
mkswap ${MOUNTPOINT}/swapfile 2>$ERR
check_for_error "Swapfile mkswap" "$?"
swapon ${MOUNTPOINT}/swapfile 2>$ERR
check_for_error "Swapfile swapon" "$?"
else # Swap Partition
# Warn user if creating a new swap
if [[ $(lsblk -o FSTYPE ${PARTITION} | grep -i "swap") != "swap" ]]; then
DIALOG " $_PrepMntPart " --yesno "\nmkswap ${PARTITION}\n " 0 0
if [[ $? -eq 0 ]]; then
mkswap ${PARTITION} >/dev/null 2>$ERR
check_for_error "Swap partition: mkswap" "$?"
else
return 0
fi
fi
# Whether existing to newly created, activate swap
swapon ${PARTITION} >/dev/null 2>$ERR
check_for_error "Swap partition: swapon" "$?"
# Since a partition was used, remove that partition from the list
PARTITIONS=$(echo $PARTITIONS | sed "s~${PARTITION} [0-9]*[G-M]~~" | sed "s~${PARTITION} [0-9]*\.[0-9]*[G-M]~~" | sed s~${PARTITION}$' -'~~)
NUMBER_PARTITIONS=$(( NUMBER_PARTITIONS - 1 ))
fi
fi
ini mount.swap "${PARTITION}"
}
raid_level_menu() {
declare -i loopmenu=1
while ((loopmenu)); do
RAID_OPT=""
DIALOG "RAID" --menu "\n$_RAIDLevelTitle\n" 20 75 6 \
"0" "$_RAIDLevel0" \
"1" "$_RAIDLevel1" \
"5" "$_RAIDLevel5" \
"6" "$_RAIDLevel6" \
"10" "$_RAIDLevel10" \
"$_Back" "-" 2>${ANSWER}
case $(cat ${ANSWER}) in
"0") raid_array_menu 0
;;
"1") raid_array_menu 1
;;
"5") raid_array_menu 5
;;
"6") raid_array_menu 6
;;
"10") raid_array_menu 10
;;
*) loopmenu=0
return 0
;;
esac
done
}
raid_create() {
RAID_DEVICES=${1}
RAID_DEVICE_NUMBER=$(echo ${1} | wc -w)
RAID_LEVEL=${2}
RAID_DEVICE_NAME=${3}
# creates the array
mdadm --create --level=${RAID_LEVEL} --metadata=1.2 --raid-devices=${RAID_DEVICE_NUMBER} /dev/md/${RAID_DEVICE_NAME} ${RAID_DEVICES}
# array is disassembled and reassembled to prevent the array from being named /dev/md/md127
# the check of /etc/mdadm.conf is preformed to prevent the user from adding duplicate entries
if [[ $(cat /etc/mdadm.conf | grep "/dev/md/${RAID_DEVICE_NAME}" | wc -l) == 0 ]]; then
mdadm --detail --scan | grep -e "/dev/md/${RAID_DEVICE_NAME}" -e "/dev/md/md127" >> /etc/mdadm.conf
mdadm --stop /dev/md/${RAID_DEVICE_NAME}
mdadm --assemble --scan
fi
DIALOG "$__ArrayCreatedTitle" --msgbox "\n$_ArrayCreatedDescription\n\nmdadm --create --level=${RAID_LEVEL} --metadata=1.2 --raid-devices=${RAID_DEVICE_NUMBER} /dev/md/${RAID_DEVICE_NAME} ${RAID_DEVICES}\n" 0 0
}
raid_get_array_name() {
DIALOG "$_DeviceNameTitle" --inputbox "\n$_DeviceNameDescription\n\n$_DeviceNamePrefixWarning\n" 0 0 2>${ANSWER}
raid_device_name=$(cat ${ANSWER})
if [[ ${raid_device_name} != "" ]]; then
raid_create "${1}" ${2} ${raid_device_name}
fi
}
raid_array_menu() {
# find raid partitions.
INCLUDE_PART='part\|crypt'
umount_partitions
find_partitions
# Amend partition(s) found for use in check list
PARTITIONS=$(echo $PARTITIONS | sed 's/M\|G\|T/& off/g')
RAID_LEVEL=${1}
# select partitions for the array
echo "" > $ANSWER
while [[ $(cat ${ANSWER}) == "" ]]; do
DIALOG "$_PartitionSelectTitle" --checklist "\n$__PartitionSelectDescription\n\n$_UseSpaceBar\n " 0 0 12 ${PARTITIONS} 2> ${ANSWER}
done
ANSWERS=$(cat ${ANSWER})
raid_get_array_name "${ANSWERS[@]}" ${RAID_LEVEL}
}
luks_menu() {
declare -i loopmenu=1
while ((loopmenu)); do
LUKS_OPT=""
DIALOG " $_PrepLUKS " --menu "\n$_LuksMenuBody\n$_LuksMenuBody2\n$_LuksMenuBody3\n " 0 0 0 \
"$_LuksOpen" "cryptsetup open --type luks" \
"$_LuksEncrypt" "cryptsetup -q luksFormat" \
"$_LuksEncryptAdv" "cryptsetup -q -s -c luksFormat" \
"Express LUKS" "cryptsetup -q -s --pbkdf-force-iterations 200000 -c luksFormat" \
"$_Back" "-" 2>${ANSWER}
case $(cat ${ANSWER}) in
"$_LuksOpen") luks_open
;;
"$_LuksEncrypt") luks_setup && luks_default && luks_show
;;
"$_LuksEncryptAdv") luks_setup && luks_key_define && luks_show
;;
"Express LUKS") luks_setup && luks_express && luks_show
;;
*) loopmenu=0
return 0
;;
esac
done
}
luks_open() {
LUKS_ROOT_NAME=""
INCLUDE_PART='part\|crypt\|lvm'
umount_partitions
find_partitions
# Filter out partitions that don't contain crypt device
list_non_crypt > /tmp/.ignore_part
for part in $(cat /tmp/.ignore_part); do
delete_partition_in_list $part
done
# stop if no encrypted partition found
if [[ $PARTITIONS == "" ]]; then
DIALOG " $_ErrTitle " --msgbox "\n$_LuksErr\n " 0 0
return 1
fi
# Select encrypted partition to open
DIALOG " $_LuksOpen " --menu "\n$_LuksMenuBody\n " 0 0 12 ${PARTITIONS} 2>${ANSWER} || return 0
PARTITION=$(cat ${ANSWER})
# Enter name of the Luks partition and get password to open it
DIALOG " $_LuksOpen " --inputbox "\n$_LuksOpenBody\n " 0 0 "cryptroot" 2>${ANSWER} || return 0
LUKS_ROOT_NAME=$(cat ${ANSWER})
DIALOG " $_PrepLUKS " --clear --insecure --passwordbox "\n$_LuksPassBody\n " 0 0 2> ${ANSWER} || return 0
PASSWD=$(cat ${ANSWER})
# Try to open the luks partition with the credentials given. If successful show this, otherwise
# show the error
DIALOG " $_LuksOpen " --infobox "\n$_PlsWaitBody\n " 0 0
echo $PASSWD | cryptsetup open --type luks ${PARTITION} ${LUKS_ROOT_NAME} 2>$ERR
check_for_error "luks pwd ${PARTITION} ${LUKS_ROOT_NAME}" "$?"
echo "" > /tmp/.devlist
lsblk -o NAME,TYPE,FSTYPE,SIZE,MOUNTPOINT ${PARTITION} | grep "crypt\|NAME\|MODEL\|TYPE\|FSTYPE\|SIZE" >> /tmp/.devlist
DIALOG " $_DevShowOpt " --textbox /tmp/.devlist 0 0
}
luks_password() {
luks_get_password
while [[ "$PASSWD" != "$PASSWD2" ]]; do
DIALOG " $_ErrTitle " --msgbox "\n$_PassErrBody\n " 0 0
luks_get_password
done
}
luks_get_password() {
DIALOG " $_PrepLUKS " --clear --insecure --passwordbox "\n$_LuksPassBody\n " 0 0 2> ${ANSWER} || return 0
PASSWD=$(cat ${ANSWER})
DIALOG " $_PrepLUKS " --clear --insecure --passwordbox "\n$_PassReEntBody\n " 0 0 2> ${ANSWER} || return 0
PASSWD2=$(cat ${ANSWER})
}
luks_setup() {
modprobe -a dm-mod dm_crypt
INCLUDE_PART='part\|lvm'
umount_partitions
find_partitions
# Select partition to encrypt
DIALOG " $_LuksEncrypt " --menu "\n$_LuksCreateBody\n " 0 0 12 ${PARTITIONS} 2>${ANSWER} || return 1
PARTITION=$(cat ${ANSWER})
# Enter name of the Luks partition and get password to create it
DIALOG " $_LuksEncrypt " --inputbox "\n$_LuksOpenBody\n " 0 0 "cryptroot" 2>${ANSWER} || return 1
LUKS_ROOT_NAME=$(cat ${ANSWER})
luks_password
}
luks_default() {
# Encrypt selected partition or LV with credentials given
DIALOG " $_LuksEncrypt " --infobox "\n$_PlsWaitBody\n " 0 0
sleep 2
echo $PASSWD | cryptsetup -q --type luks1 luksFormat ${PARTITION} 2>$ERR
check_for_error "luksFormat ${PARTITION}" $?
# Now open the encrypted partition or LV
echo $PASSWD | cryptsetup open ${PARTITION} ${LUKS_ROOT_NAME} 2>$ERR
check_for_error "open ${PARTITION} ${LUKS_ROOT_NAME}" $?
}
luks_express() {
# Encrypt selected partition or LV with credentials given
DIALOG " $_LuksEncrypt " --infobox "\n$_PlsWaitBody\n " 0 0
sleep 2
echo $PASSWD | cryptsetup -q --pbkdf-force-iterations 200000 --type luks1 luksFormat ${PARTITION} 2>$ERR
check_for_error "luksFormat ${PARTITION}" $?
# Now open the encrypted partition or LV
echo $PASSWD | cryptsetup open ${PARTITION} ${LUKS_ROOT_NAME} 2>$ERR
check_for_error "open ${PARTITION} ${LUKS_ROOT_NAME}" $?
}
luks_key_define() {
DIALOG " $_PrepLUKS " --inputbox "\n$_LuksCipherKey\n " 0 0 "-s 512 -c aes-xts-plain64" 2>${ANSWER} || return 1
# Encrypt selected partition or LV with credentials given
DIALOG " $_LuksEncryptAdv " --infobox "\n$_PlsWaitBody\n " 0 0
sleep 2
echo $PASSWD | cryptsetup -q $(cat ${ANSWER}) luksFormat ${PARTITION} 2>$ERR
check_for_error "encrypt ${PARTITION}" "$?"
# Now open the encrypted partition or LV
echo $PASSWD | cryptsetup open ${PARTITION} ${LUKS_ROOT_NAME} 2>$ERR
check_for_error "open ${PARTITION} ${LUKS_ROOT_NAME}" "$?"
}
luks_show() {
printf "\n${_LuksEncruptSucc}\n\n" > /tmp/.devlist
lsblk -o NAME,TYPE,FSTYPE,SIZE ${PARTITION} | grep "part\|crypt\|NAME\|TYPE\|FSTYPE\|SIZE" >> /tmp/.devlist
DIALOG " $_LuksEncrypt " --textbox /tmp/.devlist 0 0
}
lvm_menu() {
declare -i loopmenu=1
while ((loopmenu)); do
DIALOG " $_PrepLVM $_PrepLVM2 " --infobox "\n$_PlsWaitBody\n " 0 0
sleep 1
lvm_detect
DIALOG " $_PrepLVM $_PrepLVM2 " --menu "\n$_LvmMenu\n " 22 60 4 \
"$_LvmCreateVG" "vgcreate -f, lvcreate -L -n" \
"$_LvmDelVG" "vgremove -f" \
"$_LvMDelAll" "lvremove, vgremove, pvremove -f" \
"$_Back" "-" 2>${ANSWER}
case $(cat ${ANSWER}) in
"$_LvmCreateVG") lvm_create
;;
"$_LvmDelVG") lvm_del_vg
;;
"$_LvMDelAll") lvm_del_all
;;
*) loopmenu=0
return 0
;;
esac
done
}
lvm_detect() {
LVM_PV=$(pvs -o pv_name --noheading 2>/dev/null)
LVM_VG=$(vgs -o vg_name --noheading 2>/dev/null)
LVM_LV=$(lvs -o vg_name,lv_name --noheading --separator - 2>/dev/null)
if [[ $LVM_LV != "" ]] && [[ $LVM_VG != "" ]] && [[ $LVM_PV != "" ]]; then
DIALOG " $_PrepLVM " --infobox "\n$_LvmDetBody\n " 0 0
sleep 2
modprobe dm-mod 2>$ERR
check_for_error "modprobe dm-mod" "$?"
vgscan >/dev/null 2>&1
vgchange -ay >/dev/null 2>&1
fi
}
# Create Volume Group and Logical Volumes
lvm_create() {
# Find LVM appropriate partitions.
INCLUDE_PART='part\|crypt'
umount_partitions
find_partitions
# Amend partition(s) found for use in check list
PARTITIONS=$(echo $PARTITIONS | sed 's/M\|G\|T/& off/g')
# Name the Volume Group
DIALOG " $_LvmCreateVG " --inputbox "\n$_LvmNameVgBody\n " 0 0 2>${ANSWER} || return 0
LVM_VG=$(cat ${ANSWER})
# Loop while the Volume Group name starts with a "/", is blank, has spaces, or is already being used
while [[ ${LVM_VG:0:1} == "/" ]] || [[ ${#LVM_VG} -eq 0 ]] || [[ $LVM_VG =~ \ |\' ]] || [[ $(lsblk | grep ${LVM_VG}) != "" ]]; do
DIALOG " $_ErrTitle " --msgbox "\n$_LvmNameVgErr\n " 0 0
DIALOG " $_LvmCreateVG " --inputbox "\n$_LvmNameVgBody\n " 0 0 "" 2>${ANSWER} || return 0
LVM_VG=$(cat ${ANSWER})
done
# Select the partition(s) for the Volume Group
echo "" > $ANSWER
while [[ $(cat ${ANSWER}) == "" ]]; do
DIALOG " $_LvmCreateVG " --checklist "\n$_LvmPvSelBody\n\n$_UseSpaceBar\n " 0 0 12 ${PARTITIONS} 2>${ANSWER} || return 0
done
VG_PARTS=$(cat ${ANSWER})
# Once all the partitions have been selected, show user. On confirmation, use it/them in 'vgcreate' command.
# Also determine the size of the VG, to use for creating LVs for it.
DIALOG " $_LvmCreateVG " --yesno "\n$_LvmPvConfBody1 [${LVM_VG}] $_LvmPvConfBody2\n${VG_PARTS}\n " 0 0
if [[ $? -eq 0 ]]; then
DIALOG " $_LvmCreateVG " --infobox "\n$_LvmPvActBody1 [${LVM_VG}].\n$_PlsWaitBody\n " 0 0
sleep 1
vgcreate -f ${LVM_VG} ${VG_PARTS} >/dev/null
check_for_error "vgcreate -f ${LVM_VG} ${VG_PARTS}"
# Once created, get size and size type for display and later number-crunching for lv creation
VG_SIZE=$(vgdisplay $LVM_VG | awk '/VG Size/ {print $3}' | sed -e 's/<//' | sed 's/\..*//; s/\,.*//')
VG_SIZE_TYPE=$(vgdisplay $LVM_VG | grep 'VG Size' | awk '{print $4}')
# Convert the VG size into GB and MB. These variables are used to keep tabs on space available and remaining
[[ ${VG_SIZE_TYPE:0:1} == "G" ]] && LVM_VG_MB=$(( VG_SIZE * 1000 )) || LVM_VG_MB=$VG_SIZE
DIALOG " $_LvmCreateVG " --msgbox "\n$_LvmPvDoneBody1 [${LVM_VG}] (${VG_SIZE} ${VG_SIZE_TYPE}) $_LvmPvDoneBody2.\n " 0 0 || return 0
fi
#
# Once VG created, create Logical Volumes
#
# Specify number of Logical volumes to create.
DIALOG " $_LvmCreateVG " --inputbox "\n$_LvmLvNumBody1 [${LVM_VG}]. $_LvmLvNumBody2\n " 0 0 2>${ANSWER}
# repeat if answer is not a number
while [[ $(cat ${ANSWER}) != ?(-)+([0-9]) ]]; do
DIALOG " $_ErrTitle " --inputbox "\n$_LvmLvNumBody1 [${LVM_VG}]. $_LvmLvNumBody2\n " 0 0 2>${ANSWER}
done
NUMBER_LOGICAL_VOLUMES=$(cat ${ANSWER})
# Loop while the number of LVs is greater than 1. This is because the size of the last LV is automatic.
while [[ $NUMBER_LOGICAL_VOLUMES -gt 1 ]]; do
DIALOG " $_LvmCreateVG (LV:$NUMBER_LOGICAL_VOLUMES) " --inputbox "\n$_LvmLvNameBody1\n " 0 0 "lvol" 2>${ANSWER} || return 0
LVM_LV_NAME=$(cat ${ANSWER})
# Loop if preceeded with a "/", if nothing is entered, if there is a space, or if that name already exists.
while [[ ${LVM_LV_NAME:0:1} == "/" ]] || [[ ${#LVM_LV_NAME} -eq 0 ]] || [[ ${LVM_LV_NAME} =~ \ |\' ]] || [[ $(lsblk | grep ${LVM_LV_NAME}) != "" ]]; do
DIALOG " $_ErrTitle " --msgbox "\n$_LvmLvNameErrBody\n " 0 0
DIALOG " $_LvmCreateVG (LV:$NUMBER_LOGICAL_VOLUMES) " --inputbox "\n$_LvmLvNameBody1\n " 0 0 "lvol" 2>${ANSWER} || return 0
LVM_LV_NAME=$(cat ${ANSWER})
done
DIALOG " $_LvmCreateVG (LV:$NUMBER_LOGICAL_VOLUMES) " --inputbox \
"\n[${LVM_VG}]: ${VG_SIZE}${VG_SIZE_TYPE} - (${LVM_VG_MB}MB $_LvmLvSizeBody1).\n\n$_LvmLvSizeBody2\n " 0 0 "" 2>${ANSWER} || return 0
LVM_LV_SIZE=$(cat ${ANSWER})
check_lv_size
# Loop while an invalid value is entered.
while [[ $LV_SIZE_INVALID -eq 1 ]]; do
DIALOG " $_ErrTitle " --msgbox "\n$_LvmLvSizeErrBody\n " 0 0
DIALOG " $_LvmCreateVG (LV:$NUMBER_LOGICAL_VOLUMES) " --inputbox \
"\n[${LVM_VG}]: ${VG_SIZE}${VG_SIZE_TYPE} - (${LVM_VG_MB}MB $_LvmLvSizeBody1).\n\n$_LvmLvSizeBody2\n " 0 0 "" 2>${ANSWER} || return 0
LVM_LV_SIZE=$(cat ${ANSWER})
check_lv_size
done
# Create the LV
lvcreate -W y -qq -L ${LVM_LV_SIZE} ${LVM_VG} -n ${LVM_LV_NAME} 2>$ERR
check_for_error "lvcreate -W y -qq -L ${LVM_LV_SIZE} ${LVM_VG} -n ${LVM_LV_NAME}" "$?"
DIALOG " $_LvmCreateVG (LV:$NUMBER_LOGICAL_VOLUMES) " --msgbox "\nLV ${LVM_LV_NAME} (${LVM_LV_SIZE}) $_LvmPvDoneBody2.\n " 0 0
NUMBER_LOGICAL_VOLUMES=$(( NUMBER_LOGICAL_VOLUMES - 1 ))
done
# Now the final LV. Size is automatic.
DIALOG " $_LvmCreateVG (LV:$NUMBER_LOGICAL_VOLUMES) " --inputbox "\n$_LvmLvNameBody1 $_LvmLvNameBody2 (${LVM_VG_MB}MB).\n " 0 0 "lvol" 2>${ANSWER} || return 0
LVM_LV_NAME=$(cat ${ANSWER})
# Loop if preceeded with a "/", if nothing is entered, if there is a space, or if that name already exists.
while [[ ${LVM_LV_NAME:0:1} == "/" ]] || [[ ${#LVM_LV_NAME} -eq 0 ]] || [[ ${LVM_LV_NAME} =~ \ |\' ]] || [[ $(lsblk | grep ${LVM_LV_NAME}) != "" ]]; do
DIALOG " $_ErrTitle " --msgbox "\n$_LvmLvNameErrBody\n " 0 0
DIALOG " $_LvmCreateVG (LV:$NUMBER_LOGICAL_VOLUMES) " --inputbox "\n$_LvmLvNameBody1 $_LvmLvNameBody2 (${LVM_VG_MB}MB).\n " 0 0 "lvol" 2>${ANSWER} || return 0
LVM_LV_NAME=$(cat ${ANSWER})
done
# Create the final LV
lvcreate -W y -qq -l +100%FREE ${LVM_VG} -n ${LVM_LV_NAME} 2>$ERR
check_for_error "lvcreate -W y -qq -l +100%FREE ${LVM_VG} -n ${LVM_LV_NAME}" "$?"
NUMBER_LOGICAL_VOLUMES=$(( NUMBER_LOGICAL_VOLUMES - 1 ))
LVM=1
DIALOG " $_LvmCreateVG " --yesno "\n$_LvmCompBody\n " 0 0 && show_devices || return 0
}
check_lv_size() {
LV_SIZE_INVALID=0
chars=0
# Check to see if anything was actually entered and if first character is '0'
([[ ${#LVM_LV_SIZE} -eq 0 ]] || [[ ${LVM_LV_SIZE:0:1} -eq "0" ]]) && LV_SIZE_INVALID=1
# If not invalid so far, check for non numberic characters other than the last character
if [[ $LV_SIZE_INVALID -eq 0 ]]; then
while [[ $chars -lt $(( ${#LVM_LV_SIZE} - 1 )) ]]; do
[[ ${LVM_LV_SIZE:chars:1} != [0-9] ]] && LV_SIZE_INVALID=1 && return 0;
chars=$(( chars + 1 ))
done
fi
# If not invalid so far, check that last character is a M/m or G/g
if [[ $LV_SIZE_INVALID -eq 0 ]]; then
LV_SIZE_TYPE=$(echo ${LVM_LV_SIZE:$(( ${#LVM_LV_SIZE} - 1 )):1})
case $LV_SIZE_TYPE in
"m"|"M"|"g"|"G") LV_SIZE_INVALID=0 ;;
*) LV_SIZE_INVALID=1 ;;
esac
fi
# If not invalid so far, check whether the value is greater than or equal to the LV remaining Size.
# If not, convert into MB for VG space remaining.
if [[ ${LV_SIZE_INVALID} -eq 0 ]]; then
case ${LV_SIZE_TYPE} in
"G"|"g")
if [[ $(( $(echo ${LVM_LV_SIZE:0:$(( ${#LVM_LV_SIZE} - 1 ))}) * 1000 )) -ge ${LVM_VG_MB} ]]; then
LV_SIZE_INVALID=1
else
LVM_VG_MB=$(( LVM_VG_MB - $(( $(echo ${LVM_LV_SIZE:0:$(( ${#LVM_LV_SIZE} - 1 ))}) * 1000 )) ))
fi
;;
"M"|"m")
if [[ $(echo ${LVM_LV_SIZE:0:$(( ${#LVM_LV_SIZE} - 1 ))}) -ge ${LVM_VG_MB} ]]; then
LV_SIZE_INVALID=1
else
LVM_VG_MB=$(( LVM_VG_MB - $(echo ${LVM_LV_SIZE:0:$(( ${#LVM_LV_SIZE} - 1 ))}) ))
fi
;;
*) LV_SIZE_INVALID=1
;;
esac
fi
}
lvm_del_vg() {
# Generate list of VGs for selection
lvm_show_vg
# If no VGs, no point in continuing
if [[ $VG_LIST == "" ]]; then
DIALOG " $_ErrTitle " --msgbox "\n$_LvmVGErr\n " 0 0
return 0
fi
# Select VG
DIALOG " $_PrepLVM " --menu "\n$_LvmSelVGBody\n " 0 0 5 ${VG_LIST} 2>${ANSWER} || return 0
# Ask for confirmation
DIALOG " $_LvmDelVG " --yesno "\n$_LvmDelQ\n " 0 0
# if confirmation given, delete
if [[ $? -eq 0 ]]; then
vgremove -f $(cat ${ANSWER}) 2>/dev/null
check_for_error "delete lvm-VG $(cat ${ANSWER})"
fi
}
lvm_show_vg() {
VG_LIST=""
vg_list=$(lvs --noheadings | awk '{print $2}' | uniq)
for i in ${vg_list}; do
VG_LIST="${VG_LIST} ${i} $(vgdisplay ${i} | grep -i "vg size" | awk '{print $3$4}')"
done
}
lvm_del_all() {
# check if VG exist at all
if [[ $(lvs) == "" ]]; then
DIALOG " $_ErrTitle " --msgbox "\n$_LvmVGErr\n " 0 0
return 0
fi
LVM_PV=$(pvs -o pv_name --noheading 2>/dev/null)
LVM_VG=$(vgs -o vg_name --noheading 2>/dev/null)
LVM_LV=$(lvs -o vg_name,lv_name --noheading --separator - 2>/dev/null)
# Ask for confirmation
DIALOG " $_LvmDelLV " --yesno "\n$_LvmDelQ\n " 0 0
# if confirmation given, delete
if [[ $? -eq 0 ]]; then
for i in ${LVM_LV}; do
lvremove -f /dev/mapper/${i} 2>/dev/null
check_for_error "remove LV ${i}"
done
for i in ${LVM_VG}; do
vgremove -f ${i} 2>/dev/null
check_for_error "remove VG ${i}"
done
for i in ${LV_PV}; do
pvremove -f ${i} 2>/dev/null
check_for_error "remove LV-PV ${i}"
done
fi
}
# returns a list of devices containing zfs members
zfs_list_devs() {
# get a list of devices with zpools on them
for device in $(zpool status -PL 2>/dev/null | awk '{print $1}' | grep "^/"); do
# add the device
echo $device
# now lets add any other forms of those devices
find -L /dev/ -xtype l -samefile ${device} 2>/dev/null
done
}
zfs_list_datasets() {
case $1 in
"zvol")
zfs list -Ht volume -o name,volsize 2>/dev/null
;;
"legacy")
zfs list -Ht filesystem -o name,mountpoint 2>/dev/null | grep "^.*/.*legacy$" | awk '{print $1}'
;;
*)
zfs list -H -o name 2>/dev/null | grep "/"
esac
}
# creates a new zpool on an existing partition
zfs_create_zpool() {
# LVM Detection. If detected, activate.
lvm_detect
INCLUDE_PART='part\|lvm\|crypt'
umount_partitions
find_partitions
list_mounted > /tmp/.ignore_part
zfs_list_devs >> /tmp/.ignore_part
list_containing_crypt >> /tmp/.ignore_part
check_for_error "ignore crypted: $(list_containing_crypt)"
for part in $(cat /tmp/.ignore_part); do
delete_partition_in_list $part
done
# Identify the partition for the zpool
DIALOG " $_zfsZpoolPartMenuTitle " --menu "\n$_zfsZpoolPartMenuBody\n " 0 0 12 ${PARTITIONS} 2>${ANSWER} || return 1
PARTITION=$(cat ${ANSWER})
# We need to get a name for the zpool
local -i loopmenu=1
ZFSMENUTEXT=$_zfsZpoolCBody
while ((loopmenu)); do
DIALOG " $_zfsZpoolCTitle " --inputbox "\n$ZFSMENUTEXT\n " 0 0 "zpmanjaro" 2>${ANSWER} || return 1
ZFSMENUTEXT=$_zfsZpoolCBody
# validation
[[ ! $(cat ${ANSWER}) =~ ^[a-zA-Z][a-zA-Z0-9.:_-]*$ ]] && ZFSMENUTEXT=$_zfsZpoolCValidation1
[[ $(cat ${ANSWER}) =~ ^(log|mirror|raidz|raidz1|raidz2|raidz3|spare).*$ ]] && ZFSMENUTEXT=$_zfsZpoolCValidation2
[[ $ZFSMENUTEXT == $_zfsZpoolCBody ]] && loopmenu=0
done
ZFS_ZPOOL_NAME=$(cat ${ANSWER})
# Find the UUID of the partition
PARTUUID=$(lsblk -lno PATH,PARTUUID | grep "^${PARTITION}" | awk '{print $2}')
# See if the partition has a partuuid, if not use the device name
if [[ -n ${PARTUUID} ]]; then
zpool create -m none ${ZFS_ZPOOL_NAME} ${PARTUUID} 2>$ERR
check_for_error "Creating zpool ${ZFS_ZPOOL_NAME} on device ${PARTITION} using partuuid ${PARTUUID}"
else
zpool create -m none ${ZFS_ZPOOL_NAME} ${PARTITION} 2>$ERR
check_for_error "Creating zpool ${ZFS_ZPOOL_NAME} on device ${PARTITION}"
fi
ZFS=1
# Since zfs manages mountpoints, we export it and then import with a root of $MOUNTPOINT
zpool export ${ZFS_ZPOOL_NAME} 2>$ERR
zpool import -R ${MOUNTPOINT} ${ZFS_ZPOOL_NAME} 2>>$ERR
check_for_error "Export and importing ${ZFS_POOL_NAME}"
return 0
}
# Creates a zfs filesystem, the first parameter is the ZFS path and the second is the mount path
zfs_create_dataset() {
local zpath=$1
local zmount=$2
zfs create -o mountpoint=$zmount $zpath 2>$ERR
check_for_error "Creating zfs dataset ${zpath} with mountpoint ${zmount}"
}
# Automated configuration of zfs. Creates a new zpool and a default set of filesystems
zfs_auto() {
# first we need to create a zpool to hold the datasets/zvols
zfs_create_zpool
if [ $? != 0 ]; then
DIALOG " $_zfsZpoolCTitle " --infobox "\n$_zfsCancelled\n " 0 0
sleep 3
return 0
fi
# next create the datasets including their parents
zfs_create_dataset "${ZFS_ZPOOL_NAME}/data" "none"
zfs_create_dataset "${ZFS_ZPOOL_NAME}/ROOT" "none"
zfs_create_dataset "${ZFS_ZPOOL_NAME}/ROOT/manjaro" "none"
zfs_create_dataset "${ZFS_ZPOOL_NAME}/ROOT/manjaro/root" "/"
zfs_create_dataset "${ZFS_ZPOOL_NAME}/data/home" "/home"
zfs_create_dataset "${ZFS_ZPOOL_NAME}/ROOT/manjaro/paccache" "/var/cache/pacman"
# set the rootfs
zpool set bootfs=${ZFS_ZPOOL_NAME}/ROOT/manjaro/root ${ZFS_ZPOOL_NAME} 2>$ERR
check_for_error "Setting zfs bootfs"
# provide confirmation to the user
DIALOG " $_zfsZpoolCTitle " --infobox "\n$_zfsAutoComplete\n " 0 0
sleep 3
}
zfs_import_pool() {
local zplist
local zpoolitem
for zpoolitem in $(zpool import 2>/dev/null | grep "^[[:space:]]*pool" | awk -F : '{print $2}' | awk '{$1=$1};1'); do
zplist="${zplist} ${zpoolitem} -"
done
if [[ ${zplist} ]]; then
DIALOG " $_zfsZpoolImportMenuTitle " --menu "\n$_zfsZpoolImportMenuBody\n " 0 0 12 ${zplist} 2>${ANSWER} || return 0
zpool import -R ${MOUNTPOINT} $(cat ${ANSWER}) 2>$ERR
check_for_error "Import zpool $(cat ${ANSWER})"
ZFS=1
else
DIALOG " $_zfsZpoolImportMenuTitle " --infobox "\n$_zfsZpoolNoPool\n " 0 0
sleep 3
fi
}
# return a list of imported zpools
zfs_list_pools() {
zpool list -H 2>/dev/null | awk '{print $1}'
}
zfs_new_ds() {
local zplist
local zmount=$1
local zpoolitem
for zpoolitem in `zfs_list_pools`; do
zplist="${zplist} ${zpoolitem} -"
done
if [[ ${zplist} ]]; then
# select a zpool
DIALOG " $_zfsSelectZpoolMenuTitle " --menu "\n$_zfsSelectZpoolMenuBody\n " 0 0 12 ${zplist} 2>${ANSWER} || return 0
local zpool=$(cat ${ANSWER})
else
# no imported zpools
DIALOG " $_zfsSelectZpoolMenuTitle " --infobox "\n$_zfsZpoolNoPool\n " 0 0
sleep 3
return 0
fi
# enter a name for the dataset
local -i loopmenu=1
local zfsmenubody=$_zfsDSMenuNameBody
while ((loopmenu)); do
DIALOG " $_zfsDSMenuNameTitle " --inputbox "\n$zfsmenubody\n " 0 0 "" 2>${ANSWER} || return 1
# validation
[[ ! $(cat ${ANSWER}) =~ ^[a-zA-Z][a-zA-Z0-9.:/_-]*$ ]] && zfsmenubody=$_zfsZpoolCValidation1 || loopmenu=0
done
local zname=$(cat ${ANSWER})
case $zmount in
"legacy")
zfs_create_dataset ${zpool}/${zname} ${zmount} 2>$ERR
;;
"zvol")
# get the size of the zvol
loopmenu=1
zfsmenubody=$_zfsZvolSizeMenuBody
while ((loopmenu)); do
DIALOG " $_zfsZvolSizeMenuTitle " --inputbox "\n$zfsmenubody\n " 0 0 "" 2>${ANSWER} || return 1
# validation
[[ $(cat ${ANSWER}) =~ ^[0-9]*$ ]] && loopmenu=0 || zfsmenubody=$_zfsZvolSizeMenuValidation
done
local zsize=$(cat ${ANSWER})
zfs create -V ${zsize}M ${zpool}/${zname} 2>$ERR
;;
*)
# select a mount point
loopmenu=1
zfsmenubody=$_zfsMountMenuBody
while ((loopmenu)); do
DIALOG " $_zfsMountMenuTitle " --inputbox "\n$zfsmenubody\n " 0 0 "" 2>${ANSWER} || return 0
zmount=$(cat ${ANSWER})
zfsmenubody=$_zfsMountMenuBody
# validation
[[ $(findmnt -n ${MOUNTPOINT}/${zmount}) ]] && zfsmenubody=$_zfsMountMenuInUse
[[ ! ($zmount =~ ^/ || $zmount == none) ]] && zfsmenubody=$_zfsMountMenuNotValid
[[ $zfsmenubody == $_zfsMountMenuBody ]] && loopmenu=0
done
zfs_create_dataset ${zpool}/${zname} ${zmount} 2>$ERR
;;
esac
check_for_error "new zfs dataset ${zpool}/${zname} on ${zmount}"
}
zfs_destroy_dataset() {
local zlist
# get dataset list and format for the menu
local zds
for zds in $(zfs_list_datasets); do
zlist="${zlist} ${zds} -"
done
# select the dataset to destroy
if [[ ${zlist} ]]; then
DIALOG " $_zfsDestroyMenuTitle " --menu "\n$_zfsDestroyMenuBody\n " 0 0 12 ${zlist} 2>${ANSWER} || return 0
local zdataset=$(cat ${ANSWER})
else
# no available datasets
DIALOG " $_zfsDestroyMenuTitle " --infobox "\n$_zfsDatasetNotFound\n " 0 0
sleep 3
return 0
fi
# better confirm this one
DIALOG --defaultno --yesno "$_zfsDestroyMenuConfirm1 ${zdataset} $_zfsDestroyMenuConfirm2" 0 0
if [ $? ]; then
zfs destroy -r ${zdataset}
check_for_error "zfs destroy ${zdataset}"
fi
}
zfs_set_property () {
local zlist
# get dataset list and format for the menu
local zds
for zds in $(zfs_list_datasets); do
zlist="${zlist} ${zds} -"
done
# select the dataset
if [[ ${zlist} ]]; then
DIALOG " $_zfsSetMenuTitle " --menu "\n$_zfsSetMenuBody\n " 0 0 12 ${zlist} 2>${ANSWER} || return 0
local zdataset=$(cat ${ANSWER})
else
# no available datasets
DIALOG " $_zfsSetMenuTitle " --infobox "\n$_zfsDatasetNotFound\n " 0 0
sleep 3
return 0
fi
# get property/value input
local -i loopmenu=1
zfsmenubody=$_zfsSetMenuBody
local zsetstmt
while ((loopmenu)); do
DIALOG " $_zfsSetMenuTitle " --inputbox "\n$zfsmenubody\n " 0 0 "" 2>${ANSWER} || return 0
zsetstmt=$(cat ${ANSWER})
# validation
[[ ! $zsetstmt =~ ^[a-zA-Z@]*=[a-zA-Z0-9@-]*$ ]] && zfsmenubody=$_zfsMountMenuNotValid || loopmenu=0
done
#set the property
zfs set ${zsetstmt} ${zdataset} 2>$ERR
check_for_error "zfs set ${zsetstmt} on ${zdataset}"
}
zfs_menu_manual() {
local -i loopmenu=1
while ((loopmenu)); do
DIALOG " $_zfsManualMenuTitle " --menu "\n$_zfsManualMenuBody\n " 22 60 8 \
"$_zfsManualMenuOptCreate" "" \
"$_zfsManualMenuOptImport" "" \
"$_zfsManualMenuOptNewFile" "" \
"$_zfsManualMenuOptNewLegacy" "" \
"$_zfsManualMenuOptNewZvol" "" \
"$_zfsManualMenuOptSet" "" \
"$_zfsManualMenuOptDestroy" "" \
"$_Back" "" 2>${ANSWER}
case $(cat ${ANSWER}) in
"$_zfsManualMenuOptCreate") zfs_create_zpool
;;
"$_zfsManualMenuOptImport") zfs_import_pool
;;
"$_zfsManualMenuOptNewFile") zfs_new_ds
;;
"$_zfsManualMenuOptNewLegacy") zfs_new_ds "legacy"
;;
"$_zfsManualMenuOptNewZvol") zfs_new_ds "zvol"
;;
"$_zfsManualMenuOptSet") zfs_set_property
;;
"$_zfsManualMenuOptDestroy") zfs_destroy_dataset
;;
*) loopmenu=0
return 0
;;
esac
done
}
# The main ZFS menu
zfs_menu() {
# check for zfs support
modprobe zfs 2>$ERR
if [[ $(cat $ERR) ]]; then
DIALOG " $_zfsZpoolCTitle " --infobox "\n$_zfsNotSupported\n " 0 0
sleep 3
return 0
fi
declare -i loopmenu=1
while ((loopmenu)); do
DIALOG " $_PrepZFS " --menu "\n$_zfsMainMenuBody\n " 22 60 3 \
"$_zfsMainMenuOptAutomatic" "" \
"$_zfsMainMenuOptManual" "" \
"$_Back" "" 2>${ANSWER}
case $(cat ${ANSWER}) in
"$_zfsMainMenuOptAutomatic") zfs_auto
;;
"$_zfsMainMenuOptManual") zfs_menu_manual
;;
*) loopmenu=0
return 0
;;
esac
done
}
make_esp() {
# Extra Step for VFAT UEFI Partition. This cannot be in an LVM container.
if [[ $SYSTEM == "UEFI" ]]; then
if DIALOG " $_PrepMntPart " --menu "\n$_SelUefiBody\n " 0 0 12 ${PARTITIONS} 2>${ANSWER}; then
PARTITION=$(cat ${ANSWER})
UEFI_PART=${PARTITION}
# If it is already a fat/vfat partition...
if [[ $(fsck -N $PARTITION | grep fat) ]]; then
DIALOG " $_PrepMntPart " --defaultno --yesno "\n$_FormUefiBody $PARTITION $_FormUefiBody2\n " 0 0 && {
mkfs.vfat -F32 ${PARTITION} >/dev/null 2>$ERR
check_for_error "mkfs.vfat -F32 ${PARTITION}" "$?"
} # || return 0
else
mkfs.vfat -F32 ${PARTITION} >/dev/null 2>$ERR
check_for_error "mkfs.vfat -F32 ${PARTITION}" "$?"
fi
if [[ "$LUKS" == 0 ]]; then
_MntUefiMessage="$_MntUefiBody"
else
_MntUefiMessage="$_MntUefiCrypt"
fi
DIALOG " $_PrepMntPart " --radiolist "\n$_MntUefiMessage\n " 0 0 2 \
"/boot/efi" "" on \
"/boot" "" off 2>${ANSWER}
if [[ $(cat ${ANSWER}) != "" ]]; then
UEFI_MOUNT=$(cat ${ANSWER})
mkdir -p ${MOUNTPOINT}${UEFI_MOUNT} 2>$ERR
check_for_error "create ${MOUNTPOINT}${UEFI_MOUNT}" $?
mount ${PARTITION} ${MOUNTPOINT}${UEFI_MOUNT} 2>$ERR
check_for_error "mount ${PARTITION} ${MOUNTPOINT}${UEFI_MOUNT}" $?
if confirm_mount ${MOUNTPOINT}${UEFI_MOUNT}; then
ini mount.efi "${UEFI_MOUNT}"
delete_partition_in_list "$PARTITION"
fi
fi
fi
fi
}
mount_partitions() {
# Warn users that they CAN mount partitions without formatting them!
DIALOG " $_PrepMntPart " --msgbox "\n$_WarnMount1 '$_FSSkip' $_WarnMount2\n " 15 65
# LVM Detection. If detected, activate.
lvm_detect
# Ensure partitions are unmounted (i.e. where mounted previously)
INCLUDE_PART='part\|lvm\|crypt'
umount_partitions
# We need to remount the zfs filesystems that have defined mountpoints already
zfs mount -aO 2>/dev/null
# Get list of available partitions
find_partitions
# Add legacy zfs filesystems to the list - these can be mounted but not formatted
for i in $(zfs_list_datasets "legacy"); do
PARTITIONS="${PARTITIONS} ${i}"
PARTITIONS="${PARTITIONS} zfs"
NUMBER_PARTITIONS=$(( NUMBER_PARTITIONS + 1 ))
done
# Filter out partitions that have already been mounted and partitions that just contain crypt or zfs devices
list_mounted > /tmp/.ignore_part
zfs_list_devs >> /tmp/.ignore_part
list_containing_crypt >> /tmp/.ignore_part
check_for_error "ignore crypted: $(list_containing_crypt)"
for part in $(cat /tmp/.ignore_part); do
delete_partition_in_list $part
done
# check to see if we already have a zfs root mounted
if [ $(findmnt -ln -o FSTYPE ${MOUNTPOINT}) == "zfs" ]; then
DIALOG " $_PrepMntPart " --infobox "\n$_zfsFoundRoot\n " 0 0
sleep 3
else
# Identify and mount root
DIALOG " $_PrepMntPart " --menu "\n$_SelRootBody\n " 0 0 12 ${PARTITIONS} 2>${ANSWER} || return 0
PARTITION=$(cat ${ANSWER})
ROOT_PART=${PARTITION}
echo ${ROOT_PART} > /tmp/.root_partitioni
echo ${ROOT_PART} > /tmp/.root_partition
# Reset the mountpoint variable, in case this is the second time through this menu and old state is still around
MOUNT=""
# Format with FS (or skip) -> # Make the directory and mount. Also identify LUKS and/or LVM
select_filesystem && mount_current_partition || return 0
ini mount.root "${PARTITION}"
delete_partition_in_list "${ROOT_PART}"
# Extra check if root is on LUKS or lvm
get_cryptroot
echo "$LUKS_DEV" > /tmp/.luks_dev
# If the root partition is btrfs, offer to create subvolumus
if [[ $(findmnt -no FSTYPE ${MOUNTPOINT}) == btrfs ]]; then
# Check if there are subvolumes already on the btrfs partition
if [[ $(btrfs subvolume list ${MOUNTPOINT} | wc -l) -gt 1 ]] && DIALOG " The volume has already subvolumes " --yesno "\nFound subvolumes $(btrfs subvolume list ${MOUNTPOUNT} | cut -d" " -f9)\n\nWould you like to mount them? \n " 0 0; then
# Pre-existing subvolumes and user wants to mount them
mount_existing_subvols
else
# No subvolumes present. Make some new ones
DIALOG " Your root volume is formatted in btrfs " --yesno "\nWould you like to create subvolumes in it? \n " 0 0 && btrfs_subvolumes
fi
fi
fi
# We need to remove legacy zfs partitions before make_swap since they can't hold swap
local zlegacy
for zlegacy in $(zfs_list_datasets "legacy"); do
delete_partition_in_list ${zlegacy}
done
# Identify and create swap, if applicable
make_swap
# Now that swap is done we put the legacy partitions back, unless they are already mounted
for i in $(zfs_list_datasets "legacy"); do
PARTITIONS="${PARTITIONS} ${i}"
PARTITIONS="${PARTITIONS} zfs"
NUMBER_PARTITIONS=$(( NUMBER_PARTITIONS + 1 ))
done
for part in $(list_mounted); do
delete_partition_in_list $part
done
# All other partitions
while [[ $NUMBER_PARTITIONS > 0 ]]; do
DIALOG " $_PrepMntPart " --menu "\n$_ExtPartBody\n " 0 0 12 "$_Done" $"-" ${PARTITIONS} 2>${ANSWER} || return 0
PARTITION=$(cat ${ANSWER})
if [[ $PARTITION == $_Done ]]; then
make_esp
get_cryptroot
get_cryptboot
echo "$LUKS_DEV" > /tmp/.luks_dev
return 0;
else
MOUNT=""
select_filesystem
# Ask user for mountpoint. Don't give /boot as an example for UEFI systems!
[[ $SYSTEM == "UEFI" ]] && MNT_EXAMPLES="/home\n/var" || MNT_EXAMPLES="/boot\n/home\n/var"
DIALOG " $_PrepMntPart $PARTITON " --inputbox "\n$_ExtPartBody1$MNT_EXAMPLES\n " 0 0 "/" 2>${ANSWER} || return 0
MOUNT=$(cat ${ANSWER})
# loop while the mountpoint specified is incorrect (is only '/', is blank, or has spaces).
while [[ ${MOUNT:0:1} != "/" ]] || [[ ${#MOUNT} -le 1 ]] || [[ $MOUNT =~ \ |\' ]]; do
# Warn user about naming convention
DIALOG " $_ErrTitle " --msgbox "\n$_ExtErrBody\n " 0 0
# Ask user for mountpoint again
DIALOG " $_PrepMntPart $PARTITON " --inputbox "\n$_ExtPartBody1$MNT_EXAMPLES\n " 0 0 "/" 2>${ANSWER} || return 0
MOUNT=$(cat ${ANSWER})
done
# Create directory and mount.
mount_current_partition
delete_partition_in_list "$PARTITION"
# Determine if a seperate /boot is used. 0 = no seperate boot, 1 = seperate non-lvm boot,
# 2 = seperate lvm boot. For Grub configuration
if [[ $MOUNT == "/boot" ]]; then
[[ $(lsblk -lno TYPE ${PARTITION} | grep "lvm") != "" ]] && LVM_SEP_BOOT=2 || LVM_SEP_BOOT=1
fi
fi
done
}
get_cryptroot() {
# Identify if /mnt or partition is type "crypt" (LUKS on LVM, or LUKS alone)
if $(lsblk | sed -r 's/^[^[:alnum:]]+//' | awk '/\/mnt$/ {print $6}' | grep -q crypt) || $(lsblk -i | tac | sed -r 's/^[^[:alnum:]]+//' | sed -n -e "/\/mnt$/,/part/p" | awk '{print $6}' | grep -q crypt); then
LUKS=1
root_name=$(mount | awk '/\/mnt / {print $1}' | sed s~/dev/mapper/~~g | sed s~/dev/~~g)
#Get the name of the Luks device
if $(lsblk -i | grep -q -e "crypt /mnt"); then
# Mountpoint is directly on the LUKS device, so LUKS deivece is the same as root name
LUKS_ROOT_NAME="$root_name"
else
# Mountpoint is not directly on LUKS device, so we need to get the crypt device above the mountpoint
LUKS_ROOT_NAME="$(lsblk -i | tac | sed -r 's/^[^[:alnum:]]+//' | sed -n -e "/\/mnt$/,/crypt/p" | awk '/crypt/ {print $1}')"
fi
# Check if LUKS on LVM
if [[ $(lsblk -lno NAME,FSTYPE,TYPE,MOUNTPOINT | grep "lvm" | grep "/mnt$" | grep -i "crypto_luks" | uniq | awk '{print "/dev/mapper/"$1}') != "" ]]; then
cryptparts=$(lsblk -lno NAME,FSTYPE,TYPE,MOUNTPOINT | grep "lvm" | grep "/mnt$" | grep -i "crypto_luks" | uniq | awk '{print "/dev/mapper/"$1}')
for i in ${cryptparts}; do
if [[ $(lsblk -lno NAME ${i} | grep $LUKS_ROOT_NAME) != "" ]]; then
LUKS_DEV="cryptdevice=${i}:$LUKS_ROOT_NAME"
LVM=1
fi
done
fi
# Check if LVM on LUKS
if [[ $(lsblk -lno NAME,FSTYPE,TYPE | grep " crypt$" | grep -i "LVM2_member" | uniq | awk '{print "/dev/mapper/"$1}') != "" ]]; then
cryptparts=$(lsblk -lno NAME,FSTYPE,TYPE | grep " crypt$" | grep -i "LVM2_member" | uniq | awk '{print "/dev/mapper/"$1}')
for i in ${cryptparts}; do
if [[ $(lsblk -lno NAME ${i} | grep $LUKS_ROOT_NAME) != "" ]]; then
LUKS_UUID=$(lsblk -ino NAME,FSTYPE,TYPE,MOUNTPOINT,UUID | tac | sed -r 's/^[^[:alnum:]]+//' | sed -n -e "/\/mnt /,/part/p" | awk '/crypto_LUKS/ {print $4}')
LUKS_DEV="cryptdevice=UUID=$LUKS_UUID:$LUKS_ROOT_NAME"
LVM=1
fi
done
fi
# Check if LUKS alone
if [[ $(lsblk -lno NAME,FSTYPE,TYPE | grep "part" | grep -i "crypto_luks" | uniq | awk '{print "/dev/"$1}') != "" ]]; then
cryptparts=$(lsblk -lno NAME,FSTYPE,TYPE,MOUNTPOINT | grep "/mnt$" | grep "part" | grep -i "crypto_luks" | uniq | awk '{print "/dev/"$1}')
for i in ${cryptparts}; do
if [[ $(lsblk -lno NAME ${i} | grep $LUKS_ROOT_NAME) != "" ]]; then
LUKS_UUID=$(lsblk -lno UUID,TYPE,FSTYPE ${i} | grep "part" | grep -i "crypto_luks" | awk '{print $1}')
LUKS_DEV="cryptdevice=UUID=$LUKS_UUID:$LUKS_ROOT_NAME"
fi
done
fi
echo "$LUKS_DEV" > /tmp/.luks_dev
fi
}
get_cryptboot(){
# If /boot is encrypted
if $(lsblk | sed -r 's/^[^[:alnum:]]+//' | awk '/\/mnt\/boot$/ {print $6}' | grep -q crypt) || $(lsblk -i | tac | sed -r 's/^[^[:alnum:]]+//' | sed -n -e "/\/mnt\/boot$/,/part/p" | awk '{print $6}' | grep -q crypt); then
LUKS=1
boot_name=$(mount | awk '/\/mnt\/boot / {print $1}' | sed s~/dev/mapper/~~g | sed s~/dev/~~g)
#Get the name of the Luks device
if $(lsblk -i | grep -q -e "crypt /mnt"); then
# Mountpoint is directly on the LUKS device, so LUKS deivece is the same as root name
LUKS_BOOT_NAME="$boot_name"
# Get UUID of the encrypted /boot
LUKS_BOOT_UUID=$(lsblk -lno UUID,MOUNTPOINT | awk '/\mnt\/boot$/ {print $1}')
else
# Mountpoint is not directly on LUKS device, so we need to get the crypt device above the mountpoint
LUKS_BOOT_NAME="$(lsblk -i | tac | sed -r 's/^[^[:alnum:]]+//' | sed -n -e "/\/mnt\/boot$/,/crypt/p" | awk '/crypt/ {print $1}')"
# Get UUID of the encrypted /boot
LUKS_BOOT_UUID=$(lsblk -ino NAME,FSTYPE,TYPE,MOUNTPOINT,UUID | tac | sed -r 's/^[^[:alnum:]]+//' | sed -n -e "/\/mnt\/boot /,/part/p" | awk '/crypto_LUKS/ {print $4}')
fi
# Check if LVM on LUKS
if $(lsblk -lno TYPE,MOUNTPOINT | grep "/mnt/boot$" | grep -q lvm); then
LVM=1
fi
# Add Cryptdevice to LUKS_DEV, if not already present (if on same LVM on LUKS as /)
if [[ $(echo $LUKS_DEV | grep $LUKS_BOOT_UUID) == "" ]]; then
LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_BOOT_UUID:$LUKS_BOOT_NAME"
fi
echo "$LUKS_DEV" > /tmp/.luks_dev
fi
}
btrfs_subvolumes() {
#1) save mount options and name of the root partition
mount | grep "on /mnt " | grep -Po '(?<=\().*(?=\))' > /tmp/.root_mount_options
#lsblk -lno MOUNTPOINT,NAME | awk '/^\/mnt / {print $2}' > /tmp/.root_partition
#2) choose automatic or manual mode
DIALOG " Choose mode " --menu "\n$_Note\nAutomatic mode is designed to\nallow integration with snapper,\nnon-recursive snapshots,\nseparating system and user data\nand restoring snapshots without losing data. " 0 0 2 \
"1" "automatic" \
"2" "manual" 2>/tmp/.subvol_mode
if [[ $(cat /tmp/.subvol_mode) != "" ]]; then
if [[ $(cat /tmp/.subvol_mode) -eq 2 ]]; then
# Create subvolumes manually
DIALOG " Create subvolumes " --inputbox "\nInput names of the subvolumes separated by spaces. The first one will be used for mounting /." 0 0 "@ @home @cache" 2>/tmp/.subvols || return 0
cd /mnt
for subvol in $(cat /tmp/.subvols); do
btrfs subvolume create $subvol
done
cd
# Mount subvolumes
umount /mnt
# Mount the first subvolume as /
mount -o $(cat ${MOUNT_OPTS}),subvol="$(awk '{print $1}' /tmp/.subvols)" "$(cat /tmp/.root_partition)" /mnt
# Remove the first subvolume from the subvolume list
sed -i -r 's/(\s+)?\S+//1' /tmp/.subvols
# Loop to mount all created subvolumes
for sub in $(cat /tmp/.subvols); do
DIALOG "Mount subvolume $sub" --inputbox "\nInput mountpoint of the subvolume $sub\nas it would appear in installed system\n(without prepending /mnt)\n." 0 0 "/home" 2>/tmp/.mountp || return 0
mkdir -p /mnt/"$(cat /tmp/.mountp)"
mount -o $(cat ${MOUNT_OPTS}),subvol="$sub" "$(cat /tmp/.root_partition)" /mnt"$(cat /tmp/.mountp)"
done
else
DIALOG " Automatic btrfs subvolumes" --yesno "\nThis creates subvolumes @ for /,@home for /home, @cache for /var/cache. \n " 0 0 || return 0
# Create subvolumes automatically
cd /mnt
btrfs subvolume create @
btrfs subvolume create @home
btrfs subvolume create @cache
#btrfs subvolume create @snapshots
cd
# Mount subvolumes
umount /mnt
mount -o $(cat ${MOUNT_OPTS}),subvol=@ "$(cat /tmp/.root_partition)" /mnt
mkdir -p /mnt/home
mkdir -p /mnt/var/cache
mount -o $(cat ${MOUNT_OPTS}),subvol=@home "$(cat /tmp/.root_partition)" /mnt/home
#mount -o $(cat ${MOUNT_OPTS}),subvol=@cache "$(cat /tmp/.root_partition)" /mnt/var/cache
fi
else
return 0
fi
}
mount_existing_subvols() {
# Set mount options
format_name=$(echo ${PARTITION} | rev | cut -d/ -f1 | rev)
format_device=$(lsblk -i | tac | sed -r 's/^[^[:alnum:]]+//' | sed -n -e "/$format_name/,/disk/p" | awk '/disk/ {print $1}')
if [[ "$(cat /sys/block/${format_device}/queue/rotational)" == 1 ]]; then
fs_opts="autodefrag,compress=zlib,noatime,nossd,commit=120"
else
fs_opts="compress=lzo,noatime,space_cache,ssd,commit=120"
fi
btrfs subvolume list /mnt | cut -d" " -f9 > /tmp/.subvols
umount /mnt
# Mount subvolumes one by one
for subvol in $(cat /tmp/.subvols); do
# Ask for mountpoint
DIALOG "Mount subvolume $subvol" --inputbox "\nInput mountpoint of the subvolume $subvol\nas it would appear in installed system\n(without prepending /mnt).\n" 0 0 "/" 2>/tmp/.mountp || return 0
[[ -e "/mnt/$(cat /tmp/.mountp)" ]] || mkdir -p /mnt/"$(cat /tmp/.mountp)"
# Mount the subvolume
mount -o "${fs_opts},subvol=$subvol" "$(cat /tmp/.root_partition)" /mnt"$(cat /tmp/.mountp)"
done
}