|
| 1 | +declare -A module_options |
| 2 | +module_options+=( |
| 3 | + ["module_partitioner,author"]="@igorpecovnik" |
| 4 | + ["module_partitioner,maintainer"]="@igorpecovnik" |
| 5 | + ["module_partitioner,feature"]="module_partitioner" |
| 6 | + ["module_partitioner,example"]="new run create delete show getroot autoinstall help" |
| 7 | + ["module_partitioner,desc"]="Partitioner manager TUI" |
| 8 | + ["module_partitioner,status"]="review" |
| 9 | + ["module_partitioner,doc_link"]="https://docs.armbian.com" |
| 10 | + ["module_partitioner,group"]="System" |
| 11 | + ["module_partitioner,port"]="" |
| 12 | + ["module_partitioner,arch"]="" |
| 13 | +) |
| 14 | + |
| 15 | +function module_partitioner() { |
| 16 | + local title="Partitioner" |
| 17 | + local condition=$(which "$title" 2>/dev/null) |
| 18 | + |
| 19 | + # Read boot loader functions |
| 20 | + [[ -f /usr/lib/u-boot/platform_install.sh ]] && source /usr/lib/u-boot/platform_install.sh |
| 21 | + |
| 22 | + # Start mtdcheck with probable MTD block device partitions: |
| 23 | + mtdcheck=$(grep 'mtdblock' /proc/partitions | awk '{print $NF}' | xargs) |
| 24 | + # Append mtdcheck with probable MTD char devices filtered for partition name(s) |
| 25 | + # containing "spl" or "boot" case insensitive, |
| 26 | + # since we are currently interested in MTD partitions for boot flashing only. |
| 27 | + # Note: The following statement will add matching MTD char device names |
| 28 | + # combined with partition name (separated from devicename by a :colon:): |
| 29 | + # mtd0:partition0_name mtd1:partition1_name ... mtdN:partitionN_name |
| 30 | + [[ -f /proc/mtd ]] && mtdcheck="$mtdcheck${mtdcheck:+ }$(grep -i -E '^mtd[0-9]+:.*(spl|boot).*' /proc/mtd | awk '{print $1$NF}' | sed 's/\"//g' | xargs)" |
| 31 | + |
| 32 | + apt -y install ntfs-3g bc |
| 33 | + |
| 34 | + # Convert the example string to an array |
| 35 | + local commands |
| 36 | + IFS=' ' read -r -a commands <<< "${module_options["module_partitioner,example"]}" |
| 37 | + |
| 38 | + case "$1" in |
| 39 | + "${commands[0]}") |
| 40 | + echo "Install to partition $2" |
| 41 | + exit |
| 42 | + ;; |
| 43 | + "${commands[1]}") |
| 44 | + |
| 45 | + while true; do |
| 46 | + |
| 47 | + # get all available targets |
| 48 | + ${module_options["module_partitioner,feature"]} ${commands[4]} |
| 49 | + |
| 50 | + list=() |
| 51 | + periodic=1 |
| 52 | + while IFS== read key value; do |
| 53 | + case "$key" in |
| 54 | + "name") name="$value" ;; |
| 55 | + "size") size=$(printf "%14s" "$value") ;; |
| 56 | + "type") type=$(printf "%4s" "$value") ;; |
| 57 | + "fsused") fsused="$value" ;; |
| 58 | + "fstype") fstype="$value" ;; |
| 59 | + "mountpoint") mountpoint="$value" ;; |
| 60 | + esac |
| 61 | + if [ "$(($periodic % 6))" -eq 0 ]; then |
| 62 | + if [[ "$type" == "disk" ]]; then |
| 63 | + # recognize devices features |
| 64 | + driveinfo=$(udevadm info --query=all --name=$name | grep 'ID_MODEL=' | cut -d"=" -f2 | sed "s/_/ /g") |
| 65 | + drivebus=$(udevadm info --query=all --name=$name | grep 'ID_BUS=' | cut -d"=" -f2 | sed "s/_/ /g") |
| 66 | + [[ $name == *mtdb* ]] && driveinfo="SPI flash" |
| 67 | + [[ $name == *nvme* ]] && driveinfo="M2 NVME solid state drive $driveinfo" |
| 68 | + # if smartmontools are installed, lets query more info |
| 69 | + if [[ $name == *nvme* ]] && command -v smartctl >/dev/null; then |
| 70 | + mapfile -t array < <(smartctl -ija $name | jq -r ' |
| 71 | + .model_name, |
| 72 | + .nvme_smart_health_information_log.data_units_written, |
| 73 | + .temperature.current' |
| 74 | + ) |
| 75 | + tbw=$(echo ${array[1]} | awk '{ printf "%.0f\n", $1*500/1024/1024/1024; }')"" |
| 76 | + temperature=$(echo ${array[2]})"℃" |
| 77 | + driveinfo="${array[0]} | TBW: ${tbw} | Temperature: ${temperature}" |
| 78 | + fi |
| 79 | + [[ $name == *mmc* ]] && driveinfo="eMMC or SD card" |
| 80 | + [[ $name == *sd* && $drivebus == usb ]] && driveinfo="USB storage $driveinfo" |
| 81 | + list+=("${name}" "$(printf "%-30s%12s" $name $size)" "$driveinfo") |
| 82 | + fi # type is disk |
| 83 | + fi |
| 84 | + periodic=$(($periodic + 1)) |
| 85 | + done <<< "$devices" |
| 86 | + |
| 87 | + list_length=$((${#list[@]} / 3)) |
| 88 | + selected_disk=$(dialog \ |
| 89 | + --notags \ |
| 90 | + --cancel-label "Cancel" \ |
| 91 | + --ok-label "Install" \ |
| 92 | + --extra-button \ |
| 93 | + --extra-label "Advanced" \ |
| 94 | + --erase-on-exit \ |
| 95 | + --item-help \ |
| 96 | + --title "Select destination drive" \ |
| 97 | + --menu "\n Storage device Size" \ |
| 98 | + $((${list_length} + 8)) 48 $((${list_length} + 1)) \ |
| 99 | + "${list[@]}" 3>&1 1>&2 2>&3) |
| 100 | + exitstatus=$? |
| 101 | + |
| 102 | + case "$exitstatus" in |
| 103 | + 0) ${module_options["module_partitioner,feature"]} ${commands[5]} # auto install |
| 104 | + ;; |
| 105 | + 1) break |
| 106 | + ;; |
| 107 | + 3) |
| 108 | + # drive partitioning |
| 109 | + devices=$( |
| 110 | + lsblk -Alnp -io NAME,SIZE,FSUSED,TYPE,FSTYPE,MOUNTPOINT -e 252 --json \ |
| 111 | + | jq --arg selected_disk "$selected_disk" '.blockdevices[]? |
| 112 | + | select((.name | test ($selected_disk)) |
| 113 | + and (.name | test ("mtdblock0|nvme|mmcblk|sd")) |
| 114 | + and (.name | test ("boot") | not ))' \ |
| 115 | + | jq -r 'to_entries|map("\(.key)=\(.value|tostring)")|.[]' |
| 116 | + ) |
| 117 | + list=() |
| 118 | + periodic=1 |
| 119 | + while IFS== read key value; do |
| 120 | + case "$key" in |
| 121 | + "name") name="$value" ;; |
| 122 | + "size") size=$(printf "%14s" "$value") ;; |
| 123 | + "type") type=$(printf "%4s" "$value") ;; |
| 124 | + "fsused") fsused="$value" ;; |
| 125 | + "fstype") fstype="$value" ;; |
| 126 | + "mountpoint") mountpoint="$value" ;; |
| 127 | + esac |
| 128 | + if [ "$(($periodic % 6))" -eq 0 ]; then |
| 129 | + if [[ "$type" == "part" ]]; then |
| 130 | + #echo "$periodic $name $size $type $fsused $fstype $mountpoint" |
| 131 | + driveinfo=$(udevadm info --query=all --name=$name | grep 'ID_MODEL=' | cut -d"=" -f2 | sed "s/_/ /g") |
| 132 | + drivebus=$(udevadm info --query=all --name=$name | grep 'ID_BUS=' | cut -d"=" -f2 | sed "s/_/ /g") |
| 133 | + [[ $fstype == null ]] && fstype="" |
| 134 | + [[ $fsused == null ]] && fsused="" |
| 135 | + [[ $name == *mtdb* ]] && driveinfo="SPI flash" |
| 136 | + [[ $name == *nvme* ]] && driveinfo="M2 NVME solid state drive $driveinfo" |
| 137 | + [[ $name == *mmc* ]] && driveinfo="eMMC or SD card" |
| 138 | + [[ $name == *sd* && $drivebus == usb ]] && driveinfo="USB storage $driveinfo" |
| 139 | + list+=("${name}" "$(printf "%-10s%14s%9s%9s" ${name} ${fstype} ${size} ${fsused})" "$driveinfo") |
| 140 | + fi |
| 141 | + fi |
| 142 | + periodic=$(($periodic + 1)) |
| 143 | + done <<< "$devices" |
| 144 | + ;; |
| 145 | + esac |
| 146 | + list_length=$((${#list[@]} / 3)) |
| 147 | + partitioner=$(dialog \ |
| 148 | + --notags \ |
| 149 | + --cancel-label "Cancel" \ |
| 150 | + --ok-label "Install" \ |
| 151 | + --erase-on-exit \ |
| 152 | + --extra-button \ |
| 153 | + --item-help \ |
| 154 | + --extra-label "Manage" \ |
| 155 | + --title "Select or manage partitions" \ |
| 156 | + --menu "\n Partition FS type Size Used" \ |
| 157 | + $((${list_length} + 8)) 48 $((${list_length} + 1)) \ |
| 158 | + "${list[@]}" 3>&1 1>&2 2>&3) |
| 159 | + exitstatus=$? |
| 160 | + case "$exitstatus" in |
| 161 | + *) ${module_options["module_partitioner,feature"]} ${commands[${exitstatus}]} $partitioner ;; |
| 162 | + 1) break ;; |
| 163 | + esac |
| 164 | + done |
| 165 | + ;; |
| 166 | + "${commands[2]}") |
| 167 | + echo "Select $3" |
| 168 | + exit |
| 169 | + ;; |
| 170 | + "${commands[3]}") |
| 171 | + # get additional info from partition |
| 172 | + local size=$(lsblk -Alnbp -io SIZE $2 | xargs -I {} echo "scale=0;{}/1024/1024/1024" | bc -l) |
| 173 | + local fstype=$(lsblk -Alnbp -io FSTYPE $2) |
| 174 | + local minimal=$(ntfsresize --info $2 -m | tail -1 | grep -Eo '[0-9]{1,10}' | xargs -I {} echo "scale=0;{}/1024" | bc -l) |
| 175 | + while true; do |
| 176 | + shrinkedsize=$(dialog --title "Shrinking $fstype partition $2" \ |
| 177 | + --inputbox "\nValid size between ${minimal}-${size} GB" 9 50 "$(( minimal + size / 2 ))" 3>&1 1>&2 2>&3) |
| 178 | + exitstatus=$? |
| 179 | + if [[ $shrinkedsize -ge $minimal ]]; then |
| 180 | + break |
| 181 | + fi |
| 182 | + done |
| 183 | + ntfsresize --no-action --size "${shrinkedsize}G" $2 >/dev/null |
| 184 | + if [[ $exitstatus -ne 1 && $? -eq 0 ]]; then |
| 185 | + ntfsresize -f --size "${shrinkedsize}G" $2 |
| 186 | + fi |
| 187 | + read |
| 188 | + # Removal logic here |
| 189 | + ;; |
| 190 | + "${commands[4]}") |
| 191 | + #recognize_root |
| 192 | + root_uuid=$(sed -e 's/^.*root=//' -e 's/ .*$//' < /proc/cmdline) |
| 193 | + root_partition=$(blkid | tr -d '":' | grep "${root_uuid}" | awk '{print $1}') |
| 194 | + root_partition_name=$(echo $root_partition | sed 's/\/dev\///g') |
| 195 | + root_partition_device_name=$(lsblk -ndo pkname $root_partition) |
| 196 | + root_partition_device=/dev/$root_partition_device_name |
| 197 | + # list all devices except rootfs |
| 198 | + devices=$( |
| 199 | + lsblk -Alnp -io NAME,SIZE,FSUSED,TYPE,FSTYPE,MOUNTPOINT -e 252 --json \ |
| 200 | + | jq --arg root_partition_device "$root_partition_device" '.blockdevices[]? |
| 201 | + | select((.name | test ($root_partition_device) | not) |
| 202 | + and (.name | test ("mtdblock0|nvme|mmcblk|sd")) |
| 203 | + and (.name | test ("boot|mtdb") | not ))' \ |
| 204 | + | jq -r 'to_entries|map("\(.key)=\(.value|tostring)")|.[]' |
| 205 | + ) |
| 206 | + ;; |
| 207 | + "${commands[6]}") |
| 208 | + |
| 209 | + if [[ $(type -t write_uboot_platform_mtd) == function ]]; then |
| 210 | + dialog --title "$title" --backtitle "$backtitle" --yesno \ |
| 211 | + "Do you want to write the bootloader to MTD Flash?\n\nIt is required if you have not done it before or if you have some non-Armbian bootloader in this flash." 8 60 |
| 212 | + |
| 213 | + if [[ $? -eq 0 ]]; then |
| 214 | + write_uboot_to_mtd_flash "$DIR" "$mtdcheck" |
| 215 | + fi |
| 216 | + fi |
| 217 | + |
| 218 | + echo "Delete $2" |
| 219 | + read |
| 220 | + # Removal logic here |
| 221 | + ;; |
| 222 | + "${commands[7]}") |
| 223 | + echo -e "\nUsage: ${module_options["module_partitioner,feature"]} <command>" |
| 224 | + echo -e "Commands: ${module_options["module_partitioner,example"]}" |
| 225 | + echo "Available commands:" |
| 226 | + echo -e "\trun\t- Run $title." |
| 227 | + echo |
| 228 | + ;; |
| 229 | + *) |
| 230 | + ${module_options["module_partitioner,feature"]} ${commands[7]} |
| 231 | + ;; |
| 232 | + esac |
| 233 | + } |
| 234 | + |
| 235 | +# uncomment to test the module |
| 236 | +module_partitioner "$1" |
| 237 | + |
| 238 | + |
| 239 | + |
| 240 | + |
0 commit comments