diff options
-rw-r--r-- | NOTES | 13 | ||||
-rw-r--r-- | TODO | 14 | ||||
-rw-r--r-- | src/core/libs/lib-blockdevices-filesystems.sh | 228 | ||||
-rw-r--r-- | src/core/libs/lib-ui-interactive.sh | 20 | ||||
-rw-r--r-- | unofficial/modules/dieter/procedures/automatic | 2 |
5 files changed, 148 insertions, 129 deletions
@@ -0,0 +1,13 @@ +* umounting/destructing blockdevice/filesystem stuff in the blockdevice library. +** Goals +not break while trying to build the setup like the user requested (breakage could happen if a device mapper volume is still active or a filesystem is still mounted) +still allow user to mount stuff himself behind the installers back. he is smarter then us. just do what we're told. +** Options +*** umount/deconstruct before trying to build +problems: - it's hard to know what we should delete, our 'build' plan might be different then the current environment (eg devices with same name but other function), + usually because of a previous run with the wrong settings, or which failed + - we can't base ourselves on things like "we should only have / and /dev/shm". The user can mount things himself + - quite complicated code if want to make it smart, but it's a dead end anyway. +*** if buildup fails, ask user to rollback -> implemented approach +- user should not ctrl-c and installer should not crash. this is doable. a 'wrong' state can be an acceptable exception. +- right now we can start repartitioning a disks that has filesystems mounted. is this harmfull? this only happens if unclean rollback or user did it, so NP i think @@ -16,20 +16,6 @@ ALPHA PHASE: get some people to test and suggest ideas, while fixing bugs and re * automatically configure grub for dm_crypt and lvm * 'additional, optional info' not shown correctly in _dia_ask_option bug -* Rethink umount/destruct blockdevice/filesystem stuff -** Goals -not break while trying to build the setup like the user requested (breakage could happen if a device mapper volume is still active or a filesystem is still mounted) -still allow user to mount stuff himself behind the installers back. he is smarter then us. just do what we're told. -** Options -*** umount/deconstruct before trying to build -problems: - it's hard to know what we should delete, our 'build' plan might be different then the current environment (eg devices with same name but other function), - usually because of a previous run with the wrong settings, or which failed - - we can't base ourselves on things like "we should only have / and /dev/shm". The user can mount things himself - - quite complicated code if want to make it smart, but it's a dead end anyway. -*** if buildup fails, ask user to rollback -- user should not ctrl-c and installer should not crash. this is doable. a 'wrong' state can be an exception. - - BETA PHASE: try to get aif on the (beta) installcd as an experimental, alternative installer. * find a way to not have to preload libs and stuff, only load them when needed. -> faster start of install program * involve broader community diff --git a/src/core/libs/lib-blockdevices-filesystems.sh b/src/core/libs/lib-blockdevices-filesystems.sh index c7de0e8..26389d1 100644 --- a/src/core/libs/lib-blockdevices-filesystems.sh +++ b/src/core/libs/lib-blockdevices-filesystems.sh @@ -374,18 +374,92 @@ generate_filesystem_list () } -# process all entries in $TMP_BLOCKDEVICES, create all blockdevices and filesystems and mount them correctly, destroying what's necessary first. +# process all entries in $TMP_BLOCKDEVICES, create all blockdevices and filesystems and mount them correctly process_filesystems () { debug "process_filesystems Called. checking all entries in $TMP_BLOCKDEVICES" rm -f $TMP_FSTAB generate_filesystem_list + returncode=0 - # phase 1: destruct all mounts in the vfs that are about to be reconstructed. (and also swapoff where appropriate) + # phase 1: create all blockdevices and filesystems in the correct order (for each fs, the underlying block/lvm/devicemapper device must be available so dependencies must be resolved. for lvm:first pv's, then vg's, then lv's etc) + # don't let them mount yet. we take care of all that ourselves in the next phase + + infofy "Phase 1: Creating blockdevices" disks + done_filesystems= + for i in `seq 1 10` + do + open_items=0 + while read part part_type part_label fs_type fs_create fs_mountpoint fs_mount fs_opts fs_label fs_params + do + fs_id="$part $fs_type $fs_mountpoint $fs_opts $fs_label $fs_params" + if [ "$fs_create" = yes ] + then + if check_is_in "$fs_id" "${done_filesystems[@]}" + then + debug "$fs_id ->Already done" + else + # We can't always do -b on the lvm VG. because the devicefile sometimes doesn't exist for a VG. vgdisplay to the rescue! + if [ "$part_type" = lvm-vg ] && vgdisplay $part | grep -q 'VG Name' # $part is a lvm VG and it exists. note that vgdisplay exists 0 when the requested vg doesn't exist. + then + debug "$fs_id ->Still need to do it: Making the filesystem on a vg volume" + infofy "Making $fs_type filesystem on $part" disks + process_filesystem $part $fs_type $fs_create $fs_mountpoint no_mount $fs_opts $fs_label $fs_params && done_filesystems+=("$fs_id") || returncode=1 + elif [ "$part_type" != lvm-pv -a -b "$part" ] # $part is not a lvm PV and it exists + then + debug "$fs_id ->Still need to do it: Making the filesystem on a non-pv volume" + infofy "Making $fs_type filesystem on $part" disks + process_filesystem $part $fs_type $fs_create $fs_mountpoint no_mount $fs_opts $fs_label $fs_params && done_filesystems+=("$fs_id") || returncode=1 + elif [ "$part_type" = lvm-pv ] && pvdisplay ${fs_params//:/ } >/dev/null # $part is a lvm PV. all needed lvm pv's exist. note that pvdisplay exits 5 as long as one of the args doesn't exist + then + debug "$fs_id ->Still need to do it: Making the filesystem on a pv volume" + infofy "Making $fs_type filesystem on $part" disks + process_filesystem ${part/+/} $fs_type $fs_create $fs_mountpoint no_mount $fs_opts $fs_label $fs_params && done_filesystems+=("$fs_id") || returncode=1 + else + debug "$fs_id ->Cannot do right now..." + open_items=1 + fi + fi + fi + done < $TMP_FILESYSTEMS + [ $open_items -eq 0 ] && break + done + [ $open_items -eq 1 ] && show_warning "Filesystem/blockdevice processor problem" "Warning: Could not create all needed filesystems. Either the underlying blockdevices didn't became available in 10 iterations, or process_filesystem failed" && returncode=1 + + + + # phase 2: mount all filesystems in the vfs in the correct order. (also swapon where appropriate) + + infofy "Phase 2: Mounting filesystems" disks + sort -t \ -k 6 $TMP_FILESYSTEMS | while read part part_type part_label fs_type fs_create fs_mountpoint fs_mount fs_opts fs_label fs_params + do + if [ "$fs_mountpoint" != no_mountpoint ] + then + infofy "Mounting $part" disks + process_filesystem $part $fs_type no $fs_mountpoint $fs_mount $fs_opts $fs_label $fs_params || returncode=1 + elif [ "$fs_type" = swap ] + then + infofy "Swaponning $part" disks + process_filesystem $part $fs_type no $fs_mountpoint $fs_mount $fs_opts $fs_label $fs_params || returncode=1 + fi + done + + [ $returncode -eq 0 ] && infofy "Done processing filesystems/blockdevices" disks 1 && return 0 + return $returncode +} + + +# Roll back everything specified in $BLOCK_DATA. Doesn't restore data after you erased it, of course. +rollback_filesystems () +{ + infofy "Rolling back filesystems..." disks + generate_filesystem_list + local warnings= + + # phase 1: destruct all mounts in the vfs and swapoff swap volumes who are listed in $BLOCK_DATA # re-order list so that we umount in the correct order. eg first umount /a/b/c, then /a/b. we sort alphabetically, which has the side-effect of sorting by stringlength, hence by vfs dependencies. - # TODO: this is not entirely correct: what if something is mounted in a previous run that is now not anymore in $TMP_BLOCKDEVICES ? that needs to be cleaned up too. - infofy "Phase 1: Umounting all needed mountpoints" disks + infofy "Phase 1: Umounting all specified mountpoints" disks done_umounts= # We translate some devices back to their original (eg /dev/sda3+ -> /dev/sda3 for lvm PV's). No need to bother user twice for such devices. sort -t \ -k 6 $TMP_FILESYSTEMS | tac | while read part part_type part_label fs_type fs_create fs_mountpoint fs_mount fs_opts fs_label fs_params do @@ -399,12 +473,13 @@ process_filesystems () if ! check_is_in "$part_real" "${done_umounts[@]}" then infofy "(Maybe) Umounting $part_real" disks - if mount | grep -q "^$part_real " # could be that this was not mounted yet. no problem, we can just skip it then. NOTE: umount part, not mountpoint. some other part could be mounted in this place, we don't want to affect that. + if mount | grep -q "^$part_real " # could be that this was not mounted yet. no problem, we can just skip it then. then if umount $part_real >$LOG then done_umounts+=("$part_real") else + warnings="$warnings\nCould not umount umount $part_real . Probably device is still busy. See $LOG" show_warning "Umount failure" "Could not umount umount $part_real . Probably device is still busy. See $LOG" #TODO: fix device busy things fi fi @@ -412,41 +487,17 @@ process_filesystems () fi done -# devs_avail=1 -# while [ $devs_avail = 1 ] -# do -# devs_avail=0 -# for part in `findpartitions` -# do -# if entry=`grep ^$part $TMP_BLOCKDEVICES` -# then -# process_filesystem "$entry" && sed -i "/^$part/d" $TMP_BLOCKDEVICES && debug "$part processed and removed from $TMP_BLOCKDEVICES" -# devs_avail=1 -# fi -# done -# done -# entries=`wc -l $TMP_BLOCKDEVICES` -# if [ $entries -gt 0 ] -# then -# die_error "Could not process all entries because not all available blockdevices became available. Unprocessed:`awk '{print \$1}' $TMP_BLOCKDEVICES`" -# else -# debug "All entries processed..." -# fi - - - # phase 2: destruct blockdevices if they would exist already and must be destructed, in the correct order (first lvm LV, then VG, then PV etc) - # targets are device-mapper devices such as any lvm things, dm_crypt devices, etc and lvm PV's. - # in theory devices with same names could be stacked on each other with different dependencies. I hope that's not the case for now. In the future maybe we should destruct things we need and who are in /etc/mtab or something. TODO: example?? I should have noted it when i thought of this. - # NOTE: an alternative approach could be to just go over all /dev/mapper devices or normal devices that are lvm PV's (by using finddisks etc instead of $TMP_BLOCKDEVICES, or even better by using finddisks and only doing it if they are in $TMP_BLOCKDEVICES ) and attempt to destruct. - # do that a few times and the ones that blocked because something else on it will probable have become freed and possible to destruct + # phase 2: destruct blockdevices listed in $BLOCK_DATA if they would exist already, in the correct order (first lvm LV, then VG, then PV etc) + # targets are device-mapper devices such as any lvm things, dm_crypt devices, etc and lvm PV's. - # Possible approach 1 (not implemented): for each target in $TMP_BLOCKDEVICES, check that it has no_fs or has a non-lvm/dm_crypt fs. (egrep -v ' lvm-pv;| lvm-vg;| lvm-lv;| dm_crypt;' ) and clean it -> requires updating of underlying block device when you clean something, on a copy of .block_data etc. too complicated + # Possible approach 1 (not implemented): for each target in $TMP_BLOCKDEVICES, check that it has no_fs or has a non-lvm/dm_crypt fs. (egrep -v ' lvm-pv;| lvm-vg;| lvm-lv;| dm_crypt;' ) and clean it + # -> requires updating of underlying block device string when you clean something, on a copy of .block_data etc. too complicated # Approach 2 : iterate over all targets in $TMP_BLOCKDEVICES as much as needed, until a certain limit, and in each loop check what can be cleared by looking at the real, live usage of / dependencies on the partition. - # the advantage of approach 2 over 1 is that 1) it's easier. 2) it's better, because the live environment can be different then what's described in $TMP_BLOCKDEVICES anyway. - # TODO: what if eg /dev/sda2 is listed now as a PV but in the runtime system it's in use as a dm_crypt or something? then it won't be cleaned up and it will still be blocking. Maybe we should start by looking at the actual runtime system and clean up from that. + # -> easier (implemented) + - infofy "Phase 2: destructing blockdevices" disks + infofy "Phase 2: destructing specified blockdevices" disks for i in `seq 1 10` do open_items=0 @@ -463,7 +514,11 @@ process_filesystems () open_items=1 else infofy "Attempting destruction of device $part (type $part_type)" disks - cryptsetup luksClose $real_part >$LOG || show_warning "process_filesystems blockdevice destruction" "Could not cryptsetup luksClose $real_part" + if ! cryptsetup luksClose $real_part >$LOG + then + warnings="$warnings\nCould not cryptsetup luksClose $real_part" + show_warning "process_filesystems blockdevice destruction" "Could not cryptsetup luksClose $real_part" + fi fi else debug "Skipping destruction of device $part (type $part_type) because it doesn't exist" @@ -472,13 +527,17 @@ process_filesystems () then if [ -b $real_part ] && pvdisplay $real_part &>/dev/null then - if if vgdisplay -v 2>/dev/null | grep -q $real_part # check if it's in use + if vgdisplay -v 2>/dev/null | grep -q $real_part # check if it's in use then debug "$part ->Cannot do right now..." open_items=1 else infofy "Attempting destruction of device $part (type $part_type)" disks - pvremove $real_part >$LOG || show_warning "process_filesystems blockdevice destruction" "Could not pvremove $part" + if ! pvremove $real_part >$LOG + then + warnings="$warnings\nCould not pvremove $part" + show_warning "process_filesystems blockdevice destruction" "Could not pvremove $part" + fi fi else debug "Skipping destruction of device $part (type $part_type) because it doesn't exist" @@ -494,7 +553,11 @@ process_filesystems () open_items=1 else infofy "Attempting destruction of device $part (type $part_type)" disks - vgremove $part >$LOG || show_warning "process_filesystems blockdevice destruction" "Could not vgremove $part" # we shouldn't need -f because we clean up the lv's first. + if ! vgremove $part >$LOG # we shouldn't need -f because we clean up the lv's first. + then + warnings="$warnings\nCould not vgremove $part" + show_warning "process_filesystems blockdevice destruction" "Could not vgremove $part" + fi fi else debug "Skipping destruction of device $part (type $part_type) because it doesn't exist" @@ -504,15 +567,20 @@ process_filesystems () if lvdisplay $part >/dev/null && ! vgdisplay $part 2>/dev/null | grep -q 'VG Name' # it exists: lvdisplay works, and it's not a volume group (you can do lvdisplay $volumegroup) then have_crypt=0 - for i in `ls /dev/mapper/`; do cryptsetup isLuks $i >/dev/null && have_crypt=1; done - # TODO: Find a way to determine if a volume is used for a dm_crypt device. this is a hacky workaround that may not work (we check if we have we have dm_crypt devices in /dev/mapper. we may have 'em, but not there, or we could have hits, but devices that don't use this LV) + for i in `awk '$2 ~ /dm_crypt/ {print $1}' $TMP_BLOCKDEVICES`; do cryptsetup isLuks $i >/dev/null && have_crypt=1; done + # TODO: Find a way to determine if a volume is used for a dm_crypt device. + # this is a workaround that checks if any of the specified dm_crypts is still active. These devices may not be using this lvm LV, but we don't do much harm in skipping anyway. The dm_crypts should be cleared otherwise there's a problem anyway. if [ $have_crypt -gt 0 ] then debug "$part ->Cannot do right now..." open_items=1 else infofy "Attempting destruction of device $part (type $part_type)" disks - lvremove -f $part >$LOG || show_warning "process_filesystems blockdevice destruction" "Could not lvremove -f $part" + if ! lvremove -f $part >$LOG + then + warnings="$warnings\nCould not lvremove -f $part" + show_warning "process_filesystems blockdevice destruction" "Could not lvremove -f $part" + fi fi else debug "Skipping destruction of device $part (type $part_type) because it doesn't exist" @@ -524,72 +592,14 @@ process_filesystems () [ $open_items -eq 0 ] && break done - [ $open_items -eq 1 ] && show_warning "Filesystem/blockdevice processor problem" "Warning: Could not destruct all filesystems/blockdevices. It appears some depending filesystems/blockdevices could not be cleared in 10 iterations" - - - # phase 3: create all blockdevices and filesystems in the correct order (for each fs, the underlying block/lvm/devicemapper device must be available so dependencies must be resolved. for lvm:first pv's, then vg's, then lv's etc) - # don't let them mount yet. we take care of all that ourselves in the next phase - - infofy "Phase 3: Creating blockdevices" disks - done_filesystems= - for i in `seq 1 10` - do - open_items=0 - while read part part_type part_label fs_type fs_create fs_mountpoint fs_mount fs_opts fs_label fs_params - do - fs_id="$part $fs_type $fs_mountpoint $fs_opts $fs_label $fs_params" - if [ "$fs_create" = yes ] - then - if check_is_in "$fs_id" "${done_filesystems[@]}" - then - debug "$fs_id ->Already done" - else - # We can't always do -b on the lvm VG. because the devicefile sometimes doesn't exist for a VG. vgdisplay to the rescue! - if [ "$part_type" = lvm-vg ] && vgdisplay $part | grep -q 'VG Name' # $part is a lvm VG and it exists. note that vgdisplay exists 0 when the requested vg doesn't exist. - then - debug "$fs_id ->Still need to do it: Making the filesystem on a vg volume" - infofy "Making $fs_type filesystem on $part" disks - process_filesystem $part $fs_type $fs_create $fs_mountpoint no_mount $fs_opts $fs_label $fs_params && done_filesystems+=("$fs_id") - elif [ "$part_type" != lvm-pv -a -b "$part" ] # $part is not a lvm PV and it exists - then - debug "$fs_id ->Still need to do it: Making the filesystem on a non-pv volume" - infofy "Making $fs_type filesystem on $part" disks - process_filesystem $part $fs_type $fs_create $fs_mountpoint no_mount $fs_opts $fs_label $fs_params && done_filesystems+=("$fs_id") - elif [ "$part_type" = lvm-pv ] && pvdisplay ${fs_params//:/ } >/dev/null # $part is a lvm PV. all needed lvm pv's exist. note that pvdisplay exits 5 as long as one of the args doesn't exist - then - debug "$fs_id ->Still need to do it: Making the filesystem on a pv volume" - infofy "Making $fs_type filesystem on $part" disks - process_filesystem ${part/+/} $fs_type $fs_create $fs_mountpoint no_mount $fs_opts $fs_label $fs_params && done_filesystems+=("$fs_id") - else - debug "$fs_id ->Cannot do right now..." - open_items=1 - fi - fi - fi - done < $TMP_FILESYSTEMS - [ $open_items -eq 0 ] && break - done - [ $open_items -eq 1 ] && show_warning "Filesystem/blockdevice processor problem" "Warning: Could not create all needed filesystems. Either the underlying blockdevices didn't became available in 10 iterations, or process_filesystem failed" - - - - # phase 4: mount all filesystems in the vfs in the correct order. (also swapon where appropriate) - - infofy "Phase 4: Mounting filesystems" disks - sort -t \ -k 6 $TMP_FILESYSTEMS | while read part part_type part_label fs_type fs_create fs_mountpoint fs_mount fs_opts fs_label fs_params - do - if [ "$fs_mountpoint" != no_mountpoint ] - then - infofy "Mounting $part" disks - process_filesystem $part $fs_type no $fs_mountpoint $fs_mount $fs_opts $fs_label $fs_params - elif [ "$fs_type" = swap ] - then - infofy "Swaponning $part" disks - process_filesystem $part $fs_type no $fs_mountpoint $fs_mount $fs_opts $fs_label $fs_params - fi - done - - infofy "Done processing filesystems/blockdevices" disks 1 + if [ $open_items -eq 1 ] + then + warnings="$warnings\nCould not destruct all filesystems/blockdevices. It appears some depending filesystems/blockdevices could not be cleared in 10 iterations" + show_warning "Filesystem/blockdevice processor problem" "Warning: Could not destruct all filesystems/blockdevices. It appears some depending filesystems/blockdevices could not be cleared in 10 iterations" + fi + [ -n "$warnings" ] && show_warning "Rollback problems" "Some problems occurred while rolling back: $warnings.\n Thisk needs to be fixed before retrying disk/filesystem creation or restarting the installer" && return 1 + infofy "Rollback succeeded" disks + return 0 } diff --git a/src/core/libs/lib-ui-interactive.sh b/src/core/libs/lib-ui-interactive.sh index f5df834..1ed844e 100644 --- a/src/core/libs/lib-ui-interactive.sh +++ b/src/core/libs/lib-ui-interactive.sh @@ -163,10 +163,20 @@ interactive_autoprepare() process_disks || die_error "Something went wrong while partitioning" - process_filesystems || die_error "Something went wrong while processing the filesystems" - notify "Auto-prepare was successful" - return 0 - + if ! process_filesystems + then + show_warning "Filesystem processing" "Something went wrong while processing the filesystems. Attempting rollback." + if rollback_filesystems + then + show_warning "Filesystem rollback" "Rollback succeeded. Please try to figure out what went wrong and try me again. If you found a bug in the installer, please report it." + return 1 + else + die_error "Filesystem processing and rollback failed. Please try the installer again. If you found a bug in the installer, please report it." + fi + else + notify "Auto-prepare was successful" + return 0 + fi } @@ -504,7 +514,7 @@ interactive_filesystems() { process_filesystems && notify "Partitions were successfully created." && return 0 - show_warning "Filesystem processing" "Something went wrong while processing the filesystems" + ask_yesno "Seems like some stuff went wrong while processing the filesystems. do you want to rollback? (this cleans up the new mountpoints, filesystems, etc. not doing this can break the next run of the installer unless you clean it up yourself" yes && rollback_filesystems return 1 } diff --git a/unofficial/modules/dieter/procedures/automatic b/unofficial/modules/dieter/procedures/automatic index 3420232..3907fa2 100644 --- a/unofficial/modules/dieter/procedures/automatic +++ b/unofficial/modules/dieter/procedures/automatic @@ -79,7 +79,7 @@ worker_prepare_disks () cryptsetup luksClose sda2_crypt 2>/dev/null dd if=/dev/urandom of=/dev/sda bs=512 count=1 - #TODO: integrate this stuff into the functions in the libs + do error checking and handling + #TODO: integrate this stuff into the functions in the libs (process_partitions and filesystems, rollback and bailout if needed) + do error checking and handling #NOTE: i don't think i should quote to prevent globbing, but it does seem to help i think (hard to check as resource is busy and you can't reload kernel partition tables) sfdisk /dev/sda 2>&1 | grep -v 'not have an msdos signature' << EOF ,10,L,'*' |