#!/bin/sh . /lib/partman/lib/lvm-base.sh . /lib/partman/lib/commit.sh ##################################### # # Functions # ##################################### do_initial_setup() { # Commit the changes confirm_changes partman-lvm || exit 0 commit_changes partman-lvm/commit_failed || exit $? # initialize (pvcreate) all volumes that are not already prepared for pv in $(pv_list); do if ! pv_create "$pv"; then db_subst partman-lvm/pvcreate_error PV "$pv" db_input critical partman-lvm/pvcreate_error db_go || true exit 0 fi done } do_display() { lvm_get_config db_subst partman-lvm/displayall CURRENT_CONFIG "$RET" db_input critical partman-lvm/displayall db_capb align db_go || true db_capb backup align db_get partman-lvm/displayall } do_vg_create() { local pvs line pv output vg pathmap pvs="" pathmap="" # Look for free PVs IFS="$NL" for line in $(pv_list_allowed_free); do restore_ifs local dev="${line%%$TAB*}" line="${line#*$TAB}" local id="${line%%$TAB*}" line="${line#*$TAB}" local size="${line%%$TAB*}" local path="${line#*$TAB}" cd $dev if [ -e "$path" ] && pv_get_info "$path"; then output=$(printf "%-30s (%sMB)" "$path" "$SIZE") elif [ ! -s "$id/visual_filesystem" ]; then output=$(printf "%-30s (%sMB)" "$path" "$(convert_to_megabytes $size)") else local visual="$(cat "$id/visual_filesystem")" output=$(printf "%-30s (%sMB; %s)" "$path" "$(convert_to_megabytes $size)" "$visual") fi pvs="${pvs:+$pvs, }$output" pathmap="${pathmap:+$pathmap$NL}$path$TAB$dev//$id" IFS="$NL" done restore_ifs if [ -z "$pvs" ]; then db_input critical partman-lvm/nopartitions db_go || true return fi # Prompt for VG name db_set partman-lvm/vgcreate_name "" db_input critical partman-lvm/vgcreate_name db_go || return db_get partman-lvm/vgcreate_name vg="$RET" # Check VG name if [ -z "$vg" ]; then db_input critical partman-lvm/vgcreate_nonamegiven db_go || true return fi if ! vg_name_ok "$vg"; then db_input critical partman-lvm/badnamegiven db_go || true return fi # Check whether the VG name is already in use if vgs "$vg" > /dev/null 2>&1; then db_input critical partman-lvm/vgcreate_nameused db_go || true return fi # Check whether the VG name overlaps with an existing device if [ -e "/dev/$vg" ]; then db_input critical partman-lvm/vgcreate_devnameused db_go || true return fi # Choose the PVs to use db_subst partman-lvm/vgcreate_parts PARTITIONS "$pvs" db_reset partman-lvm/vgcreate_parts db_input critical partman-lvm/vgcreate_parts db_go || return db_get partman-lvm/vgcreate_parts if [ -z "$RET" ]; then db_input critical partman-lvm/vgcreate_nosel db_go || true return fi pvs=$(echo "$RET" | sed -e "s/ *([^)]*) *//g; s/ *, */\\$NL/g") local newpvs= local need_commit= IFS="$NL" for pv in $pvs; do for line in $pathmap; do restore_ifs if [ "${line%%$TAB*}" = "$pv" ]; then local devid="${line#*$TAB}" local path if path="$(pv_prepare "${devid%//*}" "${devid#*//}")"; then need_commit=true fi newpvs="${newpvs:+$newpvs }$path" break fi IFS="$NL" done IFS="$NL" done restore_ifs pvs="$newpvs" if [ "$need_commit" ]; then do_initial_setup fi if ! vg_create "$vg" $pvs; then db_subst partman-lvm/vgcreate_error VG "$vg" db_input critical partman-lvm/vgcreate_error db_go || true else vg_lock_pvs "$vg" $pvs fi } do_vg_delete() { local vgs vg output pvs vgs="" # Look for VGs with no LVs for vg in $(vg_list); do vg_get_info "$vg" [ "$LVS" -eq 0 ] || continue output=$(printf "%-30s (%sMB)" "$vg" "$SIZE") vgs="${vgs:+$vgs, }$output" done if [ -z "$vgs" ]; then db_input critical partman-lvm/vgdelete_novg db_go || true return fi # Prompt for VG to delete db_subst partman-lvm/vgdelete_names GROUPS "$vgs" db_reset partman-lvm/vgdelete_names db_input critical partman-lvm/vgdelete_names db_go || return db_get partman-lvm/vgdelete_names vg=$(echo "$RET" | sed -e 's/[[:space:]]*(.*//') # Confirm db_subst partman-lvm/vgdelete_confirm VG $vg db_set partman-lvm/vgdelete_confirm false db_input critical partman-lvm/vgdelete_confirm db_go || true db_get partman-lvm/vgdelete_confirm [ "$RET" = true ] || return pvs=$(vg_list_pvs "$vg") if ! vg_delete "$vg"; then db_input critical partman-lvm/vgdelete_error db_go || true else for pv in $pvs; do partman_unlock_unit "$pv" done fi } do_vg_extend() { local pvs line pv output vgs vg pathmap vgs="" pathmap="" # Get eligible PVs pvs="" IFS="$NL" for line in $(pv_list_allowed_free); do restore_ifs local dev="${line%%$TAB*}" line="${line#*$TAB}" local id="${line%%$TAB*}" line="${line#*$TAB}" local size="${line%%$TAB*}" local path="${line#*$TAB}" cd $dev if [ -e "$path" ] && pv_get_info "$path"; then output=$(printf "%-30s (%sMB)" "$path" "$SIZE") elif [ ! -f "$id/visual_filesystem" ]; then continue else local visual="$(cat "$id/visual_filesystem")" output=$(printf "%-30s (%sMB; %s)" "$path" "$(convert_to_megabytes $size)" "$visual") fi pvs="${pvs:+$pvs, }$output" pathmap="${pathmap:+$pathmap$NL}$path$TAB$dev//$id" IFS="$NL" done restore_ifs if [ -z "$pvs" ]; then db_input critical partman-lvm/nopartitions db_go || true return fi # Get VG list vgs="" for vg in $(vg_list); do vg_get_info "$vg" output=$(printf "%-30s (%sMB)" "$vg" "$SIZE") vgs="${vgs:+$vgs, }$output" done if [ -z "$vgs" ]; then db_input critical partman-lvm/vgextend_novg db_go || true return fi # Prompt for VG to extend db_subst partman-lvm/vgextend_names GROUPS "$vgs" db_reset partman-lvm/vgextend_names db_input critical partman-lvm/vgextend_names db_go || return db_get partman-lvm/vgextend_names vg=$(echo "$RET" | sed -e 's/[[:space:]]*(.*//') # Prompt for PVs to use db_subst partman-lvm/vgextend_parts PARTITIONS "$pvs" db_reset partman-lvm/vgextend_parts db_input critical partman-lvm/vgextend_parts db_go || return db_get partman-lvm/vgextend_parts if [ -z "$RET" ]; then db_input critical partman-lvm/vgextend_nosel db_go || true return fi pvs=$(echo "$RET" | sed -e "s/ *([^)]*) *//g; s/ *, */\\$NL/g") local newpvs= local need_commit= IFS="$NL" for pv in $pvs; do for line in $pathmap; do restore_ifs if [ "${line%%$TAB*}" = "$pv" ]; then local devid="${line#*$TAB}" local path if path="$(pv_prepare "${devid%//*}" "${devid#*//}")"; then need_commit=true fi newpvs="${newpvs:+$newpvs }$path" break fi IFS="$NL" done IFS="$NL" done restore_ifs pvs="$newpvs" if [ "$need_commit" ]; then do_initial_setup fi for pv in $pvs; do if ! vg_extend "$vg" "$pv"; then db_subst partman-lvm/vgextend_error PARTITION $pv db_subst partman-lvm/vgextend_error VG $vg db_input critical partman-lvm/vgextend_error db_go || true return else vg_lock_pvs "$vg" $pv fi done } do_vg_reduce() { local vgs vg output pvs pv # Check for VGs with more than one pv vgs="" db_metaget partman-lvm/text/pvs description for vg in $(vg_list); do vg_get_info "$vg" [ "$PVS" -gt 1 ] || continue output=$(printf "%-30s (%sMB - %s)" "$vg" "$FREE" "$PVS $RET") vgs="${vgs:+$vgs, }$output" done if [ -z "$vgs" ]; then db_input critical partman-lvm/vgreduce_novg db_go || true return fi # Prompt for VG to reduce db_subst partman-lvm/vgreduce_names GROUPS "$vgs" db_reset partman-lvm/vgreduce_names db_input critical partman-lvm/vgreduce_names db_go || return db_get partman-lvm/vgreduce_names vg=$(echo "$RET" | sed -e 's/[[:space:]]*(.*//') # Prompt for PV to remove pvs="" for pv in $(vg_list_pvs "$vg"); do pv_get_info "$pv" output=$(printf "%-30s (%sMB)" "$pv" "$SIZE") pvs="${pvs:+$pvs, }$output" done # Prompt for PVs to use db_subst partman-lvm/vgreduce_parts PARTITIONS "$pvs" db_reset partman-lvm/vgreduce_parts db_input critical partman-lvm/vgreduce_parts db_go || return db_get partman-lvm/vgreduce_parts if [ -z "$RET" ]; then db_input critical partman-lvm/vgreduce_nosel db_go || true return fi pvs=$(echo "$RET" | sed -e 's/ *([^)]*) *//g') pvs=$(csv_to_ssv "$pvs") # Check if all PVs were selected and delete in that case count=$(echo -n "$pvs" | wc -w) vg_get_info "$vg" if [ $count -eq $PVS ]; then if ! vg_delete "$vg"; then db_input critical partman-lvm/vgdelete_error db_go || true fi return fi # Go for it for pv in $pvs; do if ! vg_reduce "$vg" "$pv"; then db_subst partman-lvm/vgreduce_error VG "$vg" db_subst partman-lvm/vgreduce_error PARTITION "$pv" db_input critical partman-lvm/vgreduce_error db_go || true return else partman_unlock_unit "$pv" fi done } do_lv_create() { local vgs vg output lv extents size max_size # Find eligible VGs vgs="" for vg in $(vg_list_free); do vg_get_info "$vg" output=$(printf "%-30s (%sMB)" "$vg" "$FREE") vgs="${vgs:+$vgs, }$output" done if [ -z "$vgs" ]; then db_input critical partman-lvm/lvcreate_nofreevg db_go || true return fi # Prompt for VG to use db_subst partman-lvm/lvcreate_vgnames GROUPS "$vgs" db_reset partman-lvm/lvcreate_vgnames db_input critical partman-lvm/lvcreate_vgnames db_go || return db_get partman-lvm/lvcreate_vgnames vg=$(echo "$RET" | sed -e 's/[[:space:]]*(.*//') # Prompt for name to give the new lv db_set partman-lvm/lvcreate_name "" db_input critical partman-lvm/lvcreate_name db_go || return db_get partman-lvm/lvcreate_name lv="$RET" # Check LV name if [ -z "$lv" ]; then db_input critical partman-lvm/lvcreate_nonamegiven db_go || true return fi if ! lv_name_ok "$lv"; then db_input critical partman-lvm/badnamegiven db_go || true return fi # Make sure the name isn't already in use if lvs "/dev/$vg/$lv" > /dev/null 2>&1; then db_subst partman-lvm/lvcreate_exists LV $lv db_subst partman-lvm/lvcreate_exists VG $vg db_input critical partman-lvm/lvcreate_exists db_go || true return fi # Prompt for lv size vg_get_info "$vg" max_size="${FREE}M" db_set partman-lvm/lvcreate_size "${max_size}B" db_fset partman-lvm/lvcreate_size seen false db_input critical partman-lvm/lvcreate_size db_go || return db_get partman-lvm/lvcreate_size [ -n "$RET" ] || return size="$RET" extents=$(lvm_extents_from_human "$vg" "$size") # If the maximum free space should be used for the new LV, use the # number of physical extents (PEs) because the size given by LVM # might not be accurate, resulting in an error because the VG is # not big enough (see #250594). if [ $(human2longint "$size") = $(human2longint "$max_size") ]; then extents=$FREEPE fi if ! lv_create "$vg" "$lv" "$extents"; then db_subst partman-lvm/lvcreate_error VG $vg db_subst partman-lvm/lvcreate_error LV $lv db_subst partman-lvm/lvcreate_error SIZE $size db_input critical partman-lvm/lvcreate_error db_go || true return fi } do_lv_delete() { local lvs line output lv vg lvs="" for line in $(lv_list); do lv=$(echo "$line" | cut -d':' -f1) vg=$(echo "$line" | cut -d':' -f2) lv_get_info "$vg" "$lv" output=$(printf "%-30s (%sMB - %s)" "$lv" "$SIZE" "$vg") lvs="${lvs:+$lvs, }$output" done if [ -z "$lvs" ]; then db_input critical partman-lvm/lvdelete_nolv db_go || true return fi db_subst partman-lvm/lvdelete_lvnames LVS "$lvs" db_reset partman-lvm/lvdelete_lvnames db_input critical partman-lvm/lvdelete_lvnames db_go || return db_get partman-lvm/lvdelete_lvnames lv=$(echo "$RET" | cut -d' ' -f1) vg=$(echo "$RET" | sed -e 's/.*(\(.*\))/\1/') vg=${vg##* } if ! lv_delete "$vg" "$lv"; then db_subst partman-lvm/lvdelete_error VG $vg db_subst partman-lvm/lvdelete_error LV $lv db_input critical partman-lvm/lvdelete_error db_go || true return fi } lvm_menu_add () { local choice=$1 db_metaget partman-lvm/menu/$choice description if [ "$choices" ]; then choices="$choices, $choice" choices_l10n="$choices_l10n, $RET" else choices="$choice" choices_l10n="$RET" fi } ##################################### # # Main stuff # ##################################### do_initial_setup while [ 1 ]; do # Get some statistics allowed_pvs=$(pv_list_allowed_free | wc -l) free_pvs=$(pv_list_free | wc -l) used_pvs=$(pvs --noheadings | wc -l) # All PVs used_pvs=$(( $used_pvs - $free_pvs )) # Used = All PVs - Free PVs vgs=$(vg_list | wc -l) lvs=$(lv_list | wc -l) # Build menu options choices="" choices_l10n="" lvm_menu_add display if [ $allowed_pvs -gt 0 ]; then lvm_menu_add createvg fi # Other options only if there is at least one VG if [ $vgs -gt 0 ]; then # First check, then add so the order is constant do_reducevg="" do_deletevg="" do_createlv="" # Check all VGs for vg in $(vg_list); do vg_get_info "$vg" if [ $PVS -gt 1 ]; then do_reducevg="1" fi if [ $LVS -eq 0 ]; then do_deletevg="1" fi if [ $FREEPE -gt 0 ]; then do_createlv="1" fi done if [ "$do_createlv" ]; then lvm_menu_add createlv fi if [ "$do_deletevg" ]; then lvm_menu_add deletevg fi if [ $lvs -gt 0 ]; then lvm_menu_add deletelv fi if [ $allowed_pvs -gt 0 ]; then lvm_menu_add extendvg fi if [ "$do_reducevg" ]; then lvm_menu_add reducevg fi fi # Add Finish option lvm_menu_add finish # Setup main menu template db_subst partman-lvm/mainmenu CHOICES "$choices" db_subst partman-lvm/mainmenu CHOICES_L10N "$choices_l10n" db_subst partman-lvm/mainmenu FREE_PVS "$free_pvs" db_subst partman-lvm/mainmenu USED_PVS "$used_pvs" db_subst partman-lvm/mainmenu VGS "$vgs" db_subst partman-lvm/mainmenu LVS "$lvs" db_reset partman-lvm/mainmenu db_input critical partman-lvm/mainmenu db_go || break db_get partman-lvm/mainmenu option="$RET" case "$option" in display) do_display ;; createvg) do_vg_create ;; deletevg) do_vg_delete ;; extendvg) do_vg_extend ;; reducevg) do_vg_reduce ;; createlv) do_lv_create ;; deletelv) do_lv_delete ;; finish) break ;; *) logger -t partman-lvm "Unknown selection '$option'" break ;; esac done stop_parted_server restart_partman exit 0