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.
1684 lines
65 KiB
Bash
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
|
|
}
|