diff --git a/pkg/storaged/block/format-dialog.jsx b/pkg/storaged/block/format-dialog.jsx
index 6d72f69a1c55..b575dc6b4def 100644
--- a/pkg/storaged/block/format-dialog.jsx
+++ b/pkg/storaged/block/format-dialog.jsx
@@ -32,7 +32,7 @@ import {
dialog_open,
TextInput, PassInput, CheckBoxes, SelectOne, SizeSlider,
BlockingMessage, TeardownMessage,
- init_active_usage_processes
+ init_teardown_usage
} from "../dialog.jsx";
import { get_fstab_config, is_valid_mount_point } from "../filesystem/utils.jsx";
@@ -630,7 +630,7 @@ function format_dialog_internal(client, path, start, size, enable_dos_extended,
}
},
Inits: [
- init_active_usage_processes(client, usage),
+ init_teardown_usage(client, usage),
unlock_before_format
? init_existing_passphrase(block, true, type => { existing_passphrase_type = type })
: null
diff --git a/pkg/storaged/block/resize.jsx b/pkg/storaged/block/resize.jsx
index 77cf023daf3f..34706c43f52f 100644
--- a/pkg/storaged/block/resize.jsx
+++ b/pkg/storaged/block/resize.jsx
@@ -31,7 +31,7 @@ import {
} from "../crypto/keyslots.jsx";
import {
dialog_open, SizeSlider, BlockingMessage, TeardownMessage, SelectSpaces,
- init_active_usage_processes
+ init_teardown_usage
} from "../dialog.jsx";
import { std_reply } from "../stratis/utils.jsx";
import { pvs_to_spaces } from "../lvm2/utils.jsx";
@@ -534,7 +534,7 @@ export function grow_dialog(client, lvol_or_part, info, to_fit) {
}
},
Inits: [
- init_active_usage_processes(client, usage),
+ init_teardown_usage(client, usage),
passphrase_fields.length
? init_existing_passphrase(block, false, pp => { recovered_passphrase = pp })
: null
@@ -647,7 +647,7 @@ export function shrink_dialog(client, lvol_or_part, info, to_fit) {
}
},
Inits: [
- init_active_usage_processes(client, usage),
+ init_teardown_usage(client, usage),
passphrase_fields.length
? init_existing_passphrase(block, false, pp => { recovered_passphrase = pp })
: null
diff --git a/pkg/storaged/btrfs/subvolume.jsx b/pkg/storaged/btrfs/subvolume.jsx
index b776dae9390a..659e42a95fd7 100644
--- a/pkg/storaged/btrfs/subvolume.jsx
+++ b/pkg/storaged/btrfs/subvolume.jsx
@@ -36,7 +36,7 @@ import { btrfs_usage, validate_subvolume_name, parse_subvol_from_options } from
import { at_boot_input, update_at_boot_input, mounting_dialog, mount_options } from "../filesystem/mounting-dialog.jsx";
import {
dialog_open, TextInput,
- TeardownMessage, init_active_usage_processes,
+ TeardownMessage, init_teardown_usage,
} from "../dialog.jsx";
import { check_mismounted_fsys, MismountAlert } from "../filesystem/mismounting.jsx";
import {
@@ -204,6 +204,7 @@ function subvolume_delete(volume, subvol, mount_point_in_parent, card) {
const paths_to_delete = [];
const usage = [];
+ usage.Teardown = true;
for (const sv of all_subvols) {
const [config, mount_point] = get_fstab_config_with_client(client, block, false, sv);
const fs_is_mounted = is_mounted(client, block, sv);
@@ -241,7 +242,7 @@ function subvolume_delete(volume, subvol, mount_point_in_parent, card) {
}
},
Inits: [
- init_active_usage_processes(client, usage)
+ init_teardown_usage(client, usage)
]
});
}
diff --git a/pkg/storaged/dialog.jsx b/pkg/storaged/dialog.jsx
index fe5f64f1390c..8dc6d87d5f02 100644
--- a/pkg/storaged/dialog.jsx
+++ b/pkg/storaged/dialog.jsx
@@ -240,10 +240,16 @@ import { show_modal_dialog, apply_modal_dialog } from "cockpit-components-dialog
import { ListingTable } from "cockpit-components-table.jsx";
import { FormHelper } from "cockpit-components-form-helper";
-import { fmt_size, block_name, format_size_and_text, format_delay, for_each_async } from "./utils.js";
+import {
+ decode_filename, fmt_size, block_name, format_size_and_text, format_delay, for_each_async,
+ is_available_block
+} from "./utils.js";
import { fmt_to_fragments } from "utils.jsx";
+
import client from "./client.js";
+import fsys_is_empty_sh from "./fsys-is-empty.sh";
+
const _ = cockpit.gettext;
function make_rows(fields, values, errors, onChange) {
@@ -328,6 +334,23 @@ const Body = ({ body, teardown, fields, values, errors, isFormHorizontal, onChan
);
};
+const ExtraConfirmation = ({ title, text, confirm_text, onChange }) => {
+ const [confirmed, setConfirmed] = useState(false);
+
+ return (
+
+ {text}
+ {
+ setConfirmed(val);
+ onChange(val);
+ }} />
+ );
+};
+
function flatten_fields(fields) {
return fields.reduce(
(acc, val) => acc.concat([val]).concat(val.options && val.options.nested_fields
@@ -340,6 +363,8 @@ export const dialog_open = (def) => {
const nested_fields = def.Fields || [];
const fields = flatten_fields(nested_fields);
const values = { };
+ let confirmation = null;
+ let confirmed = false;
let errors = null;
fields.forEach(f => { values[f.tag] = f.initial_value });
@@ -415,8 +440,10 @@ export const dialog_open = (def) => {
caption: variant.Title,
style: actions.length == 0 ? "primary" : "secondary",
danger: def.Action.Danger || def.Action.DangerButton,
- disabled: running_promise != null || (def.Action.disable_on_error &&
- errors && errors.toString() != "[object Object]"),
+ disabled: (running_promise != null ||
+ (def.Action.disable_on_error &&
+ errors && errors.toString() != "[object Object]") ||
+ (confirmation && !confirmed)),
clicked: progress_callback => run_action(progress_callback, variant.tag),
});
}
@@ -436,13 +463,21 @@ export const dialog_open = (def) => {
}
}
- const extra = (
-
- { def.Action && def.Action.Danger
- ? {def.Action.Danger}
- : null
- }
-
);
+ let extra = null;
+ if (confirmation) {
+ extra = {
+ confirmed = val;
+ update_footer();
+ }} />;
+ } else if (def.Action && def.Action.Danger) {
+ extra = (
+
+ {def.Action.Danger}
+
);
+ }
return {
idle_message: (running_promise
@@ -537,6 +572,12 @@ export const dialog_open = (def) => {
update();
},
+ need_confirmation: (conf) => {
+ confirmation = conf;
+ confirmed = false;
+ update_footer();
+ },
+
close: () => {
dlg.footerProps.dialog_done();
}
@@ -1207,13 +1248,14 @@ const teardown_block_name = use => {
};
export const TeardownMessage = (usage, expect_single_unmount) => {
- if (usage.length == 0)
+ if (!usage.Teardown)
return null;
if (is_expected_unmount(usage, expect_single_unmount))
return ;
const rows = [];
+ let have_data = false;
usage.forEach((use, index) => {
if (use.block) {
const name = teardown_block_name(use);
@@ -1223,12 +1265,22 @@ export const TeardownMessage = (usage, expect_single_unmount) => {
if (location === false)
location = _("(Not part of target)");
}
+ if (use.data_warning)
+ have_data = true;
rows.push({
columns: [name,
location || "-",
use.actions.length ? use.actions.join(", ") : "-",
{
- title: ,
+ title: <>
+
+ { use.data_warning &&
+
+ { "\n" }
+ { use.data_warning }
+
+ }
+ >,
props: { className: "pf-v5-u-text-align-right" }
}
]
@@ -1247,6 +1299,11 @@ export const TeardownMessage = (usage, expect_single_unmount) => {
{ title: "" }
]}
rows={rows} />
+ { have_data &&
+ <>
+
+ >
+ }
);
};
@@ -1268,24 +1325,46 @@ export function teardown_danger_message(usage, expect_single_unmount) {
}
}
-export function init_active_usage_processes(client, usage, expect_single_unmount) {
+export function init_teardown_usage(client, usage, expect_single_unmount) {
return {
- title: _("Checking related processes"),
- func: dlg => {
- return for_each_async(usage, u => {
+ title: _("Checking filesystem usage"),
+ func: async function (dlg) {
+ let have_data = false;
+ for (const u of usage) {
if (u.usage == "mounted") {
- return client.find_mount_users(u.location)
- .then(users => {
- u.users = users;
- });
- } else
- return Promise.resolve();
- }).then(() => {
- dlg.set_attribute("Teardown", TeardownMessage(usage, expect_single_unmount));
- const msg = teardown_danger_message(usage, expect_single_unmount);
- if (msg)
- dlg.add_danger(msg);
- });
+ u.users = await client.find_mount_users(u.location);
+ }
+ if (client.in_anaconda_mode() && !expect_single_unmount && u.block) {
+ if (u.block.IdUsage == "filesystem") {
+ const empty = await cockpit.script(fsys_is_empty_sh,
+ [decode_filename(u.block.PreferredDevice)],
+ { superuser: true, err: "message" });
+ if (empty.trim() != "yes")
+ u.data_warning = _("Filesystem is not empty");
+ } else if (u.block.IdUsage == "crypto" && !client.blocks_cleartext[u.block.path]) {
+ u.data_warning = _("Locked encrypted device might contain data");
+ } else if (!client.blocks_ptable[u.block.path] &&
+ u.block.IdUsage != "raid" &&
+ !is_available_block(client, u.block)) {
+ u.data_warning = _("Device contains unrecognized data");
+ }
+ if (u.data_warning)
+ have_data = true;
+ }
+ }
+
+ if (have_data) {
+ usage.Teardown = true;
+ dlg.need_confirmation({
+ Title: _("Important data might be deleted."),
+ Text: _("The device that you are about to erase or delete might contain important data. Please confirm that you really want to delete or erase this device."),
+ ConfirmText: _("Yes, delete my data."),
+ });
+ }
+ dlg.set_attribute("Teardown", TeardownMessage(usage, expect_single_unmount));
+ const msg = teardown_danger_message(usage, expect_single_unmount);
+ if (msg)
+ dlg.add_danger(msg);
}
};
}
diff --git a/pkg/storaged/filesystem/mounting-dialog.jsx b/pkg/storaged/filesystem/mounting-dialog.jsx
index bb21343a43d9..b7e033896ad3 100644
--- a/pkg/storaged/filesystem/mounting-dialog.jsx
+++ b/pkg/storaged/filesystem/mounting-dialog.jsx
@@ -36,7 +36,7 @@ import {
dialog_open,
TextInput, PassInput, CheckBoxes, SelectOne,
TeardownMessage,
- init_active_usage_processes
+ init_teardown_usage
} from "../dialog.jsx";
import { init_existing_passphrase, unlock_with_type } from "../crypto/keyslots.jsx";
import { initial_tab_options } from "../block/format-dialog.jsx";
@@ -447,7 +447,7 @@ export function mounting_dialog(client, block, mode, forced_options, subvol) {
}
},
Inits: [
- init_active_usage_processes(client, usage, old_dir),
+ init_teardown_usage(client, usage, old_dir),
init_existing_passphrase(block, true, type => {
passphrase_type = type;
update_explicit_passphrase(dlg.get_value("mount_options")?.ro ?? opt_ro);
diff --git a/pkg/storaged/fsys-is-empty.sh b/pkg/storaged/fsys-is-empty.sh
new file mode 100644
index 000000000000..505b4841b2a6
--- /dev/null
+++ b/pkg/storaged/fsys-is-empty.sh
@@ -0,0 +1,28 @@
+#! /bin/bash
+
+set -eux
+
+dev=$1
+
+need_unmount=""
+mp=$(findmnt -no TARGET "$dev" | cat)
+if [ -z "$mp" ]; then
+ mp=$(mktemp -d)
+ need_unmount=$mp
+ mount "$dev" "$mp" -o ro
+fi
+
+# A filesystem is empty if it only has directories in it.
+
+first=$(find "$mp" -not -type d | head -1)
+
+if [ -n "$need_unmount" ]; then
+ umount "$need_unmount"
+ rmdir "$need_unmount"
+fi
+
+if [ -z "$first" ]; then
+ echo yes
+else
+ echo no
+fi
diff --git a/pkg/storaged/legacy-vdo/legacy-vdo.jsx b/pkg/storaged/legacy-vdo/legacy-vdo.jsx
index 198c3904295f..27b15552a823 100644
--- a/pkg/storaged/legacy-vdo/legacy-vdo.jsx
+++ b/pkg/storaged/legacy-vdo/legacy-vdo.jsx
@@ -27,7 +27,7 @@ import { DescriptionList, DescriptionListDescription, DescriptionListGroup, Desc
import { block_short_name, get_active_usage, teardown_active_usage, fmt_size, decode_filename, reload_systemd } from "../utils.js";
import {
- dialog_open, SizeSlider, BlockingMessage, TeardownMessage, init_active_usage_processes
+ dialog_open, SizeSlider, BlockingMessage, TeardownMessage, init_teardown_usage
} from "../dialog.jsx";
import { StorageButton, StorageOnOff } from "../storage-controls.jsx";
@@ -68,7 +68,7 @@ export function make_legacy_vdo_page(parent, vdo, backing_block, next_card) {
}
},
Inits: [
- init_active_usage_processes(client, usage)
+ init_teardown_usage(client, usage)
]
});
} else {
@@ -130,7 +130,7 @@ export function make_legacy_vdo_page(parent, vdo, backing_block, next_card) {
}
},
Inits: [
- init_active_usage_processes(client, usage)
+ init_teardown_usage(client, usage)
]
});
}
diff --git a/pkg/storaged/lvm2/block-logical-volume.jsx b/pkg/storaged/lvm2/block-logical-volume.jsx
index 2e386df20bfb..6e576c8239f7 100644
--- a/pkg/storaged/lvm2/block-logical-volume.jsx
+++ b/pkg/storaged/lvm2/block-logical-volume.jsx
@@ -34,7 +34,7 @@ import { StorageCard, StorageDescription, new_card, navigate_to_new_card_locatio
import { block_name, fmt_size, get_active_usage, teardown_active_usage, reload_systemd } from "../utils.js";
import {
dialog_open, TextInput, SelectSpaces, BlockingMessage, TeardownMessage,
- init_active_usage_processes
+ init_teardown_usage
} from "../dialog.jsx";
import { lvm2_create_snapshot_action } from "./volume-group.jsx";
@@ -85,7 +85,7 @@ export function lvol_delete(lvol, card) {
}
},
Inits: [
- init_active_usage_processes(client, usage)
+ init_teardown_usage(client, usage)
]
});
}
@@ -156,7 +156,7 @@ function deactivate(lvol, block) {
dialog_open({
Title: cockpit.format(_("Deactivate logical volume $0/$1?"), vgroup.Name, lvol.Name),
- Teardown: TeardownMessage(usage),
+ Teardown: TeardownMessage(usage, true),
Action: {
Title: _("Deactivate"),
action: async function () {
@@ -166,7 +166,7 @@ function deactivate(lvol, block) {
}
},
Inits: [
- init_active_usage_processes(client, usage)
+ init_teardown_usage(client, usage, true)
]
});
}
diff --git a/pkg/storaged/lvm2/volume-group.jsx b/pkg/storaged/lvm2/volume-group.jsx
index a8f6e7c52788..4f40a325ca19 100644
--- a/pkg/storaged/lvm2/volume-group.jsx
+++ b/pkg/storaged/lvm2/volume-group.jsx
@@ -44,7 +44,7 @@ import {
import {
dialog_open, SelectSpaces, TextInput,
BlockingMessage, TeardownMessage,
- init_active_usage_processes
+ init_teardown_usage
} from "../dialog.jsx";
import { create_logical_volume } from "./create-logical-volume-dialog.jsx";
@@ -104,7 +104,7 @@ function vgroup_delete(client, vgroup, card) {
}
},
Inits: [
- init_active_usage_processes(client, usage)
+ init_teardown_usage(client, usage)
]
});
}
@@ -328,8 +328,10 @@ const LVM2VolumeGroupCard = ({ card, vgroup }) => {
a bit inconsistent, but *shrug*.
*/
- let usage = get_active_usage(client, vgroup.path, _("delete"));
- usage = usage.filter(u => u.block && is_partial_linear_lvol(u.block));
+ const all_usage = get_active_usage(client, vgroup.path, _("delete"));
+ const usage = all_usage.filter(u => u.block && is_partial_linear_lvol(u.block));
+ usage.Blocking = all_usage.Blocking;
+ usage.Teardown = all_usage.Teardown;
if (usage.Blocking) {
dialog_open({
@@ -359,7 +361,7 @@ const LVM2VolumeGroupCard = ({ card, vgroup }) => {
}
},
Inits: [
- init_active_usage_processes(client, usage)
+ init_teardown_usage(client, usage)
]
});
}
diff --git a/pkg/storaged/mdraid/mdraid.jsx b/pkg/storaged/mdraid/mdraid.jsx
index 880ab76f1097..3fcda5afcade 100644
--- a/pkg/storaged/mdraid/mdraid.jsx
+++ b/pkg/storaged/mdraid/mdraid.jsx
@@ -43,7 +43,7 @@ import {
import {
dialog_open, SelectSpaces,
BlockingMessage, TeardownMessage,
- init_active_usage_processes
+ init_teardown_usage
} from "../dialog.jsx";
import { partitionable_block_actions } from "../partitions/actions.jsx";
@@ -81,7 +81,7 @@ function mdraid_stop(mdraid) {
}
},
Inits: [
- init_active_usage_processes(client, usage)
+ init_teardown_usage(client, usage)
]
});
return;
@@ -132,7 +132,7 @@ function mdraid_delete(mdraid, block, card) {
}
},
Inits: [
- init_active_usage_processes(client, usage)
+ init_teardown_usage(client, usage)
]
});
}
diff --git a/pkg/storaged/partitions/format-disk-dialog.jsx b/pkg/storaged/partitions/format-disk-dialog.jsx
index f1dede36d3bb..97e65f191847 100644
--- a/pkg/storaged/partitions/format-disk-dialog.jsx
+++ b/pkg/storaged/partitions/format-disk-dialog.jsx
@@ -24,7 +24,7 @@ import {
dialog_open,
SelectOne, CheckBoxes,
BlockingMessage, TeardownMessage,
- init_active_usage_processes
+ init_teardown_usage
} from "../dialog.jsx";
import { get_active_usage, block_name, teardown_active_usage, reload_systemd } from "../utils.js";
import { job_progress_wrapper } from "../jobs-panel.jsx";
@@ -84,7 +84,7 @@ export function format_disk(block) {
}
},
Inits: [
- init_active_usage_processes(client, usage)
+ init_teardown_usage(client, usage)
]
});
}
diff --git a/pkg/storaged/partitions/partition.jsx b/pkg/storaged/partitions/partition.jsx
index ec8a8e9806e7..d3783484331d 100644
--- a/pkg/storaged/partitions/partition.jsx
+++ b/pkg/storaged/partitions/partition.jsx
@@ -29,7 +29,7 @@ import { StorageButton, StorageLink } from "../storage-controls.jsx";
import {
dialog_open,
SelectOne, TextInput,
- init_active_usage_processes, BlockingMessage, TeardownMessage
+ init_teardown_usage, BlockingMessage, TeardownMessage
} from "../dialog.jsx";
import { block_name, fmt_size, get_active_usage, teardown_active_usage, reload_systemd } from "../utils.js";
import { check_unused_space, get_resize_info, free_space_after_part, grow_dialog, shrink_dialog } from "../block/resize.jsx";
@@ -64,7 +64,7 @@ export function delete_partition(block, card) {
}
},
Inits: [
- init_active_usage_processes(client, usage)
+ init_teardown_usage(client, usage)
]
});
}
diff --git a/pkg/storaged/stratis/filesystem.jsx b/pkg/storaged/stratis/filesystem.jsx
index d5b7cae73176..05dbb99368f4 100644
--- a/pkg/storaged/stratis/filesystem.jsx
+++ b/pkg/storaged/stratis/filesystem.jsx
@@ -26,7 +26,7 @@ import { DescriptionList } from "@patternfly/react-core/dist/esm/components/Desc
import {
dialog_open, TextInput, BlockingMessage, TeardownMessage,
- init_active_usage_processes,
+ init_teardown_usage,
} from "../dialog.jsx";
import { StorageUsageBar, StorageLink } from "../storage-controls.jsx";
import {
@@ -142,7 +142,7 @@ export function make_stratis_filesystem_page(parent, pool, fsys,
}
},
Inits: [
- init_active_usage_processes(client, usage)
+ init_teardown_usage(client, usage)
]
});
}
diff --git a/pkg/storaged/stratis/pool.jsx b/pkg/storaged/stratis/pool.jsx
index ca1e011cea88..883a6eb54001 100644
--- a/pkg/storaged/stratis/pool.jsx
+++ b/pkg/storaged/stratis/pool.jsx
@@ -45,7 +45,7 @@ import {
import {
dialog_open, SelectSpaces, TextInput, PassInput, SelectOne, SizeSlider,
BlockingMessage, TeardownMessage,
- init_active_usage_processes
+ init_teardown_usage
} from "../dialog.jsx";
import { validate_url, get_tang_adv } from "../crypto/tang.jsx";
@@ -154,7 +154,7 @@ function delete_pool(pool, card) {
}
},
Inits: [
- init_active_usage_processes(client, usage)
+ init_teardown_usage(client, usage)
]
});
}
diff --git a/pkg/storaged/utils.js b/pkg/storaged/utils.js
index f09a444f257d..0bfe8740e410 100644
--- a/pkg/storaged/utils.js
+++ b/pkg/storaged/utils.js
@@ -690,7 +690,7 @@ export function should_ignore(client, path) {
GET_CHILDREN_FOR_TEARDOWN is similar but doesn't consider things
like volume groups to be children of their physical volumes. This
is appropriate for teardown processing, where tearing down a
- physical volume does not imply tearing down the whole volume groups
+ physical volume does not imply tearing down the whole volume group
with everything that it contains.
*/
@@ -978,15 +978,15 @@ export function get_active_usage(client, path, top_action, child_action, is_temp
return usage;
}
- let usage = [];
+ const usage = [];
get_usage(usage, path, 0);
- if (usage.length == 1 && usage[0].level == 0 && usage[0].usage == "none")
- usage = [];
-
usage.Blocking = usage.some(u => u.blocking);
usage.Teardown = usage.some(u => !u.blocking);
+ if (usage.length == 1 && usage[0].level == 0 && usage[0].usage == "none")
+ usage.Teardown = false;
+
return usage;
}
diff --git a/test/reference b/test/reference
index e11eafdd5c2e..612b0904a905 160000
--- a/test/reference
+++ b/test/reference
@@ -1 +1 @@
-Subproject commit e11eafdd5c2e1dcbb1d86fbbce85697c41b06d55
+Subproject commit 612b0904a905e7a8d67778f63601e14d38ac2086
diff --git a/test/verify/check-storage-anaconda b/test/verify/check-storage-anaconda
index bd63558b1448..6f5a34389999 100755
--- a/test/verify/check-storage-anaconda
+++ b/test/verify/check-storage-anaconda
@@ -549,6 +549,83 @@ class TestStorageAnaconda(storagelib.StorageCase):
b.click(self.card_desc("MDRAID disk", "MDRAID device") + " button")
b.wait_in_text("body", "Not found")
+ def testNonEmpty(self):
+ b = self.browser
+ m = self.machine
+
+ disk = self.add_loopback_disk(name="loop10")
+
+ anaconda_config = {
+ "mount_point_prefix": "/sysroot",
+ "available_devices": [disk],
+ }
+
+ # Create some content on the disk
+ m.execute(f"echo einszweidrei | cryptsetup luksFormat --pbkdf-memory 32768 {disk}")
+ m.execute(f"echo einszweidrei | cryptsetup luksOpen {disk} dm-test")
+ m.execute("mkfs.ext4 /dev/mapper/dm-test; mount /dev/mapper/dm-test /mnt; echo Hi >/mnt/hello; umount /mnt")
+ m.execute("cryptsetup close dm-test")
+
+ self.login_and_go("/storage")
+ self.enterAnacondaMode(anaconda_config)
+
+ # Attempt to wipe it. This requires a extra confirmation
+ # because it is locked.
+ b.wait_text(self.card_row_col("Storage", 1, 3), "Locked data (encrypted)")
+ self.click_dropdown(self.card_row("Storage", 1), "Create partition table")
+ self.dialog_wait_open()
+ self.dialog_set_val("type", "empty")
+ b.wait_in_text("#dialog", "Locked encrypted device might contain data")
+ self.dialog_wait_apply_disabled()
+ b.assert_pixels('#dialog', "wipe")
+ b.set_checked("#dialog-confirm", val=True)
+ self.dialog_wait_apply_enabled()
+ self.dialog_cancel()
+ self.dialog_wait_close()
+
+ # Unlock and confirm the extra warning, and actually wipe it
+ self.click_dropdown(self.card_row("Storage", 1), "Unlock")
+ self.dialog({"passphrase": "einszweidrei"})
+ b.wait_text(self.card_row_col("Storage", 1, 3), "ext4 filesystem (encrypted)")
+ self.click_dropdown(self.card_row("Storage", 1), "Create partition table")
+ self.dialog_wait_open()
+ self.dialog_set_val("type", "empty")
+ b.wait_in_text("#dialog", "Filesystem is not empty")
+ b.set_checked("#dialog-confirm", val=True)
+ self.dialog_wait_apply_enabled()
+ self.dialog_apply()
+ self.dialog_wait_close()
+
+ # Put some unrecognized data on it
+
+ # This is the superblock of a legacy VDO device. Cockpit does
+ # not recognize it.
+
+ data = """
+ZG12ZG8wMDEFAAAABAAAAAAAAABdAAAAAAAAAJQJAgCGsH0mrQgGAC4WnB4G50Fzu20jY6J1rfwA
+AAAAAQAAAAAAAAABAAAA2FwKAAAAAAAA////AAAAAAA7tw9zAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+"""
+ m.execute(f"base64 -d >{disk}", input=data)
+ # Wait for udev to settle and re-trigger, udisks sometimes misses udev events on ubuntu 2204.
+ m.execute(f"udevadm settle; udevadm trigger {disk}")
+
+ b.wait_text(self.card_row_col("Storage", 1, 3), "Unrecognized data")
+ self.click_dropdown(self.card_row("Storage", 1), "Create partition table")
+ self.dialog_wait_open()
+ self.dialog_set_val("type", "empty")
+ b.wait_in_text("#dialog", "Device contains unrecognized data")
+ b.set_checked("#dialog-confirm", val=True)
+ self.dialog_wait_apply_enabled()
+ self.dialog_apply()
+ self.dialog_wait_close()
+
if __name__ == '__main__':
testlib.test_main()
diff --git a/test/verify/check-storage-unrecognized b/test/verify/check-storage-unrecognized
index 2deec8306894..71799fb5befb 100755
--- a/test/verify/check-storage-unrecognized
+++ b/test/verify/check-storage-unrecognized
@@ -53,7 +53,7 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
"""
m.execute(f"base64 -d >{disk}", input=data)
# Wait for udev to settle and re-trigger, udisks sometimes misses udev events on ubuntu 2204.
- m.execute("udevadm settle; udevadm trigger /dev/sda")
+ m.execute(f"udevadm settle; udevadm trigger {disk}")
b.wait_text(self.card_desc("Unrecognized data", "Usage"), "other")
b.wait_text(self.card_desc("Unrecognized data", "Type"), "vdo")