From 2618d8fbaa66151d2396e2973b102ec2adbaba5b Mon Sep 17 00:00:00 2001 From: Marius Vollmer Date: Fri, 5 Apr 2024 13:58:30 +0300 Subject: [PATCH 01/15] storage: Move all actions into the menu, except primary ones And make "Mount" and "Create new logical volume" primary actions. --- pkg/storaged/filesystem/filesystem.jsx | 13 ++++++++++--- pkg/storaged/lvm2/volume-group.jsx | 1 + pkg/storaged/pages.jsx | 12 ++++++------ 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/pkg/storaged/filesystem/filesystem.jsx b/pkg/storaged/filesystem/filesystem.jsx index cfde81bc7074..f2991cf874e6 100644 --- a/pkg/storaged/filesystem/filesystem.jsx +++ b/pkg/storaged/filesystem/filesystem.jsx @@ -98,9 +98,16 @@ export function make_filesystem_card(next, backing_block, content_block, fstab_c actions: [ client.in_anaconda_mode() && { title: _("Edit mount point"), action: () => edit_mount_point(content_block || backing_block) }, - content_block && mounted - ? { title: _("Unmount"), action: () => mounting_dialog(client, content_block, "unmount") } - : { title: _("Mount"), action: () => mounting_dialog(client, content_block || backing_block, "mount") }, + (content_block && mounted) + ? { + title: _("Unmount"), + action: () => mounting_dialog(client, content_block, "unmount"), + } + : { + title: _("Mount"), + primary: true, + action: () => mounting_dialog(client, content_block || backing_block, "mount"), + }, std_format_action(backing_block, content_block), ] }); diff --git a/pkg/storaged/lvm2/volume-group.jsx b/pkg/storaged/lvm2/volume-group.jsx index 8cb0a01971c3..d2c348991f0f 100644 --- a/pkg/storaged/lvm2/volume-group.jsx +++ b/pkg/storaged/lvm2/volume-group.jsx @@ -262,6 +262,7 @@ export function make_lvm2_volume_group_page(parent, vgroup) { actions: [ { title: _("Create new logical volume"), + primary: true, action: () => create_logical_volume(client, vgroup), excuse: lvol_excuse, tag: "group", diff --git a/pkg/storaged/pages.jsx b/pkg/storaged/pages.jsx index 07c04622ee1b..e206b97c3684 100644 --- a/pkg/storaged/pages.jsx +++ b/pkg/storaged/pages.jsx @@ -359,17 +359,17 @@ const ActionButtons = ({ card }) => { function for_menu(action) { // Determine whether a action should get a button or be in the - // menu + // menu. // In a narrow layout, everything goes to the menu if (narrow) return true; - // Everything that is dangerous goes to the menu - if (action.danger) - return true; + // Only primary actions are buttons (even dangerous ones) + if (action.primary) + return false; - return false; + return true; } const buttons = []; @@ -384,7 +384,7 @@ const ActionButtons = ({ card }) => { else buttons.push( a.action(false)} - kind={a.danger ? "danger" : null} excuse={a.excuse}> + kind={a.danger ? "danger" : a.primary ? "primary" : null} excuse={a.excuse}> {a.title} ); } From 804b79b319ef0125fce50b2e7d512efea8fe313f Mon Sep 17 00:00:00 2001 From: Marius Vollmer Date: Wed, 28 Aug 2024 11:01:08 +0300 Subject: [PATCH 02/15] storage: Move "Format" action one card up Offer it on the "Partition" card instead of the "Filesystem" card, for example. This makes more sense. One formats a partition, but mounts the filesystem. --- pkg/storaged/block/actions.jsx | 31 +++++++++++++++---- .../format-disk-dialog.jsx | 0 pkg/storaged/block/other.jsx | 2 +- pkg/storaged/block/unformatted-data.jsx | 2 -- pkg/storaged/block/unrecognized-data.jsx | 2 -- pkg/storaged/btrfs/device.jsx | 2 -- pkg/storaged/crypto/locked-encrypted-data.jsx | 2 -- pkg/storaged/drive/drive.jsx | 4 +-- pkg/storaged/filesystem/filesystem.jsx | 2 -- pkg/storaged/legacy-vdo/legacy-vdo.jsx | 2 ++ pkg/storaged/lvm2/block-logical-volume.jsx | 2 ++ pkg/storaged/lvm2/physical-volume.jsx | 2 -- pkg/storaged/mdraid/mdraid-disk.jsx | 2 -- pkg/storaged/mdraid/mdraid.jsx | 4 +-- pkg/storaged/partitions/partition.jsx | 2 ++ pkg/storaged/stratis/blockdev.jsx | 2 -- pkg/storaged/swap/swap.jsx | 2 -- 17 files changed, 36 insertions(+), 29 deletions(-) rename pkg/storaged/{partitions => block}/format-disk-dialog.jsx (100%) diff --git a/pkg/storaged/block/actions.jsx b/pkg/storaged/block/actions.jsx index 535e8d5e3516..c649fd17d25c 100644 --- a/pkg/storaged/block/actions.jsx +++ b/pkg/storaged/block/actions.jsx @@ -20,17 +20,36 @@ import cockpit from "cockpit"; import client from "../client"; +import { format_disk } from "./format-disk-dialog.jsx"; import { format_dialog } from "./format-dialog.jsx"; const _ = cockpit.gettext; -export function std_format_action(backing_block, content_block) { - const excuse = backing_block.ReadOnly ? _("Device is read-only") : null; +export function block_actions(block, partitionable) { + if (!block || block.Size === 0) + return []; - return { + const excuse = block.ReadOnly ? _("Device is read-only") : null; + const actions = []; + + if (partitionable) + actions.push({ + title: _("Create partition table"), + action: () => format_disk(block), + danger: true, + excuse, + }); + + actions.push({ title: _("Format"), - action: () => format_dialog(client, backing_block.path), + action: () => format_dialog(client, block.path), + danger: true, excuse, - danger: true - }; + }); + + return actions; +} + +export function partitionable_block_actions(block) { + return block_actions(block, true); } diff --git a/pkg/storaged/partitions/format-disk-dialog.jsx b/pkg/storaged/block/format-disk-dialog.jsx similarity index 100% rename from pkg/storaged/partitions/format-disk-dialog.jsx rename to pkg/storaged/block/format-disk-dialog.jsx diff --git a/pkg/storaged/block/other.jsx b/pkg/storaged/block/other.jsx index ccb5de224908..c0fd771d3275 100644 --- a/pkg/storaged/block/other.jsx +++ b/pkg/storaged/block/other.jsx @@ -26,7 +26,7 @@ import { CardBody } from "@patternfly/react-core/dist/esm/components/Card/index. import { StorageCard, StorageDescription, new_card } from "../pages.jsx"; import { block_name, should_ignore } from "../utils.js"; -import { partitionable_block_actions } from "../partitions/actions.jsx"; +import { partitionable_block_actions } from "./actions.jsx"; import { OtherIcon } from "../icons/gnome-icons.jsx"; import { make_block_page } from "../block/create-pages.jsx"; diff --git a/pkg/storaged/block/unformatted-data.jsx b/pkg/storaged/block/unformatted-data.jsx index 98f6800799f3..92cf7067d58e 100644 --- a/pkg/storaged/block/unformatted-data.jsx +++ b/pkg/storaged/block/unformatted-data.jsx @@ -20,7 +20,6 @@ import cockpit from "cockpit"; import { StorageCard, new_card } from "../pages.jsx"; -import { std_format_action } from "./actions.jsx"; import { std_lock_action } from "../crypto/actions.jsx"; const _ = cockpit.gettext; @@ -32,7 +31,6 @@ export function make_unformatted_data_card(next, backing_block, content_block) { component: StorageCard, actions: [ std_lock_action(backing_block, content_block), - std_format_action(backing_block, content_block), ] }); } diff --git a/pkg/storaged/block/unrecognized-data.jsx b/pkg/storaged/block/unrecognized-data.jsx index 91f723c8c5c0..1c8fa610cb76 100644 --- a/pkg/storaged/block/unrecognized-data.jsx +++ b/pkg/storaged/block/unrecognized-data.jsx @@ -24,7 +24,6 @@ import { CardBody } from "@patternfly/react-core/dist/esm/components/Card/index. import { DescriptionList } from "@patternfly/react-core/dist/esm/components/DescriptionList/index.js"; import { StorageCard, StorageDescription, new_card } from "../pages.jsx"; -import { std_format_action } from "./actions.jsx"; import { std_lock_action } from "../crypto/actions.jsx"; const _ = cockpit.gettext; @@ -37,7 +36,6 @@ export function make_unrecognized_data_card(next, backing_block, content_block) props: { backing_block, content_block }, actions: [ std_lock_action(backing_block, content_block), - std_format_action(backing_block, content_block), ] }); } diff --git a/pkg/storaged/btrfs/device.jsx b/pkg/storaged/btrfs/device.jsx index 9032106306b9..68ecb43850b5 100644 --- a/pkg/storaged/btrfs/device.jsx +++ b/pkg/storaged/btrfs/device.jsx @@ -28,7 +28,6 @@ import { DescriptionList } from "@patternfly/react-core/dist/esm/components/Desc import { StorageCard, StorageDescription, new_card, register_crossref } from "../pages.jsx"; import { StorageUsageBar } from "../storage-controls.jsx"; import { std_lock_action } from "../crypto/actions.jsx"; -import { std_format_action } from "../block/actions.jsx"; import { btrfs_device_usage } from "./utils.jsx"; const _ = cockpit.gettext; @@ -90,7 +89,6 @@ export function btrfs_device_actions(backing_block, content_block) { if (backing_block && content_block) return [ std_lock_action(backing_block, content_block), - std_format_action(backing_block, content_block), ]; else return []; diff --git a/pkg/storaged/crypto/locked-encrypted-data.jsx b/pkg/storaged/crypto/locked-encrypted-data.jsx index c8ca59e789e2..938db26554eb 100644 --- a/pkg/storaged/crypto/locked-encrypted-data.jsx +++ b/pkg/storaged/crypto/locked-encrypted-data.jsx @@ -20,7 +20,6 @@ import cockpit from "cockpit"; import { StorageCard, new_card } from "../pages.jsx"; -import { std_format_action } from "../block/actions.jsx"; import { unlock } from "./actions.jsx"; const _ = cockpit.gettext; @@ -34,7 +33,6 @@ export function make_locked_encrypted_data_card(next, block) { props: { block }, actions: [ { title: _("Unlock"), action: () => unlock(block) }, - std_format_action(block, null), ] }); } diff --git a/pkg/storaged/drive/drive.jsx b/pkg/storaged/drive/drive.jsx index 5d4e98e66617..1051428bf99b 100644 --- a/pkg/storaged/drive/drive.jsx +++ b/pkg/storaged/drive/drive.jsx @@ -29,7 +29,7 @@ import { HDDIcon, SSDIcon, MediaDriveIcon } from "../icons/gnome-icons.jsx"; import { StorageCard, StorageDescription, new_card, new_page } from "../pages.jsx"; import { block_name, drive_name, format_temperature, fmt_size_long, should_ignore } from "../utils.js"; import { make_block_page } from "../block/create-pages.jsx"; -import { partitionable_block_actions } from "../partitions/actions.jsx"; +import { partitionable_block_actions } from "../block/actions.jsx"; const _ = cockpit.gettext; @@ -81,7 +81,7 @@ export function make_drive_page(parent, drive) { job_path: drive.path, component: DriveCard, props: { drive }, - actions: block.Size > 0 ? partitionable_block_actions(block) : [], + actions: partitionable_block_actions(block), }); if (block.Size > 0) { diff --git a/pkg/storaged/filesystem/filesystem.jsx b/pkg/storaged/filesystem/filesystem.jsx index f2991cf874e6..f81842115977 100644 --- a/pkg/storaged/filesystem/filesystem.jsx +++ b/pkg/storaged/filesystem/filesystem.jsx @@ -34,7 +34,6 @@ import { import { StorageLink, StorageUsageBar, StorageSize } from "../storage-controls.jsx"; import { StorageCard, StorageDescription, new_card, useIsNarrow } from "../pages.jsx"; -import { std_format_action } from "../block/actions.jsx"; import { is_mounted, MountPoint, mount_point_text, edit_mount_point } from "./utils.jsx"; import { mounting_dialog } from "./mounting-dialog.jsx"; import { check_mismounted_fsys, MismountAlert } from "./mismounting.jsx"; @@ -108,7 +107,6 @@ export function make_filesystem_card(next, backing_block, content_block, fstab_c primary: true, action: () => mounting_dialog(client, content_block || backing_block, "mount"), }, - std_format_action(backing_block, content_block), ] }); } diff --git a/pkg/storaged/legacy-vdo/legacy-vdo.jsx b/pkg/storaged/legacy-vdo/legacy-vdo.jsx index 432cfb8a23d1..546c43466aab 100644 --- a/pkg/storaged/legacy-vdo/legacy-vdo.jsx +++ b/pkg/storaged/legacy-vdo/legacy-vdo.jsx @@ -33,6 +33,7 @@ import { StorageButton, StorageOnOff } from "../storage-controls.jsx"; import { StorageCard, new_page, new_card } from "../pages.jsx"; import { make_block_page } from "../block/create-pages.jsx"; +import { block_actions } from "../block/actions.jsx"; import inotify_py from "inotify.py"; import vdo_monitor_py from "./vdo-monitor.py"; @@ -149,6 +150,7 @@ export function make_legacy_vdo_page(parent, vdo, backing_block, next_card) { ? { title: _("Stop"), action: stop } : { title: _("Start"), action: () => vdo.start() } ), + ...block_actions(block), { title: _("Delete"), action: delete_, danger: true } ], }); diff --git a/pkg/storaged/lvm2/block-logical-volume.jsx b/pkg/storaged/lvm2/block-logical-volume.jsx index 8989bc30a89d..4215dd160a7c 100644 --- a/pkg/storaged/lvm2/block-logical-volume.jsx +++ b/pkg/storaged/lvm2/block-logical-volume.jsx @@ -30,6 +30,7 @@ import { Flex, FlexItem } from "@patternfly/react-core/dist/esm/layouts/Flex/ind import { StorageButton, StorageLink } from "../storage-controls.jsx"; import { check_unused_space, get_resize_info, grow_dialog, shrink_dialog } from "../block/resize.jsx"; +import { block_actions } from "../block/actions.jsx"; import { StorageCard, StorageDescription, new_card, navigate_to_new_card_location, navigate_away_from_card } from "../pages.jsx"; import { block_name, fmt_size, get_active_usage, teardown_active_usage, reload_systemd } from "../utils.js"; import { @@ -218,6 +219,7 @@ export function make_block_logical_volume_card(next, vgroup, lvol, block) { }, lvm2_create_snapshot_action(lvol), repair_action, + ...block_actions(block), { title: _("Delete"), action: () => lvol_delete(lvol, card), diff --git a/pkg/storaged/lvm2/physical-volume.jsx b/pkg/storaged/lvm2/physical-volume.jsx index 596f5f6d39fa..24d782e5a006 100644 --- a/pkg/storaged/lvm2/physical-volume.jsx +++ b/pkg/storaged/lvm2/physical-volume.jsx @@ -26,7 +26,6 @@ import { CardBody } from "@patternfly/react-core/dist/esm/components/Card/index. import { DescriptionList } from "@patternfly/react-core/dist/esm/components/DescriptionList/index.js"; import { StorageCard, StorageDescription, new_card, register_crossref } from "../pages.jsx"; -import { std_format_action } from "../block/actions.jsx"; import { std_lock_action } from "../crypto/actions.jsx"; import { StorageUsageBar } from "../storage-controls.jsx"; @@ -47,7 +46,6 @@ export function make_lvm2_physical_volume_card(next, backing_block, content_bloc props: { backing_block, content_block }, actions: [ std_lock_action(backing_block, content_block), - std_format_action(backing_block, content_block), ] }); diff --git a/pkg/storaged/mdraid/mdraid-disk.jsx b/pkg/storaged/mdraid/mdraid-disk.jsx index 40dd15a5226a..2fb85cb9f4f7 100644 --- a/pkg/storaged/mdraid/mdraid-disk.jsx +++ b/pkg/storaged/mdraid/mdraid-disk.jsx @@ -26,7 +26,6 @@ import { CardBody } from "@patternfly/react-core/dist/esm/components/Card/index. import { DescriptionList } from "@patternfly/react-core/dist/esm/components/DescriptionList/index.js"; import { StorageCard, StorageDescription, new_card, register_crossref } from "../pages.jsx"; -import { std_format_action } from "../block/actions.jsx"; import { block_short_name, fmt_size, mdraid_name } from "../utils.js"; import { std_lock_action } from "../crypto/actions.jsx"; @@ -44,7 +43,6 @@ export function make_mdraid_disk_card(next, backing_block, content_block) { props: { backing_block, content_block, mdraid }, actions: [ std_lock_action(backing_block, content_block), - std_format_action(backing_block, content_block), ] }); diff --git a/pkg/storaged/mdraid/mdraid.jsx b/pkg/storaged/mdraid/mdraid.jsx index a71a2a26cf30..a64780853cca 100644 --- a/pkg/storaged/mdraid/mdraid.jsx +++ b/pkg/storaged/mdraid/mdraid.jsx @@ -46,7 +46,7 @@ import { init_teardown_usage } from "../dialog.jsx"; -import { partitionable_block_actions } from "../partitions/actions.jsx"; +import { partitionable_block_actions } from "../block/actions.jsx"; const _ = cockpit.gettext; @@ -228,7 +228,7 @@ export function make_mdraid_page(parent, mdraid) { excuse: add_excuse, tag: "disks", }), - ...(block ? partitionable_block_actions(block, "device") : []), + ...partitionable_block_actions(block), { title: _("Delete"), action: () => mdraid_delete(mdraid, block, mdraid_card), diff --git a/pkg/storaged/partitions/partition.jsx b/pkg/storaged/partitions/partition.jsx index b52edeae051d..bf7b6713bee6 100644 --- a/pkg/storaged/partitions/partition.jsx +++ b/pkg/storaged/partitions/partition.jsx @@ -33,6 +33,7 @@ import { } 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"; +import { block_actions } from "../block/actions.jsx"; import { StorageCard, StorageDescription, new_card, navigate_away_from_card } from "../pages.jsx"; const _ = cockpit.gettext; @@ -108,6 +109,7 @@ export function make_partition_card(next, block) { action: () => grow_dialog(client, block_part, info), excuse: grow_excuse, }), + ...block_actions(block), { title: _("Delete"), action: () => delete_partition(block, card), diff --git a/pkg/storaged/stratis/blockdev.jsx b/pkg/storaged/stratis/blockdev.jsx index a56f10438439..cce7c5829b8f 100644 --- a/pkg/storaged/stratis/blockdev.jsx +++ b/pkg/storaged/stratis/blockdev.jsx @@ -26,7 +26,6 @@ import { CardBody } from "@patternfly/react-core/dist/esm/components/Card/index. import { DescriptionList } from "@patternfly/react-core/dist/esm/components/DescriptionList/index.js"; import { StorageCard, StorageDescription, new_card, register_crossref } from "../pages.jsx"; -import { std_format_action } from "../block/actions.jsx"; import { fmt_size } from "../utils.js"; import { std_lock_action } from "../crypto/actions.jsx"; @@ -45,7 +44,6 @@ export function make_stratis_blockdev_card(next, backing_block, content_block) { props: { backing_block, content_block, pool, stopped_pool }, actions: [ std_lock_action(backing_block, content_block), - std_format_action(backing_block, content_block), ] }); diff --git a/pkg/storaged/swap/swap.jsx b/pkg/storaged/swap/swap.jsx index 1960f54a195e..2d772842230b 100644 --- a/pkg/storaged/swap/swap.jsx +++ b/pkg/storaged/swap/swap.jsx @@ -26,7 +26,6 @@ import { DescriptionList } from "@patternfly/react-core/dist/esm/components/Desc import { useEvent } from "hooks"; import { StorageCard, StorageDescription, new_card } from "../pages.jsx"; -import { std_format_action } from "../block/actions.jsx"; import { fmt_size, decode_filename, encode_filename, parse_options, unparse_options, extract_option, @@ -97,7 +96,6 @@ export function make_swap_card(next, backing_block, content_block) { (block_swap && !block_swap.Active ? { title: _("Start"), action: start } : null), - std_format_action(backing_block, content_block), ] }); } From 4dfcf043841b2cd1bd6b666738f8f65d5354234d Mon Sep 17 00:00:00 2001 From: Marius Vollmer Date: Fri, 5 Apr 2024 14:02:34 +0300 Subject: [PATCH 03/15] storage: Move "Lock" and "Unlock" actions to "Encryption" card That's where they belong. Filesystems are still automatically locked and unlocked when mounting and unmounting them. --- pkg/storaged/block/create-pages.jsx | 8 +++++--- pkg/storaged/block/unformatted-data.jsx | 4 ---- pkg/storaged/block/unrecognized-data.jsx | 4 ---- pkg/storaged/btrfs/device.jsx | 11 ----------- pkg/storaged/btrfs/filesystem.jsx | 2 -- pkg/storaged/btrfs/volume.jsx | 2 -- pkg/storaged/crypto/encryption.jsx | 18 +++++++++++++++++- pkg/storaged/crypto/locked-encrypted-data.jsx | 4 ---- pkg/storaged/lvm2/physical-volume.jsx | 4 ---- pkg/storaged/mdraid/mdraid-disk.jsx | 6 +----- pkg/storaged/stratis/blockdev.jsx | 4 ---- pkg/storaged/swap/swap.jsx | 2 -- 12 files changed, 23 insertions(+), 46 deletions(-) diff --git a/pkg/storaged/block/create-pages.jsx b/pkg/storaged/block/create-pages.jsx index 555e672bb710..518dc32694db 100644 --- a/pkg/storaged/block/create-pages.jsx +++ b/pkg/storaged/block/create-pages.jsx @@ -77,17 +77,16 @@ export function make_block_page(parent, block, card) { content_block = block; } - if (is_crypto) - card = make_encryption_card(card, block); - if (!content_block) { if (!is_crypto) { // can not happen unless there is a bug in the code above. console.error("Assertion failure: is_crypto == false"); } if (fstab_config.length > 0 && !is_btrfs) { + card = make_encryption_card(card, block, true); card = make_filesystem_card(card, block, null, fstab_config); } else { + card = make_encryption_card(card, block, false); card = make_locked_encrypted_data_card(card, block); } } else { @@ -95,6 +94,9 @@ export function make_block_page(parent, block, card) { const block_pvol = client.blocks_pvol[content_block.path]; const block_swap = client.blocks_swap[content_block.path]; + if (is_crypto) + card = make_encryption_card(card, block, is_filesystem); + if (block_btrfs_blockdev) { if (single_device_volume) card = make_btrfs_filesystem_card(card, block, content_block); diff --git a/pkg/storaged/block/unformatted-data.jsx b/pkg/storaged/block/unformatted-data.jsx index 92cf7067d58e..287f86ef0f0f 100644 --- a/pkg/storaged/block/unformatted-data.jsx +++ b/pkg/storaged/block/unformatted-data.jsx @@ -20,7 +20,6 @@ import cockpit from "cockpit"; import { StorageCard, new_card } from "../pages.jsx"; -import { std_lock_action } from "../crypto/actions.jsx"; const _ = cockpit.gettext; @@ -29,8 +28,5 @@ export function make_unformatted_data_card(next, backing_block, content_block) { title: _("Unformatted data"), next, component: StorageCard, - actions: [ - std_lock_action(backing_block, content_block), - ] }); } diff --git a/pkg/storaged/block/unrecognized-data.jsx b/pkg/storaged/block/unrecognized-data.jsx index 1c8fa610cb76..974a72691812 100644 --- a/pkg/storaged/block/unrecognized-data.jsx +++ b/pkg/storaged/block/unrecognized-data.jsx @@ -24,7 +24,6 @@ import { CardBody } from "@patternfly/react-core/dist/esm/components/Card/index. import { DescriptionList } from "@patternfly/react-core/dist/esm/components/DescriptionList/index.js"; import { StorageCard, StorageDescription, new_card } from "../pages.jsx"; -import { std_lock_action } from "../crypto/actions.jsx"; const _ = cockpit.gettext; @@ -34,9 +33,6 @@ export function make_unrecognized_data_card(next, backing_block, content_block) next, component: UnrecognizedDataCard, props: { backing_block, content_block }, - actions: [ - std_lock_action(backing_block, content_block), - ] }); } diff --git a/pkg/storaged/btrfs/device.jsx b/pkg/storaged/btrfs/device.jsx index 68ecb43850b5..cbcc4b19f259 100644 --- a/pkg/storaged/btrfs/device.jsx +++ b/pkg/storaged/btrfs/device.jsx @@ -27,7 +27,6 @@ import { DescriptionList } from "@patternfly/react-core/dist/esm/components/Desc import { StorageCard, StorageDescription, new_card, register_crossref } from "../pages.jsx"; import { StorageUsageBar } from "../storage-controls.jsx"; -import { std_lock_action } from "../crypto/actions.jsx"; import { btrfs_device_usage } from "./utils.jsx"; const _ = cockpit.gettext; @@ -43,7 +42,6 @@ export function make_btrfs_device_card(next, backing_block, content_block, block next, component: BtrfsDeviceCard, props: { backing_block, content_block }, - actions: btrfs_device_actions(backing_block, content_block), }); register_crossref({ @@ -84,12 +82,3 @@ export const BtrfsDeviceCard = ({ card, backing_block, content_block }) => { ); }; - -export function btrfs_device_actions(backing_block, content_block) { - if (backing_block && content_block) - return [ - std_lock_action(backing_block, content_block), - ]; - else - return []; -} diff --git a/pkg/storaged/btrfs/filesystem.jsx b/pkg/storaged/btrfs/filesystem.jsx index c093297ae374..920b6ec99009 100644 --- a/pkg/storaged/btrfs/filesystem.jsx +++ b/pkg/storaged/btrfs/filesystem.jsx @@ -29,7 +29,6 @@ import { } from "../pages.jsx"; import { StorageUsageBar, StorageLink } from "../storage-controls.jsx"; import { btrfs_device_usage, btrfs_is_volume_mounted } from "./utils.jsx"; -import { btrfs_device_actions } from "./device.jsx"; import { rename_dialog } from "./volume.jsx"; const _ = cockpit.gettext; @@ -43,7 +42,6 @@ export function make_btrfs_filesystem_card(next, backing_block, content_block) { return new_card({ title: _("btrfs filesystem"), next, - actions: btrfs_device_actions(backing_block, content_block), component: BtrfsFilesystemCard, props: { backing_block, content_block }, }); diff --git a/pkg/storaged/btrfs/volume.jsx b/pkg/storaged/btrfs/volume.jsx index 3b4284516e64..d51858047478 100644 --- a/pkg/storaged/btrfs/volume.jsx +++ b/pkg/storaged/btrfs/volume.jsx @@ -34,7 +34,6 @@ import { fmt_size_long, validate_fsys_label, should_ignore } from "../utils.js"; import { btrfs_usage, btrfs_is_volume_mounted } from "./utils.jsx"; import { dialog_open, TextInput } from "../dialog.jsx"; import { make_btrfs_subvolume_pages } from "./subvolume.jsx"; -import { btrfs_device_actions } from "./device.jsx"; const _ = cockpit.gettext; @@ -145,7 +144,6 @@ export function make_btrfs_subvolumes_card(next, block, backing_block) { return new_card({ title: _("btrfs subvolumes"), next, - actions: btrfs_device_actions(block, backing_block), component: BtrfsSubVolumesCard, }); } diff --git a/pkg/storaged/crypto/encryption.jsx b/pkg/storaged/crypto/encryption.jsx index 4f5cf5c1abdf..7d8dffcd3266 100644 --- a/pkg/storaged/crypto/encryption.jsx +++ b/pkg/storaged/crypto/encryption.jsx @@ -34,16 +34,32 @@ import luksmeta_monitor_hack_py from "./luksmeta-monitor-hack.py"; import { is_mounted } from "../filesystem/utils.jsx"; import { StorageLink } from "../storage-controls.jsx"; import { CryptoKeyslots } from "./keyslots.jsx"; +import { lock, unlock } from "./actions.jsx"; const _ = cockpit.gettext; -export function make_encryption_card(next, block) { +export function make_encryption_card(next, block, is_filesystem) { + const content_block = client.blocks_cleartext[block.path]; + return new_card({ title: _("Encryption"), next, type_extra: _("encrypted"), component: EncryptionCard, props: { block }, + actions: [ + (content_block && !is_filesystem) && + { + title: _("Lock"), + action: () => lock(block), + }, + !content_block && + { + title: _("Unlock"), + primary: !is_filesystem, + action: () => unlock(block), + }, + ] }); } diff --git a/pkg/storaged/crypto/locked-encrypted-data.jsx b/pkg/storaged/crypto/locked-encrypted-data.jsx index 938db26554eb..e37e67a95e22 100644 --- a/pkg/storaged/crypto/locked-encrypted-data.jsx +++ b/pkg/storaged/crypto/locked-encrypted-data.jsx @@ -20,7 +20,6 @@ import cockpit from "cockpit"; import { StorageCard, new_card } from "../pages.jsx"; -import { unlock } from "./actions.jsx"; const _ = cockpit.gettext; @@ -31,8 +30,5 @@ export function make_locked_encrypted_data_card(next, block) { page_block: block, component: StorageCard, props: { block }, - actions: [ - { title: _("Unlock"), action: () => unlock(block) }, - ] }); } diff --git a/pkg/storaged/lvm2/physical-volume.jsx b/pkg/storaged/lvm2/physical-volume.jsx index 24d782e5a006..eadb6b8c9d7f 100644 --- a/pkg/storaged/lvm2/physical-volume.jsx +++ b/pkg/storaged/lvm2/physical-volume.jsx @@ -26,7 +26,6 @@ import { CardBody } from "@patternfly/react-core/dist/esm/components/Card/index. import { DescriptionList } from "@patternfly/react-core/dist/esm/components/DescriptionList/index.js"; import { StorageCard, StorageDescription, new_card, register_crossref } from "../pages.jsx"; -import { std_lock_action } from "../crypto/actions.jsx"; import { StorageUsageBar } from "../storage-controls.jsx"; const _ = cockpit.gettext; @@ -44,9 +43,6 @@ export function make_lvm2_physical_volume_card(next, backing_block, content_bloc : backing_block.Size), component: LVM2PhysicalVolumeCard, props: { backing_block, content_block }, - actions: [ - std_lock_action(backing_block, content_block), - ] }); function pvol_remove() { diff --git a/pkg/storaged/mdraid/mdraid-disk.jsx b/pkg/storaged/mdraid/mdraid-disk.jsx index 2fb85cb9f4f7..803bdd171920 100644 --- a/pkg/storaged/mdraid/mdraid-disk.jsx +++ b/pkg/storaged/mdraid/mdraid-disk.jsx @@ -27,7 +27,6 @@ import { DescriptionList } from "@patternfly/react-core/dist/esm/components/Desc import { StorageCard, StorageDescription, new_card, register_crossref } from "../pages.jsx"; import { block_short_name, fmt_size, mdraid_name } from "../utils.js"; -import { std_lock_action } from "../crypto/actions.jsx"; const _ = cockpit.gettext; @@ -40,10 +39,7 @@ export function make_mdraid_disk_card(next, backing_block, content_block) { next, location: mdraid_block ? block_short_name(mdraid_block) : (mdraid ? mdraid_name(mdraid) : null), component: MDRaidDiskCard, - props: { backing_block, content_block, mdraid }, - actions: [ - std_lock_action(backing_block, content_block), - ] + props: { backing_block, content_block, mdraid } }); if (mdraid) { diff --git a/pkg/storaged/stratis/blockdev.jsx b/pkg/storaged/stratis/blockdev.jsx index cce7c5829b8f..380383024f42 100644 --- a/pkg/storaged/stratis/blockdev.jsx +++ b/pkg/storaged/stratis/blockdev.jsx @@ -27,7 +27,6 @@ import { DescriptionList } from "@patternfly/react-core/dist/esm/components/Desc import { StorageCard, StorageDescription, new_card, register_crossref } from "../pages.jsx"; import { fmt_size } from "../utils.js"; -import { std_lock_action } from "../crypto/actions.jsx"; const _ = cockpit.gettext; @@ -42,9 +41,6 @@ export function make_stratis_blockdev_card(next, backing_block, content_block) { next, component: StratisBlockdevCard, props: { backing_block, content_block, pool, stopped_pool }, - actions: [ - std_lock_action(backing_block, content_block), - ] }); if (pool || stopped_pool) { diff --git a/pkg/storaged/swap/swap.jsx b/pkg/storaged/swap/swap.jsx index 2d772842230b..c654dc68275b 100644 --- a/pkg/storaged/swap/swap.jsx +++ b/pkg/storaged/swap/swap.jsx @@ -30,7 +30,6 @@ import { fmt_size, decode_filename, encode_filename, parse_options, unparse_options, extract_option, } from "../utils.js"; -import { std_lock_action } from "../crypto/actions.jsx"; const _ = cockpit.gettext; @@ -89,7 +88,6 @@ export function make_swap_card(next, backing_block, content_block) { component: SwapCard, props: { block: content_block, block_swap }, actions: [ - std_lock_action(backing_block, content_block), (block_swap && block_swap.Active ? { title: _("Stop"), action: stop } : null), From 37602fcc7aa096033175811d52ad460c4324b3f6 Mon Sep 17 00:00:00 2001 From: Marius Vollmer Date: Thu, 25 Jan 2024 12:30:48 +0200 Subject: [PATCH 04/15] storage: Remove "Unrmatted Data" and "Locked Data" cards They have no actions anymore. --- pkg/storaged/block/create-pages.jsx | 5 ++--- pkg/storaged/crypto/encryption.jsx | 2 +- pkg/storaged/pages.jsx | 14 ++++++++------ 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/pkg/storaged/block/create-pages.jsx b/pkg/storaged/block/create-pages.jsx index 518dc32694db..5978026cea90 100644 --- a/pkg/storaged/block/create-pages.jsx +++ b/pkg/storaged/block/create-pages.jsx @@ -87,7 +87,6 @@ export function make_block_page(parent, block, card) { card = make_filesystem_card(card, block, null, fstab_config); } else { card = make_encryption_card(card, block, false); - card = make_locked_encrypted_data_card(card, block); } } else { const is_filesystem = content_block.IdUsage == 'filesystem'; @@ -95,7 +94,7 @@ export function make_block_page(parent, block, card) { const block_swap = client.blocks_swap[content_block.path]; if (is_crypto) - card = make_encryption_card(card, block, is_filesystem); + card = make_encryption_card(card, block, is_filesystem && !(block_btrfs_blockdev && !single_device_volume)); if (block_btrfs_blockdev) { if (single_device_volume) @@ -116,7 +115,7 @@ export function make_block_page(parent, block, card) { (content_block.IdUsage == "other" && content_block.IdType == "swap")) { card = make_swap_card(card, block, content_block); } else if (client.blocks_available[content_block.path]) { - card = make_unformatted_data_card(card, block, content_block); + // No card for unformatted data } else { card = make_unrecognized_data_card(card, block, content_block); } diff --git a/pkg/storaged/crypto/encryption.jsx b/pkg/storaged/crypto/encryption.jsx index 7d8dffcd3266..f411f6f2ad57 100644 --- a/pkg/storaged/crypto/encryption.jsx +++ b/pkg/storaged/crypto/encryption.jsx @@ -44,7 +44,7 @@ export function make_encryption_card(next, block, is_filesystem) { return new_card({ title: _("Encryption"), next, - type_extra: _("encrypted"), + type_extra: content_block ? _("encrypted") : _("locked"), component: EncryptionCard, props: { block }, actions: [ diff --git a/pkg/storaged/pages.jsx b/pkg/storaged/pages.jsx index e206b97c3684..4eb782971f5c 100644 --- a/pkg/storaged/pages.jsx +++ b/pkg/storaged/pages.jsx @@ -395,20 +395,22 @@ const ActionButtons = ({ card }) => { return buttons; }; -function page_type_extra(page) { +function page_type(page) { + let type = null; const extra = []; + let c = page.card; while (c) { if (c.type_extra) extra.push(c.type_extra); + else if (!type) + type = c.title; c = c.next; } - return extra; -} -function page_type(page) { - const type = page.card.title; - const extra = page_type_extra(page); + if (!type) + type = extra.shift(); + if (extra.length > 0) return type + " (" + extra.join(", ") + ")"; else From 1b188d96d2f43b5f25b3a315766cc01a6fbdd91d Mon Sep 17 00:00:00 2001 From: Marius Vollmer Date: Fri, 5 Apr 2024 15:16:40 +0300 Subject: [PATCH 05/15] storage: New "Add encryption" action for unformatted blocks --- pkg/storaged/block/actions.jsx | 9 +++++- pkg/storaged/block/format-dialog.jsx | 47 +++++++++++++++++++++------- pkg/storaged/crypto/encryption.jsx | 2 +- 3 files changed, 45 insertions(+), 13 deletions(-) diff --git a/pkg/storaged/block/actions.jsx b/pkg/storaged/block/actions.jsx index c649fd17d25c..a96c357f9459 100644 --- a/pkg/storaged/block/actions.jsx +++ b/pkg/storaged/block/actions.jsx @@ -21,7 +21,7 @@ import cockpit from "cockpit"; import client from "../client"; import { format_disk } from "./format-disk-dialog.jsx"; -import { format_dialog } from "./format-dialog.jsx"; +import { format_dialog, add_encryption_dialog } from "./format-dialog.jsx"; const _ = cockpit.gettext; @@ -32,6 +32,13 @@ export function block_actions(block, partitionable) { const excuse = block.ReadOnly ? _("Device is read-only") : null; const actions = []; + if (client.blocks_available[block.path]) + actions.push({ + title: _("Add encryption"), + action: () => add_encryption_dialog(client, block), + excuse, + }); + if (partitionable) actions.push({ title: _("Create partition table"), diff --git a/pkg/storaged/block/format-dialog.jsx b/pkg/storaged/block/format-dialog.jsx index feaad1845cad..c22437a8e023 100644 --- a/pkg/storaged/block/format-dialog.jsx +++ b/pkg/storaged/block/format-dialog.jsx @@ -96,13 +96,18 @@ export function format_dialog(client, path, start, size, enable_dos_extended) { return false; }) .then(version => { - return format_dialog_internal(client, path, start, size, enable_dos_extended, version); + return format_dialog_internal(client, path, + { start, size, enable_dos_extended, old_luks_version: version }); }); } else { - return format_dialog_internal(client, path, start, size, enable_dos_extended); + return format_dialog_internal(client, path, { start, size, enable_dos_extended }); } } +export function add_encryption_dialog(client, block) { + return format_dialog_internal(client, block.path, { add_encryption: true }); +} + function find_root_fsys_block() { const root = client.anaconda?.mount_point_prefix || "/"; for (const p in client.blocks) { @@ -114,7 +119,8 @@ function find_root_fsys_block() { return null; } -function format_dialog_internal(client, path, start, size, enable_dos_extended, old_luks_version) { +function format_dialog_internal(client, path, options) { + const { start, size, enable_dos_extended, old_luks_version, add_encryption } = options; const block = client.blocks[path]; const block_part = client.blocks_part[path]; const block_ptable = client.blocks_ptable[path] || client.blocks_ptable[block_part?.Table]; @@ -126,13 +132,15 @@ function format_dialog_internal(client, path, start, size, enable_dos_extended, const create_partition = (start !== undefined); let title; - if (create_partition) + if (add_encryption) + title = cockpit.format(_("Add encryption to $0"), block_name(block)); + else if (create_partition) title = cockpit.format(_("Create partition on $0"), block_name(block)); else title = cockpit.format(_("Format $0"), block_name(block)); function is_filesystem(vals) { - return vals.type != "empty" && vals.type != "dos-extended" && vals.type != "biosboot" && vals.type != "swap"; + return !add_encryption && vals.type != "empty" && vals.type != "dos-extended" && vals.type != "biosboot" && vals.type != "swap"; } function add_fsys(storaged_name, entry) { @@ -182,6 +190,8 @@ function format_dialog_internal(client, path, start, size, enable_dos_extended, return vals.crypto && vals.crypto !== "none"; } + let default_crypto_type = null; + function add_crypto_type(value, title, recommended) { if ((client.manager.SupportedEncryptionTypes && client.manager.SupportedEncryptionTypes.indexOf(value) != -1) || value == "luks1") { @@ -189,10 +199,16 @@ function format_dialog_internal(client, path, start, size, enable_dos_extended, value, title: title + (recommended ? " " + _("(recommended)") : "") }); + if (recommended && !default_crypto_type) + default_crypto_type = value; } } - const crypto_types = [{ value: "none", title: _("No encryption") }]; + const crypto_types = []; + if (!add_encryption) { + crypto_types.push({ value: "none", title: _("No encryption") }); + default_crypto_type = "none"; + } if (offer_keep_keys) { if (old_luks_version) crypto_types.push({ @@ -201,6 +217,7 @@ function format_dialog_internal(client, path, start, size, enable_dos_extended, }); else crypto_types.push({ value: " keep", title: _("Reuse existing encryption") }); + default_crypto_type = " keep"; } add_crypto_type("luks1", "LUKS1", false); add_crypto_type("luks2", "LUKS2", true); @@ -286,6 +303,12 @@ function format_dialog_internal(client, path, start, size, enable_dos_extended, ]; } + if (add_encryption) { + action_variants = [ + { Title: _("Add encryption") } + ]; + } + const dlg = dialog_open({ Title: title, Teardown: TeardownMessage(usage), @@ -310,7 +333,8 @@ function format_dialog_internal(client, path, start, size, enable_dos_extended, SelectOne("type", _("Type"), { value: default_type, - choices: filesystem_options + choices: filesystem_options, + visible: () => !add_encryption, }), SizeSlider("size", _("Size"), { @@ -330,7 +354,7 @@ function format_dialog_internal(client, path, start, size, enable_dos_extended, SelectOne("crypto", _("Encryption"), { choices: crypto_types, - value: offer_keep_keys ? " keep" : "none", + value: default_crypto_type, visible: vals => vals.type != "dos-extended" && vals.type != "biosboot" && vals.type != "efi", nested_fields: [ PassInput("passphrase", _("Passphrase"), @@ -396,12 +420,12 @@ function format_dialog_internal(client, path, start, size, enable_dos_extended, }, Action: { Variants: action_variants, - Danger: (create_partition ? null : _("Formatting erases all data on a storage device.")), + Danger: (create_partition || add_encryption) ? null : _("Formatting erases all data on a storage device."), wrapper: job_progress_wrapper(client, block.path, client.blocks_cleartext[block.path]?.path), disable_on_error: usage.Teardown, action: function (vals) { const mount_now = vals.variant != "nomount"; - let type = vals.type; + let type = add_encryption ? "empty" : vals.type; let partition_type = ""; if (type == "efi") { @@ -616,7 +640,8 @@ function format_dialog_internal(client, path, start, size, enable_dos_extended, const block_swap = await client.wait_for(() => block_swap_for_block(path)); await block_swap.Start({}); } - if (is_encrypted(vals) && vals.type != "empty" && !mount_now && !client.in_anaconda_mode()) { + if (is_encrypted(vals) && vals.type != "empty" && !mount_now && + unlock_before_format && !client.in_anaconda_mode()) { const block_crypto = await client.wait_for(() => block_crypto_for_block(path)); await block_crypto.Lock({ }); } diff --git a/pkg/storaged/crypto/encryption.jsx b/pkg/storaged/crypto/encryption.jsx index f411f6f2ad57..bd8be8081054 100644 --- a/pkg/storaged/crypto/encryption.jsx +++ b/pkg/storaged/crypto/encryption.jsx @@ -53,7 +53,7 @@ export function make_encryption_card(next, block, is_filesystem) { title: _("Lock"), action: () => lock(block), }, - !content_block && + (!content_block && !is_filesystem) && { title: _("Unlock"), primary: !is_filesystem, From 71603fcc0f50a985f94c896e63858b5d387cd4de Mon Sep 17 00:00:00 2001 From: Marius Vollmer Date: Fri, 5 Apr 2024 15:30:25 +0300 Subject: [PATCH 06/15] storage: Offer "Format" on "Encryption" card --- pkg/storaged/block/actions.jsx | 34 +++++++++++++++++++--------- pkg/storaged/block/format-dialog.jsx | 7 +++++- pkg/storaged/crypto/encryption.jsx | 6 +++-- 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/pkg/storaged/block/actions.jsx b/pkg/storaged/block/actions.jsx index a96c357f9459..dc70b96e8503 100644 --- a/pkg/storaged/block/actions.jsx +++ b/pkg/storaged/block/actions.jsx @@ -21,25 +21,25 @@ import cockpit from "cockpit"; import client from "../client"; import { format_disk } from "./format-disk-dialog.jsx"; -import { format_dialog, add_encryption_dialog } from "./format-dialog.jsx"; +import { format_dialog, add_encryption_dialog, encrypted_format_dialog } from "./format-dialog.jsx"; const _ = cockpit.gettext; -export function block_actions(block, partitionable) { +export function block_actions(block, kind) { if (!block || block.Size === 0) return []; const excuse = block.ReadOnly ? _("Device is read-only") : null; const actions = []; - if (client.blocks_available[block.path]) + if (client.blocks_available[block.path] && kind != "crypto") actions.push({ title: _("Add encryption"), action: () => add_encryption_dialog(client, block), excuse, }); - if (partitionable) + if (kind == "part") actions.push({ title: _("Create partition table"), action: () => format_disk(block), @@ -47,16 +47,28 @@ export function block_actions(block, partitionable) { excuse, }); - actions.push({ - title: _("Format"), - action: () => format_dialog(client, block.path), - danger: true, - excuse, - }); + if (kind == "crypto") + actions.push({ + title: _("Format cleartext device"), + action: () => encrypted_format_dialog(client, block), + danger: true, + excuse, + }); + else + actions.push({ + title: _("Format"), + action: () => format_dialog(client, block.path), + danger: true, + excuse, + }); return actions; } export function partitionable_block_actions(block) { - return block_actions(block, true); + return block_actions(block, "part"); +} + +export function encrypted_block_actions(block) { + return block_actions(block, "crypto"); } diff --git a/pkg/storaged/block/format-dialog.jsx b/pkg/storaged/block/format-dialog.jsx index c22437a8e023..9ef5d0228784 100644 --- a/pkg/storaged/block/format-dialog.jsx +++ b/pkg/storaged/block/format-dialog.jsx @@ -108,6 +108,10 @@ export function add_encryption_dialog(client, block) { return format_dialog_internal(client, block.path, { add_encryption: true }); } +export function encrypted_format_dialog(client, block) { + return format_dialog_internal(client, block.path, { is_encrypted: true }); +} + function find_root_fsys_block() { const root = client.anaconda?.mount_point_prefix || "/"; for (const p in client.blocks) { @@ -121,6 +125,7 @@ function find_root_fsys_block() { function format_dialog_internal(client, path, options) { const { start, size, enable_dos_extended, old_luks_version, add_encryption } = options; + const is_already_encrypted = options.is_encrypted; const block = client.blocks[path]; const block_part = client.blocks_part[path]; const block_ptable = client.blocks_ptable[path] || client.blocks_ptable[block_part?.Table]; @@ -355,7 +360,7 @@ function format_dialog_internal(client, path, options) { { choices: crypto_types, value: default_crypto_type, - visible: vals => vals.type != "dos-extended" && vals.type != "biosboot" && vals.type != "efi", + visible: vals => vals.type != "dos-extended" && vals.type != "biosboot" && vals.type != "efi" && !is_already_encrypted, nested_fields: [ PassInput("passphrase", _("Passphrase"), { diff --git a/pkg/storaged/crypto/encryption.jsx b/pkg/storaged/crypto/encryption.jsx index bd8be8081054..5f3c487cdc10 100644 --- a/pkg/storaged/crypto/encryption.jsx +++ b/pkg/storaged/crypto/encryption.jsx @@ -35,6 +35,7 @@ import { is_mounted } from "../filesystem/utils.jsx"; import { StorageLink } from "../storage-controls.jsx"; import { CryptoKeyslots } from "./keyslots.jsx"; import { lock, unlock } from "./actions.jsx"; +import { encrypted_block_actions } from "../block/actions.jsx"; const _ = cockpit.gettext; @@ -48,17 +49,18 @@ export function make_encryption_card(next, block, is_filesystem) { component: EncryptionCard, props: { block }, actions: [ - (content_block && !is_filesystem) && + content_block && { title: _("Lock"), action: () => lock(block), }, - (!content_block && !is_filesystem) && + !content_block && { title: _("Unlock"), primary: !is_filesystem, action: () => unlock(block), }, + ...(content_block ? encrypted_block_actions(content_block) : []), ] }); } From 02854f753587d0c881aa87a8929862417a9dc340 Mon Sep 17 00:00:00 2001 From: Marius Vollmer Date: Mon, 17 Jun 2024 17:04:53 +0300 Subject: [PATCH 07/15] storage: Remove "Reuse existing encryption" option --- pkg/storaged/block/format-dialog.jsx | 147 +++++---------------------- 1 file changed, 28 insertions(+), 119 deletions(-) diff --git a/pkg/storaged/block/format-dialog.jsx b/pkg/storaged/block/format-dialog.jsx index 9ef5d0228784..631e1a3eaf0f 100644 --- a/pkg/storaged/block/format-dialog.jsx +++ b/pkg/storaged/block/format-dialog.jsx @@ -21,7 +21,7 @@ import cockpit from "cockpit"; import client from "../client.js"; import { - edit_crypto_config, parse_options, unparse_options, extract_option, + parse_options, unparse_options, extract_option, get_parent_blocks, is_netdev, decode_filename, encode_filename, block_name, get_active_usage, reload_systemd, teardown_active_usage, @@ -36,7 +36,6 @@ import { } from "../dialog.jsx"; import { get_fstab_config, is_valid_mount_point } from "../filesystem/utils.jsx"; -import { init_existing_passphrase, unlock_with_type } from "../crypto/keyslots.jsx"; import { job_progress_wrapper } from "../jobs-panel.jsx"; import { at_boot_input, update_at_boot_input, mount_options } from "../filesystem/mounting-dialog.jsx"; import { remember_passphrase } from "../anaconda.jsx"; @@ -83,33 +82,15 @@ export function initial_mount_options(client, block) { } export function format_dialog(client, path, start, size, enable_dos_extended) { - const block = client.blocks[path]; - if (block.IdUsage == "crypto") { - cockpit.spawn(["cryptsetup", "luksDump", decode_filename(block.Device)], { superuser: "require" }) - .then(output => { - if (output.indexOf("Keyslots:") >= 0) // This is what luksmeta-monitor-hack looks for - return 2; - else - return 1; - }) - .catch(() => { - return false; - }) - .then(version => { - return format_dialog_internal(client, path, - { start, size, enable_dos_extended, old_luks_version: version }); - }); - } else { - return format_dialog_internal(client, path, { start, size, enable_dos_extended }); - } + return format_dialog_internal(client, client.blocks[path], { start, size, enable_dos_extended }); } export function add_encryption_dialog(client, block) { - return format_dialog_internal(client, block.path, { add_encryption: true }); + return format_dialog_internal(client, block, { add_encryption: true }); } export function encrypted_format_dialog(client, block) { - return format_dialog_internal(client, block.path, { is_encrypted: true }); + return format_dialog_internal(client, block, { is_encrypted: true }); } function find_root_fsys_block() { @@ -123,16 +104,12 @@ function find_root_fsys_block() { return null; } -function format_dialog_internal(client, path, options) { - const { start, size, enable_dos_extended, old_luks_version, add_encryption } = options; +function format_dialog_internal(client, block, options) { + const { start, size, enable_dos_extended, add_encryption } = options; const is_already_encrypted = options.is_encrypted; - const block = client.blocks[path]; - const block_part = client.blocks_part[path]; - const block_ptable = client.blocks_ptable[path] || client.blocks_ptable[block_part?.Table]; - const content_block = block.IdUsage == "crypto" ? client.blocks_cleartext[path] : block; - - const offer_keep_keys = block.IdUsage == "crypto"; - const unlock_before_format = offer_keep_keys && (!content_block || content_block.ReadOnly); + const block_part = client.blocks_part[block.path]; + const block_ptable = client.blocks_ptable[block.path] || client.blocks_ptable[block_part?.Table]; + const content_block = block.IdUsage == "crypto" ? client.blocks_cleartext[block.path] : block; const create_partition = (start !== undefined); @@ -214,20 +191,10 @@ function format_dialog_internal(client, path, options) { crypto_types.push({ value: "none", title: _("No encryption") }); default_crypto_type = "none"; } - if (offer_keep_keys) { - if (old_luks_version) - crypto_types.push({ - value: " keep", - title: cockpit.format(_("Reuse existing encryption ($0)"), "LUKS" + old_luks_version) - }); - else - crypto_types.push({ value: " keep", title: _("Reuse existing encryption") }); - default_crypto_type = " keep"; - } add_crypto_type("luks1", "LUKS1", false); add_crypto_type("luks2", "LUKS2", true); - const usage = get_active_usage(client, create_partition ? null : path, _("format"), _("delete")); + const usage = get_active_usage(client, create_partition ? null : block.path, _("format"), _("delete")); if (usage.Blocking) { dialog_open({ @@ -276,8 +243,6 @@ function format_dialog_internal(client, path, options) { const opt_netdev = extract_option(split_options, "_netdev"); const extra_options = unparse_options(split_options); - let existing_passphrase_type = null; - let at_boot; if (opt_never_auto) at_boot = "never"; @@ -314,7 +279,7 @@ function format_dialog_internal(client, path, options) { ]; } - const dlg = dialog_open({ + dialog_open({ Title: title, Teardown: TeardownMessage(usage), Fields: [ @@ -365,24 +330,24 @@ function format_dialog_internal(client, path, options) { PassInput("passphrase", _("Passphrase"), { validate: function (phrase, vals) { - if (vals.crypto != " keep" && phrase === "") + if (phrase === "") return _("Passphrase cannot be empty"); }, - visible: vals => is_encrypted(vals) && vals.crypto != " keep", + visible: is_encrypted, new_password: true }), PassInput("passphrase2", _("Confirm"), { validate: function (phrase2, vals) { - if (vals.crypto != " keep" && phrase2 != vals.passphrase) + if (phrase2 != vals.passphrase) return _("Passphrases do not match"); }, - visible: vals => is_encrypted(vals) && vals.crypto != " keep", + visible: is_encrypted, new_password: true }), CheckBoxes("store_passphrase", "", { - visible: vals => is_encrypted(vals) && vals.crypto != " keep", + visible: is_encrypted, value: { on: false, }, @@ -390,15 +355,6 @@ function format_dialog_internal(client, path, options) { { title: _("Store passphrase"), tag: "on" } ] }), - PassInput("old_passphrase", _("Passphrase"), - { - validate: function (phrase) { - if (phrase === "") - return _("Passphrase cannot be empty"); - }, - visible: vals => vals.crypto == " keep" && vals.needs_explicit_passphrase, - explanation: _("The disk needs to be unlocked before formatting. Please provide a existing passphrase.") - }), TextInput("crypto_options", _("Encryption options"), { visible: is_encrypted, @@ -462,8 +418,6 @@ function format_dialog_internal(client, path, options) { options['no-discard'] = { t: 'b', v: true }; } - const keep_keys = is_encrypted(vals) && offer_keep_keys && vals.crypto == " keep"; - const config_items = []; let new_crypto_options; if (is_encrypted(vals)) { @@ -486,16 +440,14 @@ function format_dialog_internal(client, path, options) { "track-parents": { t: 'b', v: true } }; - if (!keep_keys) { - if (vals.store_passphrase.on) { - item["passphrase-contents"] = { t: 'ay', v: encode_filename(vals.passphrase) }; - } else { - item["passphrase-contents"] = { t: 'ay', v: encode_filename("") }; - } - config_items.push(["crypttab", item]); - options["encrypt.passphrase"] = { t: 's', v: vals.passphrase }; - options["encrypt.type"] = { t: 's', v: vals.crypto }; + if (vals.store_passphrase.on) { + item["passphrase-contents"] = { t: 'ay', v: encode_filename(vals.passphrase) }; + } else { + item["passphrase-contents"] = { t: 'ay', v: encode_filename("") }; } + config_items.push(["crypttab", item]); + options["encrypt.passphrase"] = { t: 's', v: vals.passphrase }; + options["encrypt.type"] = { t: 's', v: vals.crypto }; } let mount_point; @@ -549,26 +501,6 @@ function format_dialog_internal(client, path, options) { if (config_items.length > 0) options["config-items"] = { t: 'a(sa{sv})', v: config_items }; - async function maybe_unlock() { - const content_block = client.blocks_cleartext[path]; - if (content_block) { - if (content_block.ReadOnly) { - const block_crypto = client.blocks_crypto[path]; - await block_crypto.Lock({}); - await unlock_with_type(client, block, vals.old_passphrase, existing_passphrase_type, false); - } - return content_block; - } - - try { - await unlock_with_type(client, block, vals.old_passphrase, existing_passphrase_type, false); - return client.blocks_cleartext[path]; - } catch (error) { - dlg.set_values({ needs_explicit_passphrase: true }); - throw error; - } - } - function format() { if (create_partition) { if (type == "dos-extended") @@ -576,16 +508,6 @@ function format_dialog_internal(client, path, options) { else return block_ptable.CreatePartitionAndFormat(start, vals.size, partition_type, "", { }, type, options); - } else if (keep_keys) { - return (edit_crypto_config(block, - (config, commit) => { - config.options = new_crypto_options; - return commit(); - }) - .then(() => maybe_unlock()) - .then(content_block => { - return content_block.Format(type, options); - })); } else { return block.Format(type, options) .then(() => { @@ -596,10 +518,7 @@ function format_dialog_internal(client, path, options) { } function block_fsys_for_block(path) { - if (keep_keys) { - const content_block = client.blocks_cleartext[path]; - return client.blocks_fsys[content_block.path]; - } else if (is_encrypted(vals)) + if (is_encrypted(vals)) return (client.blocks_cleartext[path] && client.blocks_fsys[client.blocks_cleartext[path].path]); else @@ -607,10 +526,7 @@ function format_dialog_internal(client, path, options) { } function block_swap_for_block(path) { - if (keep_keys) { - const content_block = client.blocks_cleartext[path]; - return client.blocks_swap[content_block.path]; - } else if (is_encrypted(vals)) + if (is_encrypted(vals)) return (client.blocks_cleartext[path] && client.blocks_swap[client.blocks_cleartext[path].path]); else @@ -631,10 +547,7 @@ function format_dialog_internal(client, path, options) { if (is_encrypted(vals) && is_filesystem(vals) && vals.mount_options?.ro) { const block_crypto = await client.wait_for(() => block_crypto_for_block(path)); await block_crypto.Lock({}); - if (vals.passphrase) - await block_crypto.Unlock(vals.passphrase, { "read-only": { t: "b", v: true } }); - else - await unlock_with_type(client, block, vals.old_passphrase, existing_passphrase_type, true); + await block_crypto.Unlock(vals.passphrase, { "read-only": { t: "b", v: true } }); } if (is_filesystem(vals) && mount_now) { @@ -645,8 +558,7 @@ function format_dialog_internal(client, path, options) { const block_swap = await client.wait_for(() => block_swap_for_block(path)); await block_swap.Start({}); } - if (is_encrypted(vals) && vals.type != "empty" && !mount_now && - unlock_before_format && !client.in_anaconda_mode()) { + if (is_encrypted(vals) && vals.type != "empty" && !mount_now && !client.in_anaconda_mode()) { const block_crypto = await client.wait_for(() => block_crypto_for_block(path)); await block_crypto.Lock({ }); } @@ -660,10 +572,7 @@ function format_dialog_internal(client, path, options) { } }, Inits: [ - init_teardown_usage(client, usage), - unlock_before_format - ? init_existing_passphrase(block, true, type => { existing_passphrase_type = type }) - : null + init_active_usage_processes(client, usage), ] }); } From cec67e78792255b33453cb22ccb917ad45c123a0 Mon Sep 17 00:00:00 2001 From: Marius Vollmer Date: Fri, 5 Apr 2024 16:46:31 +0300 Subject: [PATCH 08/15] storage: Split "Erase" out from "Format" dialogs This allows us to make the format dialogs non-dangerous and primary, and give them more descriptive names. The "Create partition" version of the "Format" dialog now defaults to "empty", and "empty" can not be encrypted. This makes it a very simple dialog. --- pkg/storaged/block/actions.jsx | 59 ++++++++++------- pkg/storaged/block/erase-dialog.jsx | 80 +++++++++++++++++++++++ pkg/storaged/block/format-dialog.jsx | 52 +++++++-------- pkg/storaged/block/format-disk-dialog.jsx | 29 +++----- 4 files changed, 148 insertions(+), 72 deletions(-) create mode 100644 pkg/storaged/block/erase-dialog.jsx diff --git a/pkg/storaged/block/actions.jsx b/pkg/storaged/block/actions.jsx index dc70b96e8503..cf3ee78b19ad 100644 --- a/pkg/storaged/block/actions.jsx +++ b/pkg/storaged/block/actions.jsx @@ -22,6 +22,7 @@ import client from "../client"; import { format_disk } from "./format-disk-dialog.jsx"; import { format_dialog, add_encryption_dialog, encrypted_format_dialog } from "./format-dialog.jsx"; +import { erase_dialog } from "./erase-dialog.jsx"; const _ = cockpit.gettext; @@ -32,35 +33,47 @@ export function block_actions(block, kind) { const excuse = block.ReadOnly ? _("Device is read-only") : null; const actions = []; - if (client.blocks_available[block.path] && kind != "crypto") - actions.push({ - title: _("Add encryption"), - action: () => add_encryption_dialog(client, block), - excuse, - }); + if (client.blocks_available[block.path]) { + if (kind != "crypto") { + actions.push({ + title: _("Add encryption"), + action: () => add_encryption_dialog(client, block), + excuse, + }); + } - if (kind == "part") - actions.push({ - title: _("Create partition table"), - action: () => format_disk(block), - danger: true, - excuse, - }); + if (kind == "part") { + actions.push({ + title: _("Create partitions"), + action: () => format_disk(block), + primary: true, + excuse, + }); + } - if (kind == "crypto") - actions.push({ - title: _("Format cleartext device"), - action: () => encrypted_format_dialog(client, block), - danger: true, - excuse, - }); - else + if (kind == "crypto") { + actions.push({ + title: _("Format cleartext device"), + action: () => encrypted_format_dialog(client, block), + primary: true, + excuse, + }); + } else { + actions.push({ + title: _("Format as filesystem"), + action: () => format_dialog(client, block.path), + primary: true, + excuse, + }); + } + } else { actions.push({ - title: _("Format"), - action: () => format_dialog(client, block.path), + title: kind == "crypto" ? _("Erase cleartext device") : _("Erase"), + action: () => erase_dialog(block), danger: true, excuse, }); + } return actions; } diff --git a/pkg/storaged/block/erase-dialog.jsx b/pkg/storaged/block/erase-dialog.jsx new file mode 100644 index 000000000000..38b14fbc17cd --- /dev/null +++ b/pkg/storaged/block/erase-dialog.jsx @@ -0,0 +1,80 @@ +/* + * This file is part of Cockpit. + * + * Copyright (C) 2024 Red Hat, Inc. + * + * Cockpit is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * Cockpit is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Cockpit; If not, see . + */ + +import cockpit from "cockpit"; +import client from "../client.js"; + +import { + block_name, get_active_usage, teardown_active_usage, +} from "../utils.js"; + +import { + dialog_open, + CheckBoxes, + BlockingMessage, TeardownMessage, + init_active_usage_processes +} from "../dialog.jsx"; + +import { job_progress_wrapper } from "../jobs-panel.jsx"; + +const _ = cockpit.gettext; + +export function erase_dialog(block) { + const usage = get_active_usage(client, block.path, _("erase"), _("delete")); + + if (usage.Blocking) { + dialog_open({ + Title: cockpit.format(_("$0 is in use"), block_name(block)), + Body: BlockingMessage(usage) + }); + return; + } + + dialog_open({ + Title: cockpit.format(_("Erase $0"), block_name(block)), + Teardown: TeardownMessage(usage), + Fields: [ + CheckBoxes("erase", _("Overwrite"), + { + fields: [ + { tag: "on", title: _("Overwrite existing data with zeros (slower)") } + ], + }), + ], + Action: { + Title: _("Erase"), + Danger: _("This will erase all data on the storage device."), + wrapper: job_progress_wrapper(client, block.path), + disable_on_error: usage.Teardown, + action: async function (vals) { + const options = { + 'tear-down': { t: 'b', v: true } + }; + if (vals.erase.on) + options.erase = { t: 's', v: "zero" }; + + await teardown_active_usage(client, usage); + await block.Format("empty", options); + } + }, + Inits: [ + init_active_usage_processes(client, usage), + ] + }); +} diff --git a/pkg/storaged/block/format-dialog.jsx b/pkg/storaged/block/format-dialog.jsx index 631e1a3eaf0f..9d4797275983 100644 --- a/pkg/storaged/block/format-dialog.jsx +++ b/pkg/storaged/block/format-dialog.jsx @@ -119,7 +119,7 @@ function format_dialog_internal(client, block, options) { else if (create_partition) title = cockpit.format(_("Create partition on $0"), block_name(block)); else - title = cockpit.format(_("Format $0"), block_name(block)); + title = cockpit.format(_("Format $0 as filesystem"), block_name(block)); function is_filesystem(vals) { return !add_encryption && vals.type != "empty" && vals.type != "dos-extended" && vals.type != "biosboot" && vals.type != "swap"; @@ -133,6 +133,8 @@ function format_dialog_internal(client, block, options) { } const filesystem_options = []; + if (create_partition) + add_fsys(true, { value: "empty", title: _("Empty") }); add_fsys("xfs", { value: "xfs", title: "XFS" }); add_fsys("ext4", { value: "ext4", title: "EXT4" }); if (client.features.btrfs) @@ -146,7 +148,6 @@ function format_dialog_internal(client, block, options) { if (block_ptable && client.anaconda.efi) add_fsys(true, { value: "efi", title: "EFI system partition" }); } - add_fsys(true, { value: "empty", title: _("No filesystem") }); if (create_partition && enable_dos_extended) add_fsys(true, { value: "dos-extended", title: _("Extended partition") }); @@ -155,7 +156,9 @@ function format_dialog_internal(client, block, options) { } let default_type = null; - if (content_block?.IdUsage == "filesystem" && is_supported(content_block.IdType)) + if (create_partition) + default_type = "empty"; + else if (content_block?.IdUsage == "filesystem" && is_supported(content_block.IdType)) default_type = content_block.IdType; else { const root_block = find_root_fsys_block(); @@ -283,6 +286,21 @@ function format_dialog_internal(client, block, options) { Title: title, Teardown: TeardownMessage(usage), Fields: [ + SizeSlider("size", _("Size"), + { + value: size, + max: size, + round: 1024 * 1024, + visible: function () { + return create_partition; + } + }), + SelectOne("type", _("Type"), + { + value: default_type, + choices: filesystem_options, + visible: () => !add_encryption, + }), TextInput("name", _("Name"), { value: content_block?.IdLabel, @@ -300,32 +318,11 @@ function format_dialog_internal(client, block, options) { variant == "nomount"); } }), - SelectOne("type", _("Type"), - { - value: default_type, - choices: filesystem_options, - visible: () => !add_encryption, - }), - SizeSlider("size", _("Size"), - { - value: size, - max: size, - round: 1024 * 1024, - visible: function () { - return create_partition; - } - }), - CheckBoxes("erase", _("Overwrite"), - { - fields: [ - { tag: "on", title: _("Overwrite existing data with zeros (slower)") } - ], - }), SelectOne("crypto", _("Encryption"), { choices: crypto_types, value: default_crypto_type, - visible: vals => vals.type != "dos-extended" && vals.type != "biosboot" && vals.type != "efi" && !is_already_encrypted, + visible: vals => vals.type != "dos-extended" && vals.type != "biosboot" && vals.type != "efi" && vals.type != "empty" && !is_already_encrypted, nested_fields: [ PassInput("passphrase", _("Passphrase"), { @@ -380,8 +377,7 @@ function format_dialog_internal(client, block, options) { } }, Action: { - Variants: action_variants, - Danger: (create_partition || add_encryption) ? null : _("Formatting erases all data on a storage device."), + Variants: default_type == "empty" ? action_variants_for_empty : action_variants, wrapper: job_progress_wrapper(client, block.path, client.blocks_cleartext[block.path]?.path), disable_on_error: usage.Teardown, action: function (vals) { @@ -408,8 +404,6 @@ function format_dialog_internal(client, block, options) { const options = { 'tear-down': { t: 'b', v: true } }; - if (vals.erase.on) - options.erase = { t: 's', v: "zero" }; if (vals.name) options.label = { t: 's', v: vals.name }; diff --git a/pkg/storaged/block/format-disk-dialog.jsx b/pkg/storaged/block/format-disk-dialog.jsx index 0c18e523eff9..11a4e467a0c3 100644 --- a/pkg/storaged/block/format-disk-dialog.jsx +++ b/pkg/storaged/block/format-disk-dialog.jsx @@ -22,7 +22,7 @@ import client from "../client"; import { dialog_open, - SelectOne, CheckBoxes, + SelectOne, BlockingMessage, TeardownMessage, init_teardown_usage } from "../dialog.jsx"; @@ -43,10 +43,10 @@ export function format_disk(block) { } dialog_open({ - Title: cockpit.format(_("Initialize disk $0"), block_name(block)), + Title: cockpit.format(_("Create partitions on $0"), block_name(block)), Teardown: TeardownMessage(usage), Fields: [ - SelectOne("type", _("Partitioning"), + SelectOne("type", _("Type"), { value: "gpt", choices: [ @@ -55,32 +55,21 @@ export function format_disk(block) { value: "gpt", title: _("Compatible with modern system and hard disks > 2TB (GPT)") }, - { value: "empty", title: _("No partitioning") } ] }), - CheckBoxes("erase", _("Overwrite"), - { - fields: [ - { tag: "on", title: _("Overwrite existing data with zeros (slower)") } - ], - }), ], Action: { - Title: _("Initialize"), - Danger: _("Initializing erases all data on a disk."), + Title: _("Create partition table"), wrapper: job_progress_wrapper(client, block.path), disable_on_error: usage.Teardown, - action: function (vals) { + action: async function (vals) { const options = { 'tear-down': { t: 'b', v: true } }; - if (vals.erase.on) - options.erase = { t: 's', v: "zero" }; - return teardown_active_usage(client, usage) - .then(function () { - return block.Format(vals.type, options); - }) - .then(reload_systemd); + + await teardown_active_usage(client, usage); + await block.Format(vals.type, options); + await reload_systemd(); } }, Inits: [ From c7f54e3019c7b700a1da93bc769f46a580706ce3 Mon Sep 17 00:00:00 2001 From: Marius Vollmer Date: Fri, 5 Apr 2024 17:16:02 +0300 Subject: [PATCH 09/15] storage: Offer global "Create partition" action --- pkg/storaged/block/actions.jsx | 8 ++--- pkg/storaged/block/format-dialog.jsx | 37 ++++++++++----------- pkg/storaged/partitions/partition-table.jsx | 31 +++++++++++++---- 3 files changed, 46 insertions(+), 30 deletions(-) diff --git a/pkg/storaged/block/actions.jsx b/pkg/storaged/block/actions.jsx index cf3ee78b19ad..b95d51b2e0b8 100644 --- a/pkg/storaged/block/actions.jsx +++ b/pkg/storaged/block/actions.jsx @@ -21,7 +21,7 @@ import cockpit from "cockpit"; import client from "../client"; import { format_disk } from "./format-disk-dialog.jsx"; -import { format_dialog, add_encryption_dialog, encrypted_format_dialog } from "./format-dialog.jsx"; +import { format_dialog } from "./format-dialog.jsx"; import { erase_dialog } from "./erase-dialog.jsx"; const _ = cockpit.gettext; @@ -37,7 +37,7 @@ export function block_actions(block, kind) { if (kind != "crypto") { actions.push({ title: _("Add encryption"), - action: () => add_encryption_dialog(client, block), + action: () => format_dialog(block, { add_encryption: true }), excuse, }); } @@ -54,14 +54,14 @@ export function block_actions(block, kind) { if (kind == "crypto") { actions.push({ title: _("Format cleartext device"), - action: () => encrypted_format_dialog(client, block), + action: () => format_dialog(block, { is_encrypted: true }), primary: true, excuse, }); } else { actions.push({ title: _("Format as filesystem"), - action: () => format_dialog(client, block.path), + action: () => format_dialog(block), primary: true, excuse, }); diff --git a/pkg/storaged/block/format-dialog.jsx b/pkg/storaged/block/format-dialog.jsx index 9d4797275983..2b08f83589d4 100644 --- a/pkg/storaged/block/format-dialog.jsx +++ b/pkg/storaged/block/format-dialog.jsx @@ -81,18 +81,6 @@ export function initial_mount_options(client, block) { return initial_tab_options(client, block, true); } -export function format_dialog(client, path, start, size, enable_dos_extended) { - return format_dialog_internal(client, client.blocks[path], { start, size, enable_dos_extended }); -} - -export function add_encryption_dialog(client, block) { - return format_dialog_internal(client, block, { add_encryption: true }); -} - -export function encrypted_format_dialog(client, block) { - return format_dialog_internal(client, block, { is_encrypted: true }); -} - function find_root_fsys_block() { const root = client.anaconda?.mount_point_prefix || "/"; for (const p in client.blocks) { @@ -104,14 +92,14 @@ function find_root_fsys_block() { return null; } -function format_dialog_internal(client, block, options) { - const { start, size, enable_dos_extended, add_encryption } = options; +export function format_dialog(block, options) { + const { free_spaces, enable_dos_extended, add_encryption } = options || { }; const is_already_encrypted = options.is_encrypted; const block_part = client.blocks_part[block.path]; const block_ptable = client.blocks_ptable[block.path] || client.blocks_ptable[block_part?.Table]; const content_block = block.IdUsage == "crypto" ? client.blocks_cleartext[block.path] : block; - const create_partition = (start !== undefined); + const create_partition = (free_spaces !== undefined); let title; if (add_encryption) @@ -282,18 +270,20 @@ function format_dialog_internal(client, block, options) { ]; } + let max_size = 0; + if (create_partition) + max_size = Math.max(...free_spaces.map(f => f.size)); + dialog_open({ Title: title, Teardown: TeardownMessage(usage), Fields: [ SizeSlider("size", _("Size"), { - value: size, - max: size, + value: max_size, + max: max_size, round: 1024 * 1024, - visible: function () { - return create_partition; - } + visible: () => create_partition, }), SelectOne("type", _("Type"), { @@ -497,6 +487,13 @@ function format_dialog_internal(client, block, options) { function format() { if (create_partition) { + let start = free_spaces[0].start; + for (const fs of free_spaces) { + if (fs.size >= vals.size) { + start = fs.start; + break; + } + } if (type == "dos-extended") return block_ptable.CreatePartition(start, vals.size, "0x05", "", { }); else diff --git a/pkg/storaged/partitions/partition-table.jsx b/pkg/storaged/partitions/partition-table.jsx index 86ea19600f6d..3d5484eecc41 100644 --- a/pkg/storaged/partitions/partition-table.jsx +++ b/pkg/storaged/partitions/partition-table.jsx @@ -32,7 +32,7 @@ import { make_partition_card, delete_partition } from "./partition.jsx"; const _ = cockpit.gettext; -function make_partition_pages(parent, block) { +function make_partition_pages(parent, block, partitions) { const block_ptable = client.blocks_ptable[block.path]; let counter = 0; @@ -45,8 +45,7 @@ function make_partition_pages(parent, block) { actions: [ { title: _("Create partition"), - action: () => format_dialog(client, block.path, start, size, - enable_dos_extended), + action: () => format_dialog(block, { free_spaces: [{ start, size }], enable_dos_extended }), } ], }); @@ -80,12 +79,24 @@ function make_partition_pages(parent, block) { } } - process_partitions(parent, get_partitions(client, block), - block_ptable.Type == 'dos'); + process_partitions(parent, partitions, block_ptable.Type == 'dos'); +} + +function get_free_spaces(partitions) { + let result = []; + for (const p of partitions) { + if (p.type == 'free') + result.push({ start: p.start, size: p.size }); + else if (p.type == 'container') + result = result.concat(get_free_spaces(p.partitions)); + } + return result; } export function make_partition_table_page(parent, block, next_card) { const block_ptable = client.blocks_ptable[block.path]; + const partitions = get_partitions(client, block); + const free_spaces = get_free_spaces(partitions); const parts_card = new_card({ title: (block_ptable.Type @@ -94,10 +105,18 @@ export function make_partition_table_page(parent, block, next_card) { next: next_card, component: PartitionsCard, props: { }, + actions: [ + { + title: _("Create partition"), + action: () => format_dialog(block, { free_spaces, enable_dos_extended: false }), + primary: true, + excuse: free_spaces.length == 0 ? _("No free space") : null, + }, + ], }); const p = new_page(parent, parts_card, { sorted: false }); - make_partition_pages(p, block); + make_partition_pages(p, block, partitions); } const PartitionsCard = ({ card }) => { From 138a1e7bf0dc5f63ecbf7caa7f2d92b07211b3c7 Mon Sep 17 00:00:00 2001 From: Marius Vollmer Date: Fri, 5 Apr 2024 17:35:05 +0300 Subject: [PATCH 10/15] storage: Move swap creation out of filesystem format dialog --- pkg/storaged/block/actions.jsx | 20 +++--- pkg/storaged/block/format-dialog.jsx | 28 +------- pkg/storaged/swap/format-dialog.jsx | 98 ++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 35 deletions(-) create mode 100644 pkg/storaged/swap/format-dialog.jsx diff --git a/pkg/storaged/block/actions.jsx b/pkg/storaged/block/actions.jsx index b95d51b2e0b8..f5e7f187d2d5 100644 --- a/pkg/storaged/block/actions.jsx +++ b/pkg/storaged/block/actions.jsx @@ -22,6 +22,7 @@ import client from "../client"; import { format_disk } from "./format-disk-dialog.jsx"; import { format_dialog } from "./format-dialog.jsx"; +import { format_swap_dialog } from "../swap/format-dialog.jsx"; import { erase_dialog } from "./erase-dialog.jsx"; const _ = cockpit.gettext; @@ -34,14 +35,6 @@ export function block_actions(block, kind) { const actions = []; if (client.blocks_available[block.path]) { - if (kind != "crypto") { - actions.push({ - title: _("Add encryption"), - action: () => format_dialog(block, { add_encryption: true }), - excuse, - }); - } - if (kind == "part") { actions.push({ title: _("Create partitions"), @@ -62,7 +55,16 @@ export function block_actions(block, kind) { actions.push({ title: _("Format as filesystem"), action: () => format_dialog(block), - primary: true, + excuse, + }); + actions.push({ + title: _("Format as swap"), + action: () => format_swap_dialog(block), + excuse, + }); + actions.push({ + title: _("Add encryption"), + action: () => format_dialog(block, { add_encryption: true }), excuse, }); } diff --git a/pkg/storaged/block/format-dialog.jsx b/pkg/storaged/block/format-dialog.jsx index 2b08f83589d4..b5a705c605d1 100644 --- a/pkg/storaged/block/format-dialog.jsx +++ b/pkg/storaged/block/format-dialog.jsx @@ -94,7 +94,7 @@ function find_root_fsys_block() { export function format_dialog(block, options) { const { free_spaces, enable_dos_extended, add_encryption } = options || { }; - const is_already_encrypted = options.is_encrypted; + const is_already_encrypted = options?.is_encrypted; const block_part = client.blocks_part[block.path]; const block_ptable = client.blocks_ptable[block.path] || client.blocks_ptable[block_part?.Table]; const content_block = block.IdUsage == "crypto" ? client.blocks_cleartext[block.path] : block; @@ -110,7 +110,7 @@ export function format_dialog(block, options) { title = cockpit.format(_("Format $0 as filesystem"), block_name(block)); function is_filesystem(vals) { - return !add_encryption && vals.type != "empty" && vals.type != "dos-extended" && vals.type != "biosboot" && vals.type != "swap"; + return !add_encryption && vals.type != "empty" && vals.type != "dos-extended" && vals.type != "biosboot"; } function add_fsys(storaged_name, entry) { @@ -129,7 +129,6 @@ export function format_dialog(block, options) { add_fsys("btrfs", { value: "btrfs", title: "BTRFS" }); add_fsys("vfat", { value: "vfat", title: "VFAT" }); add_fsys("ntfs", { value: "ntfs", title: "NTFS" }); - add_fsys("swap", { value: "swap", title: "Swap" }); if (client.in_anaconda_mode()) { if (block_ptable && block_ptable.Type == "gpt" && !client.anaconda.efi) add_fsys(true, { value: "biosboot", title: "BIOS boot partition" }); @@ -357,8 +356,6 @@ export function format_dialog(block, options) { if (trigger == "type") { if (dlg.get_value("type") == "empty") { dlg.update_actions({ Variants: action_variants_for_empty }); - } else if (dlg.get_value("type") == "swap") { - dlg.update_actions({ Variants: action_variants_for_swap }); } else { dlg.update_actions({ Variants: action_variants }); } @@ -385,12 +382,6 @@ export function format_dialog(block, options) { partition_type = "21686148-6449-6e6f-744e-656564454649"; } - if (type == "swap") { - partition_type = (block_ptable && block_ptable.Type == "dos" - ? "0x82" - : "0657fd6d-a4ab-43c4-84e5-0933c84b4f4f"); - } - const options = { 'tear-down': { t: 'b', v: true } }; @@ -471,17 +462,6 @@ export function format_dialog(block, options) { } } - if (type == "swap") { - config_items.push(["fstab", { - dir: { t: 'ay', v: encode_filename("none") }, - type: { t: 'ay', v: encode_filename("swap") }, - opts: { t: 'ay', v: encode_filename(mount_now ? "defaults" : "noauto") }, - freq: { t: 'i', v: 0 }, - passno: { t: 'i', v: 0 }, - "track-parents": { t: 'b', v: true } - }]); - } - if (config_items.length > 0) options["config-items"] = { t: 'a(sa{sv})', v: config_items }; @@ -545,10 +525,6 @@ export function format_dialog(block, options) { const block_fsys = await client.wait_for(() => block_fsys_for_block(path)); await client.mount_at(client.blocks[block_fsys.path], mount_point); } - if (type == "swap" && mount_now) { - const block_swap = await client.wait_for(() => block_swap_for_block(path)); - await block_swap.Start({}); - } if (is_encrypted(vals) && vals.type != "empty" && !mount_now && !client.in_anaconda_mode()) { const block_crypto = await client.wait_for(() => block_crypto_for_block(path)); await block_crypto.Lock({ }); diff --git a/pkg/storaged/swap/format-dialog.jsx b/pkg/storaged/swap/format-dialog.jsx new file mode 100644 index 000000000000..f963140f6ae5 --- /dev/null +++ b/pkg/storaged/swap/format-dialog.jsx @@ -0,0 +1,98 @@ +/* + * This file is part of Cockpit. + * + * Copyright (C) 2024 Red Hat, Inc. + * + * Cockpit is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * Cockpit is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Cockpit; If not, see . + */ + +import cockpit from "cockpit"; +import client from "../client.js"; + +import { + encode_filename, block_name, get_active_usage, teardown_active_usage, +} from "../utils.js"; + +import { + dialog_open, + BlockingMessage, TeardownMessage, + init_active_usage_processes +} from "../dialog.jsx"; + +import { job_progress_wrapper } from "../jobs-panel.jsx"; + +const _ = cockpit.gettext; + +export function format_swap_dialog(block) { + const usage = get_active_usage(client, block.path, _("format"), _("delete")); + + if (usage.Blocking) { + dialog_open({ + Title: cockpit.format(_("$0 is in use"), block_name(block)), + Body: BlockingMessage(usage) + }); + return; + } + + dialog_open({ + Title: cockpit.format(_("Format $0 as swap"), block_name(block)), + Teardown: TeardownMessage(usage), + Action: { + Variants: [ + { Title: _("Format and start") }, + { variant: "nostart", Title: _("Format only") } + ], + wrapper: job_progress_wrapper(client, block.path), + disable_on_error: usage.Teardown, + action: async function (vals) { + const config_items = [ + ["fstab", { + dir: { t: 'ay', v: encode_filename("none") }, + type: { t: 'ay', v: encode_filename("swap") }, + opts: { t: 'ay', v: encode_filename(vals.variant == "nostart" ? "noauto" : "defaults") }, + freq: { t: 'i', v: 0 }, + passno: { t: 'i', v: 0 }, + "track-parents": { t: 'b', v: true } + }] + ]; + + const options = { + 'tear-down': { t: 'b', v: true }, + 'config-items': { t: 'a(sa{sv})', v: config_items }, + }; + + await teardown_active_usage(client, usage); + await block.Format("swap", options); + + const block_part = client.blocks_part[block.path]; + if (block_part) { + const block_ptable = client.blocks_ptable[block_part.Table]; + const partition_type = + (block_ptable && block_ptable.Type == "dos" + ? "0x82" + : "0657fd6d-a4ab-43c4-84e5-0933c84b4f4f"); + await block_part.SetType(partition_type, {}); + } + + if (vals.varian != "nostart") { + const block_swap = await client.wait_for(() => client.blocks_swap[block.path]); + await block_swap.Start({}); + } + } + }, + Inits: [ + init_active_usage_processes(client, usage), + ] + }); +} From 0f5983cb66e089e19d6ea67930f347a5ad3e20a4 Mon Sep 17 00:00:00 2001 From: Marius Vollmer Date: Fri, 12 Apr 2024 10:27:58 +0300 Subject: [PATCH 11/15] storage: Remove "Overwrite" option in Erase dialog It's not a secure erase by any means. --- pkg/storaged/block/erase-dialog.jsx | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/pkg/storaged/block/erase-dialog.jsx b/pkg/storaged/block/erase-dialog.jsx index 38b14fbc17cd..2486ce42ef9b 100644 --- a/pkg/storaged/block/erase-dialog.jsx +++ b/pkg/storaged/block/erase-dialog.jsx @@ -49,14 +49,6 @@ export function erase_dialog(block) { dialog_open({ Title: cockpit.format(_("Erase $0"), block_name(block)), Teardown: TeardownMessage(usage), - Fields: [ - CheckBoxes("erase", _("Overwrite"), - { - fields: [ - { tag: "on", title: _("Overwrite existing data with zeros (slower)") } - ], - }), - ], Action: { Title: _("Erase"), Danger: _("This will erase all data on the storage device."), @@ -66,8 +58,6 @@ export function erase_dialog(block) { const options = { 'tear-down': { t: 'b', v: true } }; - if (vals.erase.on) - options.erase = { t: 's', v: "zero" }; await teardown_active_usage(client, usage); await block.Format("empty", options); From 7d35f124f5de099431251a4267135d4799bf212d Mon Sep 17 00:00:00 2001 From: Marius Vollmer Date: Mon, 17 Jun 2024 17:05:05 +0300 Subject: [PATCH 12/15] storage: Simplify "Initialize disk" dialog Use radio buttons, and only offer MBR when it will work. --- pkg/storaged/block/actions.jsx | 6 ++--- .../initialize-disk-dialog.jsx} | 26 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) rename pkg/storaged/{block/format-disk-dialog.jsx => partitions/initialize-disk-dialog.jsx} (72%) diff --git a/pkg/storaged/block/actions.jsx b/pkg/storaged/block/actions.jsx index f5e7f187d2d5..cae9017e85ff 100644 --- a/pkg/storaged/block/actions.jsx +++ b/pkg/storaged/block/actions.jsx @@ -20,7 +20,7 @@ import cockpit from "cockpit"; import client from "../client"; -import { format_disk } from "./format-disk-dialog.jsx"; +import { initialize_disk_dialog } from "../partitions/initialize-disk-dialog.jsx"; import { format_dialog } from "./format-dialog.jsx"; import { format_swap_dialog } from "../swap/format-dialog.jsx"; import { erase_dialog } from "./erase-dialog.jsx"; @@ -37,8 +37,8 @@ export function block_actions(block, kind) { if (client.blocks_available[block.path]) { if (kind == "part") { actions.push({ - title: _("Create partitions"), - action: () => format_disk(block), + title: _("Initialize for partitions"), + action: () => initialize_disk_dialog(block), primary: true, excuse, }); diff --git a/pkg/storaged/block/format-disk-dialog.jsx b/pkg/storaged/partitions/initialize-disk-dialog.jsx similarity index 72% rename from pkg/storaged/block/format-disk-dialog.jsx rename to pkg/storaged/partitions/initialize-disk-dialog.jsx index 11a4e467a0c3..b0e1d4d2a1c1 100644 --- a/pkg/storaged/block/format-disk-dialog.jsx +++ b/pkg/storaged/partitions/initialize-disk-dialog.jsx @@ -22,7 +22,7 @@ import client from "../client"; import { dialog_open, - SelectOne, + SelectOneRadioVertical, BlockingMessage, TeardownMessage, init_teardown_usage } from "../dialog.jsx"; @@ -31,8 +31,8 @@ import { job_progress_wrapper } from "../jobs-panel.jsx"; const _ = cockpit.gettext; -export function format_disk(block) { - const usage = get_active_usage(client, block.path, _("initialize"), _("delete")); +export function initialize_disk_dialog(block) { + const usage = get_active_usage(client, block.path, _("write partition table"), _("delete")); if (usage.Blocking) { dialog_open({ @@ -42,24 +42,24 @@ export function format_disk(block) { return; } + const offer_mbr = block.Size < 2 * 1024 * 1024 * 1024 * 1024; // 2 TiB + dialog_open({ - Title: cockpit.format(_("Create partitions on $0"), block_name(block)), + Title: cockpit.format(_("Initialize $0 for partitions"), block_name(block)), Teardown: TeardownMessage(usage), Fields: [ - SelectOne("type", _("Type"), + SelectOneRadioVertical("type", _("Type"), { value: "gpt", choices: [ - { value: "dos", title: _("Compatible with all systems and devices (MBR)") }, - { - value: "gpt", - title: _("Compatible with modern system and hard disks > 2TB (GPT)") - }, - ] + { value: "gpt", title: _("Modern (GPT)") }, + { value: "dos", title: _("Legacy (MBR)") }, + ], + visible: () => offer_mbr, }), ], Action: { - Title: _("Create partition table"), + Title: _("Initialize for partitions"), wrapper: job_progress_wrapper(client, block.path), disable_on_error: usage.Teardown, action: async function (vals) { @@ -68,7 +68,7 @@ export function format_disk(block) { }; await teardown_active_usage(client, usage); - await block.Format(vals.type, options); + await block.Format(offer_mbr ? vals.type : "gpt", options); await reload_systemd(); } }, From 441df7c5b415da190ea29f37ac61668a3735441d Mon Sep 17 00:00:00 2001 From: Marius Vollmer Date: Fri, 12 Apr 2024 11:14:04 +0300 Subject: [PATCH 13/15] storage: Polish encryption actions and options a bit --- pkg/storaged/block/actions.jsx | 12 ++- pkg/storaged/block/format-dialog.jsx | 105 +++++++++++++-------------- 2 files changed, 58 insertions(+), 59 deletions(-) diff --git a/pkg/storaged/block/actions.jsx b/pkg/storaged/block/actions.jsx index cae9017e85ff..5e48676ecc44 100644 --- a/pkg/storaged/block/actions.jsx +++ b/pkg/storaged/block/actions.jsx @@ -46,9 +46,13 @@ export function block_actions(block, kind) { if (kind == "crypto") { actions.push({ - title: _("Format cleartext device"), + title: _("Format as encrypted filesystem"), action: () => format_dialog(block, { is_encrypted: true }), - primary: true, + excuse, + }); + actions.push({ + title: _("Format as encrypted swap"), + action: () => format_swap_dialog(block), excuse, }); } else { @@ -63,14 +67,14 @@ export function block_actions(block, kind) { excuse, }); actions.push({ - title: _("Add encryption"), + title: _("Format with encryption only"), action: () => format_dialog(block, { add_encryption: true }), excuse, }); } } else { actions.push({ - title: kind == "crypto" ? _("Erase cleartext device") : _("Erase"), + title: kind == "crypto" ? _("Erase encrypted device") : _("Erase"), action: () => erase_dialog(block), danger: true, excuse, diff --git a/pkg/storaged/block/format-dialog.jsx b/pkg/storaged/block/format-dialog.jsx index b5a705c605d1..30fa19c0afc9 100644 --- a/pkg/storaged/block/format-dialog.jsx +++ b/pkg/storaged/block/format-dialog.jsx @@ -30,7 +30,7 @@ import { import { dialog_open, - TextInput, PassInput, CheckBoxes, SelectOne, SizeSlider, + TextInput, PassInput, CheckBoxes, SelectOne, SelectOneRadio, SizeSlider, BlockingMessage, TeardownMessage, init_teardown_usage } from "../dialog.jsx"; @@ -252,13 +252,8 @@ export function format_dialog(block, options) { { tag: "nomount", Title: create_partition ? _("Create") : _("Format") } ]; - let action_variants_for_swap = [ - { tag: null, Title: create_partition ? _("Create and start") : _("Format and start") }, - { tag: "nomount", Title: create_partition ? _("Create only") : _("Format only") } - ]; - if (client.in_anaconda_mode()) { - action_variants = action_variants_for_swap = [ + action_variants = [ { tag: "nomount", Title: create_partition ? _("Create") : _("Format") } ]; } @@ -277,6 +272,12 @@ export function format_dialog(block, options) { Title: title, Teardown: TeardownMessage(usage), Fields: [ + SelectOne("type", create_partition ? _("Format") : _("Type"), + { + value: default_type, + choices: filesystem_options, + visible: () => !add_encryption, + }), SizeSlider("size", _("Size"), { value: max_size, @@ -284,13 +285,7 @@ export function format_dialog(block, options) { round: 1024 * 1024, visible: () => create_partition, }), - SelectOne("type", _("Type"), - { - value: default_type, - choices: filesystem_options, - visible: () => !add_encryption, - }), - TextInput("name", _("Name"), + TextInput("name", _("Volume label"), { value: content_block?.IdLabel, validate: (name, vals) => validate_fsys_label(name, vals.type), @@ -307,47 +302,47 @@ export function format_dialog(block, options) { variant == "nomount"); } }), - SelectOne("crypto", _("Encryption"), - { - choices: crypto_types, - value: default_crypto_type, - visible: vals => vals.type != "dos-extended" && vals.type != "biosboot" && vals.type != "efi" && vals.type != "empty" && !is_already_encrypted, - nested_fields: [ - PassInput("passphrase", _("Passphrase"), - { - validate: function (phrase, vals) { - if (phrase === "") - return _("Passphrase cannot be empty"); - }, - visible: is_encrypted, - new_password: true - }), - PassInput("passphrase2", _("Confirm"), - { - validate: function (phrase2, vals) { - if (phrase2 != vals.passphrase) - return _("Passphrases do not match"); - }, - visible: is_encrypted, - new_password: true - }), - CheckBoxes("store_passphrase", "", - { - visible: is_encrypted, - value: { - on: false, - }, - fields: [ - { title: _("Store passphrase"), tag: "on" } - ] - }), - TextInput("crypto_options", _("Encryption options"), - { - visible: is_encrypted, - value: crypto_extra_options - }) - ] - }), + SelectOneRadio("crypto", _("Encryption"), + { + choices: crypto_types, + value: default_crypto_type, + visible: vals => vals.type != "dos-extended" && vals.type != "biosboot" && vals.type != "efi" && vals.type != "empty" && !is_already_encrypted, + nested_fields: [ + PassInput("passphrase", _("Passphrase"), + { + validate: function (phrase, vals) { + if (phrase === "") + return _("Passphrase cannot be empty"); + }, + visible: is_encrypted, + new_password: true + }), + PassInput("passphrase2", _("Confirm"), + { + validate: function (phrase2, vals) { + if (phrase2 != vals.passphrase) + return _("Passphrases do not match"); + }, + visible: is_encrypted, + new_password: true + }), + CheckBoxes("store_passphrase", "", + { + visible: is_encrypted, + value: { + on: false, + }, + fields: [ + { title: _("Store passphrase"), tag: "on" } + ] + }), + TextInput("crypto_options", _("Encryption options"), + { + visible: is_encrypted, + value: crypto_extra_options + }) + ] + }), at_boot_input(at_boot, is_filesystem), mount_options(opt_ro, extra_options, is_filesystem), ], From 5875fe9c99c14768f1149f626f87759df0f7f86b Mon Sep 17 00:00:00 2001 From: Marius Vollmer Date: Mon, 17 Jun 2024 17:18:57 +0300 Subject: [PATCH 14/15] FIXUP - rebase conflicts --- pkg/storaged/block/erase-dialog.jsx | 4 ++-- pkg/storaged/block/format-dialog.jsx | 2 +- pkg/storaged/swap/format-dialog.jsx | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/storaged/block/erase-dialog.jsx b/pkg/storaged/block/erase-dialog.jsx index 2486ce42ef9b..b186658bdf84 100644 --- a/pkg/storaged/block/erase-dialog.jsx +++ b/pkg/storaged/block/erase-dialog.jsx @@ -28,7 +28,7 @@ import { dialog_open, CheckBoxes, BlockingMessage, TeardownMessage, - init_active_usage_processes + init_teardown_usage, } from "../dialog.jsx"; import { job_progress_wrapper } from "../jobs-panel.jsx"; @@ -64,7 +64,7 @@ export function erase_dialog(block) { } }, Inits: [ - init_active_usage_processes(client, usage), + init_teardown_usage(client, usage), ] }); } diff --git a/pkg/storaged/block/format-dialog.jsx b/pkg/storaged/block/format-dialog.jsx index 30fa19c0afc9..3748b7d3cb3b 100644 --- a/pkg/storaged/block/format-dialog.jsx +++ b/pkg/storaged/block/format-dialog.jsx @@ -534,7 +534,7 @@ export function format_dialog(block, options) { } }, Inits: [ - init_active_usage_processes(client, usage), + init_teardown_usage(client, usage), ] }); } diff --git a/pkg/storaged/swap/format-dialog.jsx b/pkg/storaged/swap/format-dialog.jsx index f963140f6ae5..2ff830cecd99 100644 --- a/pkg/storaged/swap/format-dialog.jsx +++ b/pkg/storaged/swap/format-dialog.jsx @@ -27,7 +27,7 @@ import { import { dialog_open, BlockingMessage, TeardownMessage, - init_active_usage_processes + init_teardown_usage, } from "../dialog.jsx"; import { job_progress_wrapper } from "../jobs-panel.jsx"; @@ -92,7 +92,7 @@ export function format_swap_dialog(block) { } }, Inits: [ - init_active_usage_processes(client, usage), + init_teardown_usage(client, usage), ] }); } From e372e56658d754ec8a21ac350fc65be3314da6f4 Mon Sep 17 00:00:00 2001 From: Marius Vollmer Date: Wed, 28 Aug 2024 11:40:21 +0300 Subject: [PATCH 15/15] storage: Omit "/dev/" prefix from device names everywhere --- pkg/storaged/legacy-vdo/legacy-vdo.jsx | 4 ++-- pkg/storaged/mdraid/mdraid-disk.jsx | 4 ++-- pkg/storaged/mdraid/mdraid.jsx | 4 ++-- pkg/storaged/pages.jsx | 4 ++-- pkg/storaged/partitions/initialize-disk-dialog.jsx | 5 +++-- pkg/storaged/utils.js | 8 ++++---- 6 files changed, 15 insertions(+), 14 deletions(-) diff --git a/pkg/storaged/legacy-vdo/legacy-vdo.jsx b/pkg/storaged/legacy-vdo/legacy-vdo.jsx index 546c43466aab..7da4f6a62d43 100644 --- a/pkg/storaged/legacy-vdo/legacy-vdo.jsx +++ b/pkg/storaged/legacy-vdo/legacy-vdo.jsx @@ -25,7 +25,7 @@ import { Alert } from "@patternfly/react-core/dist/esm/components/Alert/index.js import { Card, CardBody } from '@patternfly/react-core/dist/esm/components/Card/index.js'; import { DescriptionList, DescriptionListDescription, DescriptionListGroup, DescriptionListTerm } from "@patternfly/react-core/dist/esm/components/DescriptionList/index.js"; -import { block_short_name, get_active_usage, teardown_active_usage, fmt_size, decode_filename, reload_systemd } from "../utils.js"; +import { block_name, get_active_usage, teardown_active_usage, fmt_size, decode_filename, reload_systemd } from "../utils.js"; import { dialog_open, SizeSlider, BlockingMessage, TeardownMessage, init_teardown_usage } from "../dialog.jsx"; @@ -140,7 +140,7 @@ export function make_legacy_vdo_page(parent, vdo, backing_block, next_card) { title: cockpit.format(_("VDO device $0"), vdo.name), next: next_card, page_location: ["vdo", vdo.name], - page_name: block_short_name(backing_block), + page_name: block_name(backing_block), page_size: vdo.logical_size, job_path: backing_block.path, component: VDODetails, diff --git a/pkg/storaged/mdraid/mdraid-disk.jsx b/pkg/storaged/mdraid/mdraid-disk.jsx index 803bdd171920..542f92256443 100644 --- a/pkg/storaged/mdraid/mdraid-disk.jsx +++ b/pkg/storaged/mdraid/mdraid-disk.jsx @@ -26,7 +26,7 @@ import { CardBody } from "@patternfly/react-core/dist/esm/components/Card/index. import { DescriptionList } from "@patternfly/react-core/dist/esm/components/DescriptionList/index.js"; import { StorageCard, StorageDescription, new_card, register_crossref } from "../pages.jsx"; -import { block_short_name, fmt_size, mdraid_name } from "../utils.js"; +import { block_name, fmt_size, mdraid_name } from "../utils.js"; const _ = cockpit.gettext; @@ -37,7 +37,7 @@ export function make_mdraid_disk_card(next, backing_block, content_block) { const disk_card = new_card({ title: _("MDRAID disk"), next, - location: mdraid_block ? block_short_name(mdraid_block) : (mdraid ? mdraid_name(mdraid) : null), + location: mdraid_block ? block_name(mdraid_block) : (mdraid ? mdraid_name(mdraid) : null), component: MDRaidDiskCard, props: { backing_block, content_block, mdraid } }); diff --git a/pkg/storaged/mdraid/mdraid.jsx b/pkg/storaged/mdraid/mdraid.jsx index a64780853cca..ed353eb3586f 100644 --- a/pkg/storaged/mdraid/mdraid.jsx +++ b/pkg/storaged/mdraid/mdraid.jsx @@ -34,7 +34,7 @@ import { } from "../pages.jsx"; import { make_block_page } from "../block/create-pages.jsx"; import { - block_short_name, mdraid_name, encode_filename, decode_filename, + block_name, mdraid_name, encode_filename, decode_filename, fmt_size, fmt_size_long, get_active_usage, teardown_active_usage, get_available_spaces, prepare_available_spaces, reload_systemd, should_ignore, @@ -203,7 +203,7 @@ export function make_mdraid_page(parent, mdraid) { title: _("MDRAID device"), next: null, page_location: ["mdraid", mdraid.UUID], - page_name: block ? block_short_name(block) : mdraid_name(mdraid), + page_name: block ? block_name(block) : mdraid_name(mdraid), page_icon: VolumeIcon, page_category: PAGE_CATEGORY_VIRTUAL, page_size: mdraid.Size, diff --git a/pkg/storaged/pages.jsx b/pkg/storaged/pages.jsx index 4eb782971f5c..102a921a0981 100644 --- a/pkg/storaged/pages.jsx +++ b/pkg/storaged/pages.jsx @@ -38,7 +38,7 @@ import { Spinner } from "@patternfly/react-core/dist/esm/components/Spinner/inde import { DescriptionListDescription, DescriptionListGroup, DescriptionListTerm } from "@patternfly/react-core/dist/esm/components/DescriptionList/index.js"; import { Flex, FlexItem } from "@patternfly/react-core/dist/esm/layouts/Flex/index.js"; -import { decode_filename, block_short_name, fmt_size } from "./utils.js"; +import { decode_filename, block_name, fmt_size } from "./utils.js"; import { StorageButton, StorageBarMenu, StorageMenuItem, StorageSize } from "./storage-controls.jsx"; import { MultipathAlert } from "./multipath.jsx"; import { JobsPanel } from "./jobs-panel.jsx"; @@ -228,7 +228,7 @@ export function new_card({ }) { if (page_block) { page_location = [block_location(page_block)]; - page_name = block_short_name(page_block); + page_name = block_name(page_block); page_size = page_block.Size; job_path = page_block.path; } diff --git a/pkg/storaged/partitions/initialize-disk-dialog.jsx b/pkg/storaged/partitions/initialize-disk-dialog.jsx index b0e1d4d2a1c1..0954d89cf48d 100644 --- a/pkg/storaged/partitions/initialize-disk-dialog.jsx +++ b/pkg/storaged/partitions/initialize-disk-dialog.jsx @@ -22,7 +22,7 @@ import client from "../client"; import { dialog_open, - SelectOneRadioVertical, + SelectOneRadio, BlockingMessage, TeardownMessage, init_teardown_usage } from "../dialog.jsx"; @@ -48,8 +48,9 @@ export function initialize_disk_dialog(block) { Title: cockpit.format(_("Initialize $0 for partitions"), block_name(block)), Teardown: TeardownMessage(usage), Fields: [ - SelectOneRadioVertical("type", _("Type"), + SelectOneRadio("type", _("Type"), { + vertical: true, value: "gpt", choices: [ { value: "gpt", title: _("Modern (GPT)") }, diff --git a/pkg/storaged/utils.js b/pkg/storaged/utils.js index 51b082fd1203..41fcc82ffe23 100644 --- a/pkg/storaged/utils.js +++ b/pkg/storaged/utils.js @@ -238,12 +238,12 @@ export function validate_fsys_label(label, type) { } } -export function block_name(block) { +export function block_long_name(block) { return decode_filename(block.PreferredDevice); } -export function block_short_name(block) { - return block_name(block).replace(/^\/dev\//, ""); +export function block_name(block) { + return block_long_name(block).replace(/^\/dev\//, ""); } export function mdraid_name(mdraid) { @@ -340,7 +340,7 @@ export function get_block_link_parts(client, path) { location = ["vdo", vdo.name]; link = cockpit.format(_("VDO device $0"), vdo.name); } else { - location = [block_short_name(block)]; + location = [block_name(block)]; if (client.drives[block.Drive]) link = drive_name(client.drives[block.Drive]); else