LCOV - code coverage report
Current view: top level - pkg/storaged/block - format-dialog.jsx Coverage Total Hit
Test: cockpit Lines: 91.9 % 520 478
Test Date: 2026-07-17 14:32:59

            Line data    Source code
       1              : /*
       2              :  * Copyright (C) 2016 Red Hat, Inc.
       3              :  * SPDX-License-Identifier: LGPL-2.1-or-later
       4              :  */
       5              : 
       6          113 : import cockpit from "cockpit";
       7              : import client from "../client.js";
       8              : 
       9              : import {
      10              :     edit_crypto_config, parse_options, unparse_options, extract_option,
      11              :     get_parent_blocks, is_netdev,
      12              :     decode_filename, encode_filename, block_name,
      13              :     get_active_usage, reload_systemd, teardown_active_usage,
      14              :     validate_fsys_label,
      15              : } from "../utils.js";
      16              : 
      17              : import {
      18              :     dialog_open,
      19              :     TextInput, PassInput, CheckBoxes, SelectOne, SizeSlider,
      20              :     BlockingMessage, TeardownMessage,
      21              :     init_teardown_usage
      22              : } from "../dialog.jsx";
      23              : 
      24              : import { get_fstab_config, is_valid_mount_point } from "../filesystem/utils.jsx";
      25              : import { init_existing_passphrase, unlock_with_type } from "../crypto/keyslots.jsx";
      26              : import { job_progress_wrapper } from "../jobs-panel.jsx";
      27              : import { at_boot_input, update_at_boot_input, mount_options } from "../filesystem/mounting-dialog.jsx";
      28              : import { remember_passphrase } from "../anaconda.jsx";
      29              : 
      30          113 : const _ = cockpit.gettext;
      31              : 
      32           51 : export function initial_tab_options(client, block, for_fstab) {
      33           51 :     const options = { };
      34              : 
      35              :     // "nofail" is the default for new filesystems with Cockpit so
      36              :     // that a failure to mount one of them will not prevent
      37              :     // Cockpit from starting.  This allows people to debug and fix
      38              :     // these failures with Cockpit itself.
      39              :     //
      40              :     // In Anaconda mode however, we don't make "nofail" the
      41              :     // default since people will be creating the core filesystems
      42              :     // like "/", "/var", etc.
      43              : 
      44           51 :     if (!client.in_anaconda_mode())
      45           45 :         options.nofail = true;
      46              : 
      47           51 :     get_parent_blocks(client, block.path).forEach(p => {
      48            1 :         if (is_netdev(client, p)) {
      49            1 :             options._netdev = true;
      50            1 :         }
      51              :         // HACK - https://bugzilla.redhat.com/show_bug.cgi?id=1589541
      52            0 :         if (client.legacy_vdo_overlay.find_by_block(client.blocks[p])) {
      53            0 :             options._netdev = true;
      54            0 :             options["x-systemd.device-timeout=0"] = true;
      55            0 :             if (for_fstab)
      56            0 :                 options["x-systemd.requires=vdo.service"] = true;
      57            0 :         }
      58           51 :     });
      59              : 
      60           51 :     return Object.keys(options).join(",");
      61           51 : }
      62              : 
      63           45 : export function initial_crypto_options(client, block) {
      64           45 :     return initial_tab_options(client, block, false);
      65           45 : }
      66              : 
      67           45 : export function initial_mount_options(client, block) {
      68           45 :     return initial_tab_options(client, block, true);
      69           45 : }
      70              : 
      71           46 : export function format_dialog(client, path, start, size, enable_dos_extended) {
      72           46 :     const block = client.blocks[path];
      73            6 :     if (block.IdUsage == "crypto") {
      74            6 :         cockpit.spawn(["cryptsetup", "luksDump", decode_filename(block.Device)], { superuser: "require" })
      75            6 :                 .then(output => {
      76            6 :                     if (output.indexOf("Keyslots:") >= 0) // This is what luksmeta-monitor-hack looks for
      77            0 :                         return 2;
      78              :                     else
      79            2 :                         return 1;
      80            6 :                 })
      81            0 :                 .catch(() => {
      82            0 :                     return false;
      83            0 :                 })
      84            6 :                 .then(version => {
      85            6 :                     return format_dialog_internal(client, path, start, size, enable_dos_extended, version);
      86            6 :                 });
      87            5 :     } else {
      88           45 :         return format_dialog_internal(client, path, start, size, enable_dos_extended);
      89           45 :     }
      90           46 : }
      91              : 
      92           45 : function find_root_fsys_block() {
      93            0 :     const root = client.anaconda?.mount_point_prefix || "/";
      94           45 :     for (const p in client.blocks) {
      95           45 :         if (client.blocks_fsys[p] && client.blocks_fsys[p].MountPoints.map(decode_filename).indexOf(root) >= 0)
      96           39 :             return client.blocks[p];
      97           37 :         if (client.blocks[p].Configuration.find(c => c[0] == "fstab" && decode_filename(c[1].dir.v) == root))
      98            1 :             return client.blocks[p];
      99           45 :     }
     100            6 :     return null;
     101           45 : }
     102              : 
     103           46 : function format_dialog_internal(client, path, start, size, enable_dos_extended, old_luks_version) {
     104           46 :     const block = client.blocks[path];
     105           46 :     const block_part = client.blocks_part[path];
     106            6 :     const block_ptable = client.blocks_ptable[path] || client.blocks_ptable[block_part?.Table];
     107            5 :     const content_block = block.IdUsage == "crypto" ? client.blocks_cleartext[path] : block;
     108              : 
     109           46 :     const offer_keep_keys = block.IdUsage == "crypto";
     110            5 :     const unlock_before_format = offer_keep_keys && (!content_block || content_block.ReadOnly);
     111              : 
     112           46 :     const create_partition = (start !== undefined);
     113              : 
     114           46 :     let title;
     115           46 :     if (create_partition)
     116            6 :         title = cockpit.format(_("Create partition on $0"), block_name(block));
     117              :     else
     118           40 :         title = cockpit.format(_("Format $0"), block_name(block));
     119              : 
     120           45 :     function is_filesystem(vals) {
     121           45 :         return vals.type != "empty" && vals.type != "dos-extended" && vals.type != "biosboot" && vals.type != "swap";
     122           45 :     }
     123              : 
     124           46 :     function add_fsys(storaged_name, entry) {
     125           46 :         if (storaged_name === true ||
     126           46 :             (client.fsys_info && client.fsys_info[storaged_name] && client.fsys_info[storaged_name].can_format)) {
     127           46 :             filesystem_options.push(entry);
     128           46 :         }
     129           46 :     }
     130              : 
     131           46 :     const filesystem_options = [];
     132           46 :     add_fsys("xfs", { value: "xfs", title: "XFS" });
     133           46 :     add_fsys("ext4", { value: "ext4", title: "EXT4" });
     134           46 :     if (client.features.btrfs)
     135           46 :         add_fsys("btrfs", { value: "btrfs", title: "BTRFS" });
     136           46 :     add_fsys("vfat", { value: "vfat", title: "VFAT" });
     137           46 :     add_fsys("ntfs", { value: "ntfs", title: "NTFS" });
     138           46 :     add_fsys("swap", { value: "swap", title: "Swap" });
     139            6 :     if (client.in_anaconda_mode()) {
     140            3 :         if (block_ptable && block_ptable.Type == "gpt" && !client.anaconda.efi)
     141            2 :             add_fsys(true, { value: "biosboot", title: "BIOS boot partition" });
     142            3 :         if (block_ptable && client.anaconda.efi)
     143            1 :             add_fsys(true, { value: "efi", title: "EFI system partition" });
     144            6 :     }
     145           46 :     add_fsys(true, { value: "empty", title: _("No filesystem") });
     146           12 :     if (create_partition && enable_dos_extended)
     147            2 :         add_fsys(true, { value: "dos-extended", title: _("Extended partition") });
     148              : 
     149           42 :     function is_supported(type) {
     150           42 :         return filesystem_options.find(o => o.value == type);
     151           42 :     }
     152              : 
     153           46 :     let default_type = null;
     154           11 :     if (content_block?.IdUsage == "filesystem" && is_supported(content_block.IdType))
     155            9 :         default_type = content_block.IdType;
     156           45 :     else {
     157           45 :         const root_block = find_root_fsys_block();
     158           40 :         if (root_block && is_supported(root_block.IdType)) {
     159           40 :             default_type = root_block.IdType;
     160            1 :         } else if (client.anaconda?.default_fsys_type && is_supported(client.anaconda.default_fsys_type)) {
     161            1 :             default_type = client.anaconda.default_fsys_type;
     162            0 :         } else {
     163            5 :             default_type = "ext4";
     164            5 :         }
     165           45 :     }
     166              : 
     167           45 :     function is_encrypted(vals) {
     168           45 :         return vals.crypto && vals.crypto !== "none";
     169           45 :     }
     170              : 
     171           46 :     function add_crypto_type(value, title, recommended) {
     172           46 :         if ((client.manager.SupportedEncryptionTypes && client.manager.SupportedEncryptionTypes.indexOf(value) != -1) ||
     173            0 :             value == "luks1") {
     174           46 :             crypto_types.push({
     175           46 :                 value,
     176           46 :                 title: title + (recommended ? " " + _("(recommended)") : "")
     177           46 :             });
     178           46 :         }
     179           46 :     }
     180              : 
     181           46 :     const crypto_types = [{ value: "none", title: _("No encryption") }];
     182            6 :     if (offer_keep_keys) {
     183            6 :         if (old_luks_version)
     184            6 :             crypto_types.push({
     185            6 :                 value: " keep",
     186            6 :                 title: cockpit.format(_("Reuse existing encryption ($0)"), "LUKS" + old_luks_version)
     187            0 :             });
     188              :         else
     189            0 :             crypto_types.push({ value: " keep", title: _("Reuse existing encryption") });
     190            6 :     }
     191           46 :     add_crypto_type("luks1", "LUKS1", false);
     192           46 :     add_crypto_type("luks2", "LUKS2", true);
     193              : 
     194            6 :     const usage = get_active_usage(client, create_partition ? null : path, _("format"), _("delete"));
     195              : 
     196            1 :     if (usage.Blocking) {
     197            1 :         dialog_open({
     198            1 :             Title: cockpit.format(_("$0 is in use"), block_name(block)),
     199            1 :             Body: BlockingMessage(usage)
     200            1 :         });
     201            1 :         return;
     202            1 :     }
     203              : 
     204           10 :     const crypto_config = block.Configuration.find(c => c[0] == "crypttab");
     205           45 :     let crypto_options;
     206            5 :     if (crypto_config) {
     207            5 :         crypto_options = (decode_filename(crypto_config[1].options.v)
     208            5 :                 .split(",")
     209            5 :                 .filter(function (s) { return s.indexOf("x-parent") !== 0 })
     210            5 :                 .join(","));
     211            5 :     } else {
     212           45 :         crypto_options = initial_crypto_options(client, block);
     213           45 :     }
     214              : 
     215           45 :     const crypto_split_options = parse_options(crypto_options);
     216           45 :     extract_option(crypto_split_options, "noauto");
     217           45 :     extract_option(crypto_split_options, "nofail");
     218           45 :     extract_option(crypto_split_options, "_netdev");
     219           45 :     extract_option(crypto_split_options, "readonly");
     220           45 :     extract_option(crypto_split_options, "read-only");
     221           45 :     const crypto_extra_options = unparse_options(crypto_split_options);
     222              : 
     223           45 :     let [, old_dir, old_opts] = get_fstab_config(block, true,
     224           45 :                                                  content_block?.IdType == "btrfs"
     225            1 :                                                      ? { pathname: "/", id: 5 }
     226           45 :                                                      : undefined);
     227           46 :     if (old_opts == undefined)
     228           45 :         old_opts = initial_mount_options(client, block);
     229              : 
     230           45 :     old_dir = client.strip_mount_point_prefix(old_dir);
     231           45 :     if (old_dir === false)
     232            0 :         return Promise.reject(_("This device can not be used for the installation target."));
     233              : 
     234              :     // Strip out btrfs subvolume mount options
     235           41 :     const split_options = parse_options(old_opts).filter(opt => !(opt.startsWith('subvol=') || opt.startsWith('subvolid=')));
     236           45 :     extract_option(split_options, "noauto");
     237           45 :     const opt_ro = extract_option(split_options, "ro");
     238           45 :     const opt_never_auto = extract_option(split_options, "x-cockpit-never-auto");
     239           45 :     const opt_nofail = extract_option(split_options, "nofail");
     240           45 :     const opt_netdev = extract_option(split_options, "_netdev");
     241           45 :     const extra_options = unparse_options(split_options);
     242              : 
     243           45 :     let existing_passphrase_type = null;
     244              : 
     245           45 :     let at_boot;
     246           45 :     if (opt_never_auto)
     247            1 :         at_boot = "never";
     248           45 :     else if (opt_netdev)
     249            1 :         at_boot = "netdev";
     250           44 :     else if (opt_nofail)
     251            1 :         at_boot = "nofail";
     252              :     else
     253            7 :         at_boot = "local";
     254              : 
     255           45 :     let action_variants = [
     256            6 :         { tag: null, Title: create_partition ? _("Create and mount") : _("Format and mount") },
     257            6 :         { tag: "nomount", Title: create_partition ? _("Create only") : _("Format only") }
     258           46 :     ];
     259              : 
     260           46 :     const action_variants_for_empty = [
     261            6 :         { tag: "nomount", Title: create_partition ? _("Create") : _("Format") }
     262           46 :     ];
     263              : 
     264           46 :     let action_variants_for_swap = [
     265            6 :         { tag: null, Title: create_partition ? _("Create and start") : _("Format and start") },
     266            6 :         { tag: "nomount", Title: create_partition ? _("Create only") : _("Format only") }
     267           46 :     ];
     268              : 
     269            6 :     if (client.in_anaconda_mode()) {
     270            6 :         action_variants = action_variants_for_swap = [
     271            3 :             { tag: "nomount", Title: create_partition ? _("Create") : _("Format") }
     272            6 :         ];
     273            6 :     }
     274              : 
     275           45 :     const dlg = dialog_open({
     276           45 :         Title: title,
     277           45 :         Teardown: TeardownMessage(usage),
     278           45 :         Fields: [
     279           45 :             TextInput("name", _("Name"),
     280           45 :                       {
     281           45 :                           value: content_block?.IdLabel,
     282           37 :                           validate: (name, vals) => validate_fsys_label(name, vals.type),
     283           46 :                           visible: is_filesystem
     284           46 :                       }),
     285           46 :             TextInput("mount_point", _("Mount point"),
     286           46 :                       {
     287           46 :                           visible: is_filesystem,
     288           45 :                           value: old_dir || "",
     289           37 :                           validate: (val, values, variant) => {
     290           37 :                               return is_valid_mount_point(client,
     291           37 :                                                           block,
     292           37 :                                                           client.add_mount_point_prefix(val),
     293           37 :                                                           variant == "nomount");
     294           37 :                           }
     295           46 :                       }),
     296           46 :             SelectOne("type", _("Type"),
     297           46 :                       {
     298           46 :                           value: default_type,
     299           46 :                           choices: filesystem_options
     300           46 :                       }),
     301           46 :             SizeSlider("size", _("Size"),
     302           46 :                        {
     303           46 :                            value: size,
     304           46 :                            max: size,
     305           46 :                            round: 1024 * 1024,
     306           45 :                            visible: function () {
     307           45 :                                return create_partition;
     308           45 :                            }
     309           46 :                        }),
     310           46 :             CheckBoxes("erase", _("Overwrite"),
     311           46 :                        {
     312           46 :                            fields: [
     313           46 :                                { tag: "on", title: _("Overwrite existing data with zeros (slower)") }
     314           46 :                            ],
     315           46 :                        }),
     316           46 :             SelectOne("crypto", _("Encryption"),
     317           46 :                       {
     318           46 :                           choices: crypto_types,
     319            5 :                           value: offer_keep_keys ? " keep" : "none",
     320           45 :                           visible: vals => vals.type != "dos-extended" && vals.type != "biosboot" && vals.type != "efi",
     321           46 :                           nested_fields: [
     322           46 :                               PassInput("passphrase", _("Passphrase"),
     323           46 :                                         {
     324           16 :                                             validate: function (phrase, vals) {
     325           16 :                                                 if (vals.crypto != " keep" && phrase === "")
     326            0 :                                                     return _("Passphrase cannot be empty");
     327           16 :                                             },
     328           17 :                                             visible: vals => is_encrypted(vals) && vals.crypto != " keep",
     329           46 :                                             new_password: true
     330           46 :                                         }),
     331           46 :                               PassInput("passphrase2", _("Confirm"),
     332           46 :                                         {
     333           16 :                                             validate: function (phrase2, vals) {
     334           16 :                                                 if (vals.crypto != " keep" && phrase2 != vals.passphrase)
     335            0 :                                                     return _("Passphrases do not match");
     336           16 :                                             },
     337           17 :                                             visible: vals => is_encrypted(vals) && vals.crypto != " keep",
     338           46 :                                             new_password: true
     339           46 :                                         }),
     340           46 :                               CheckBoxes("store_passphrase", "",
     341           46 :                                          {
     342           17 :                                              visible: vals => is_encrypted(vals) && vals.crypto != " keep",
     343           46 :                                              value: {
     344           46 :                                                  on: false,
     345           46 :                                              },
     346           46 :                                              fields: [
     347           46 :                                                  { title: _("Store passphrase"), tag: "on" }
     348           46 :                                              ]
     349           46 :                                          }),
     350           46 :                               PassInput("old_passphrase", _("Passphrase"),
     351           46 :                                         {
     352            3 :                                             validate: function (phrase) {
     353            3 :                                                 if (phrase === "")
     354            0 :                                                     return _("Passphrase cannot be empty");
     355            3 :                                             },
     356            6 :                                             visible: vals => vals.crypto == " keep" && vals.needs_explicit_passphrase,
     357           46 :                                             explanation: _("The disk needs to be unlocked before formatting. Please provide an existing passphrase.")
     358           46 :                                         }),
     359           46 :                               TextInput("crypto_options", _("Encryption options"),
     360           46 :                                         {
     361           46 :                                             visible: is_encrypted,
     362           46 :                                             value: crypto_extra_options
     363           46 :                                         })
     364           46 :                           ]
     365           46 :                       }),
     366           46 :             at_boot_input(at_boot, is_filesystem),
     367           46 :             mount_options(opt_ro, extra_options, is_filesystem),
     368           46 :         ],
     369           45 :         update: function (dlg, vals, trigger) {
     370           45 :             update_at_boot_input(dlg, vals, trigger);
     371           44 :             if (trigger == "type") {
     372            5 :                 if (dlg.get_value("type") == "empty") {
     373            5 :                     dlg.update_actions({ Variants: action_variants_for_empty });
     374            0 :                 } else if (dlg.get_value("type") == "swap") {
     375            3 :                     dlg.update_actions({ Variants: action_variants_for_swap });
     376            0 :                 } else {
     377           38 :                     dlg.update_actions({ Variants: action_variants });
     378           38 :                 }
     379            1 :                 if (vals.type == "efi" && !vals.mount_point)
     380            1 :                     dlg.set_values({ mount_point: "/boot/efi" });
     381           16 :             } else if (trigger == "crypto") {
     382           16 :                 if (vals.crypto != "none" && vals.crypto != " keep")
     383           16 :                     dlg.show_field("crypto_options");
     384           16 :             }
     385           45 :         },
     386           46 :         Action: {
     387           46 :             Variants: action_variants,
     388            6 :             Danger: (create_partition ? null : _("Formatting erases all data on a storage device.")),
     389            5 :             wrapper: job_progress_wrapper(client, block.path, client.blocks_cleartext[block.path]?.path),
     390           46 :             disable_on_error: usage.Teardown,
     391           44 :             action: function (vals) {
     392           44 :                 const mount_now = vals.variant != "nomount";
     393           44 :                 let type = vals.type;
     394           44 :                 let partition_type = "";
     395              : 
     396            1 :                 if (type == "efi") {
     397            1 :                     type = "vfat";
     398            0 :                     partition_type = block_ptable.Type == "dos" ? "0xEF" : "c12a7328-f81f-11d2-ba4b-00a0c93ec93b";
     399            1 :                 }
     400              : 
     401            1 :                 if (type == "biosboot") {
     402            1 :                     type = "empty";
     403            1 :                     partition_type = "21686148-6449-6e6f-744e-656564454649";
     404            1 :                 }
     405              : 
     406            3 :                 if (type == "swap") {
     407            1 :                     partition_type = (block_ptable && block_ptable.Type == "dos"
     408            0 :                         ? "0x82"
     409            3 :                         : "0657fd6d-a4ab-43c4-84e5-0933c84b4f4f");
     410            3 :                 }
     411              : 
     412           44 :                 const options = {
     413           44 :                     'tear-down': { t: 'b', v: true }
     414           44 :                 };
     415           44 :                 if (vals.erase.on)
     416            2 :                     options.erase = { t: 's', v: "zero" };
     417           44 :                 if (vals.name)
     418           21 :                     options.label = { t: 's', v: vals.name };
     419              : 
     420              :                 // HACK - https://bugzilla.redhat.com/show_bug.cgi?id=1516041
     421            0 :                 if (client.legacy_vdo_overlay.find_by_block(block)) {
     422            0 :                     options['no-discard'] = { t: 'b', v: true };
     423            0 :                 }
     424              : 
     425            5 :                 const keep_keys = is_encrypted(vals) && offer_keep_keys && vals.crypto == " keep";
     426              : 
     427           44 :                 const config_items = [];
     428           44 :                 let new_crypto_options;
     429           16 :                 if (is_encrypted(vals)) {
     430           16 :                     let opts = [];
     431           14 :                     if (is_filesystem(vals)) {
     432           12 :                         if (vals.mount_options?.ro)
     433            1 :                             opts.push("readonly");
     434            8 :                         if (!mount_now || vals.at_boot == "never")
     435            8 :                             opts.push("noauto");
     436           14 :                         if (vals.at_boot == "nofail")
     437            9 :                             opts.push("nofail");
     438           14 :                         if (vals.at_boot == "netdev")
     439            2 :                             opts.push("_netdev");
     440           14 :                     }
     441              : 
     442           16 :                     opts = opts.concat(parse_options(vals.crypto_options));
     443           16 :                     new_crypto_options = { t: 'ay', v: encode_filename(unparse_options(opts)) };
     444           16 :                     const item = {
     445           16 :                         options: new_crypto_options,
     446           16 :                         "track-parents": { t: 'b', v: true }
     447           16 :                     };
     448              : 
     449           16 :                     if (!keep_keys) {
     450            0 :                         if (vals.store_passphrase.on) {
     451            0 :                             item["passphrase-contents"] = { t: 'ay', v: encode_filename(vals.passphrase) };
     452            0 :                         } else {
     453           16 :                             item["passphrase-contents"] = { t: 'ay', v: encode_filename("") };
     454           16 :                         }
     455           16 :                         config_items.push(["crypttab", item]);
     456           16 :                         options["encrypt.passphrase"] = { t: 's', v: vals.passphrase };
     457           16 :                         options["encrypt.type"] = { t: 's', v: vals.crypto };
     458           16 :                     }
     459           16 :                 }
     460              : 
     461           44 :                 let mount_point;
     462              : 
     463           37 :                 if (is_filesystem(vals)) {
     464           37 :                     const mount_options = [];
     465            3 :                     if (!mount_now || vals.at_boot == "never") {
     466           16 :                         mount_options.push("noauto");
     467           16 :                     }
     468           33 :                     if (vals.mount_options?.ro)
     469            2 :                         mount_options.push("ro");
     470           37 :                     if (vals.at_boot == "never")
     471            2 :                         mount_options.push("x-cockpit-never-auto");
     472           37 :                     if (vals.at_boot == "nofail")
     473           29 :                         mount_options.push("nofail");
     474           37 :                     if (vals.at_boot == "netdev")
     475            3 :                         mount_options.push("_netdev");
     476           33 :                     if (vals.mount_options?.extra)
     477            0 :                         mount_options.push(vals.mount_options.extra);
     478           37 :                     if (type == "btrfs")
     479            6 :                         mount_options.push("subvol=/");
     480              : 
     481           37 :                     mount_point = vals.mount_point;
     482           37 :                     if (mount_point != "") {
     483           37 :                         if (mount_point[0] != "/")
     484            0 :                             mount_point = "/" + mount_point;
     485           37 :                         mount_point = client.add_mount_point_prefix(mount_point);
     486              : 
     487           37 :                         config_items.push(["fstab", {
     488           37 :                             dir: { t: 'ay', v: encode_filename(mount_point) },
     489           37 :                             type: { t: 'ay', v: encode_filename("auto") },
     490            1 :                             opts: { t: 'ay', v: encode_filename(mount_options.join(",") || "defaults") },
     491           37 :                             freq: { t: 'i', v: 0 },
     492           37 :                             passno: { t: 'i', v: 0 },
     493           37 :                             "track-parents": { t: 'b', v: true }
     494           37 :                         }]);
     495           37 :                     }
     496           37 :                 }
     497              : 
     498            3 :                 if (type == "swap") {
     499            3 :                     config_items.push(["fstab", {
     500            3 :                         dir: { t: 'ay', v: encode_filename("none") },
     501            3 :                         type: { t: 'ay', v: encode_filename("swap") },
     502            1 :                         opts: { t: 'ay', v: encode_filename(mount_now ? "defaults" : "noauto") },
     503            3 :                         freq: { t: 'i', v: 0 },
     504            3 :                         passno: { t: 'i', v: 0 },
     505            3 :                         "track-parents": { t: 'b', v: true }
     506            3 :                     }]);
     507            3 :                 }
     508              : 
     509           44 :                 if (config_items.length > 0)
     510           41 :                     options["config-items"] = { t: 'a(sa{sv})', v: config_items };
     511              : 
     512            5 :                 async function maybe_unlock() {
     513            5 :                     const content_block = client.blocks_cleartext[path];
     514            4 :                     if (content_block) {
     515            1 :                         if (content_block.ReadOnly) {
     516            1 :                             const block_crypto = client.blocks_crypto[path];
     517            1 :                             await block_crypto.Lock({});
     518            1 :                             await unlock_with_type(client, block, vals.old_passphrase, existing_passphrase_type, false);
     519            1 :                         }
     520            4 :                         return content_block;
     521            4 :                     }
     522              : 
     523            2 :                     try {
     524            2 :                         await unlock_with_type(client, block, vals.old_passphrase, existing_passphrase_type, false);
     525            2 :                         return client.blocks_cleartext[path];
     526            0 :                     } catch (error) {
     527            0 :                         dlg.set_values({ needs_explicit_passphrase: true });
     528            0 :                         throw error;
     529            0 :                     }
     530            5 :                 }
     531              : 
     532           44 :                 function format() {
     533           12 :                     if (create_partition) {
     534           12 :                         if (type == "dos-extended")
     535            1 :                             return block_ptable.CreatePartition(start, vals.size, "0x05", "", { });
     536              :                         else
     537           12 :                             return block_ptable.CreatePartitionAndFormat(start, vals.size, partition_type, "", { },
     538           12 :                                                                          type, options);
     539            0 :                     } else if (keep_keys) {
     540            5 :                         return (edit_crypto_config(block,
     541            5 :                                                    (config, commit) => {
     542            5 :                                                        config.options = new_crypto_options;
     543            5 :                                                        return commit();
     544            5 :                                                    })
     545            5 :                                 .then(() => maybe_unlock())
     546            5 :                                 .then(content_block => {
     547            5 :                                     return content_block.Format(type, options);
     548            5 :                                 }));
     549            5 :                     } else {
     550           37 :                         return block.Format(type, options)
     551           35 :                                 .then(() => {
     552            5 :                                     if (partition_type != "" && block_part)
     553            3 :                                         return block_part.SetType(partition_type, {});
     554           35 :                                 });
     555           37 :                     }
     556           44 :                 }
     557              : 
     558           23 :                 function block_fsys_for_block(path) {
     559            4 :                     if (keep_keys) {
     560            4 :                         const content_block = client.blocks_cleartext[path];
     561            4 :                         return client.blocks_fsys[content_block.path];
     562            4 :                     } else if (is_encrypted(vals))
     563            8 :                         return (client.blocks_cleartext[path] &&
     564            0 :                                 client.blocks_fsys[client.blocks_cleartext[path].path]);
     565              :                     else
     566           15 :                         return client.blocks_fsys[path];
     567           23 :                 }
     568              : 
     569            2 :                 function block_swap_for_block(path) {
     570            0 :                     if (keep_keys) {
     571            0 :                         const content_block = client.blocks_cleartext[path];
     572            0 :                         return client.blocks_swap[content_block.path];
     573            0 :                     } else if (is_encrypted(vals))
     574            1 :                         return (client.blocks_cleartext[path] &&
     575            0 :                                 client.blocks_swap[client.blocks_cleartext[path].path]);
     576              :                     else
     577            1 :                         return client.blocks_swap[path];
     578            2 :                 }
     579              : 
     580            5 :                 function block_crypto_for_block(path) {
     581            5 :                     return client.blocks_crypto[path];
     582            5 :                 }
     583              : 
     584           42 :                 async function maybe_mount(new_path) {
     585           35 :                     const path = new_path || block.path;
     586           42 :                     const new_block = await client.wait_for(() => client.blocks[path]);
     587              : 
     588           16 :                     if (is_encrypted(vals) && vals.passphrase)
     589           16 :                         remember_passphrase(new_block, vals.passphrase);
     590              : 
     591            1 :                     if (is_encrypted(vals) && is_filesystem(vals) && vals.mount_options?.ro) {
     592            1 :                         const block_crypto = await client.wait_for(() => block_crypto_for_block(path));
     593            1 :                         await block_crypto.Lock({});
     594            1 :                         if (vals.passphrase)
     595            1 :                             await block_crypto.Unlock(vals.passphrase, { "read-only": { t: "b", v: true } });
     596              :                         else
     597            1 :                             await unlock_with_type(client, block, vals.old_passphrase, existing_passphrase_type, true);
     598            1 :                     }
     599              : 
     600           23 :                     if (is_filesystem(vals) && mount_now) {
     601           23 :                         const block_fsys = await client.wait_for(() => block_fsys_for_block(path));
     602           23 :                         await client.mount_at(client.blocks[block_fsys.path], mount_point);
     603           23 :                     }
     604            2 :                     if (type == "swap" && mount_now) {
     605            2 :                         const block_swap = await client.wait_for(() => block_swap_for_block(path));
     606            2 :                         await block_swap.Start({});
     607            2 :                     }
     608            4 :                     if (is_encrypted(vals) && vals.type != "empty" && !mount_now && !client.in_anaconda_mode()) {
     609            4 :                         const block_crypto = await client.wait_for(() => block_crypto_for_block(path));
     610            4 :                         await block_crypto.Lock({ });
     611            4 :                     }
     612           42 :                 }
     613              : 
     614           44 :                 return teardown_active_usage(client, usage)
     615           44 :                         .then(reload_systemd)
     616           44 :                         .then(format)
     617           42 :                         .then(new_path => reload_systemd().then(() => new_path))
     618           44 :                         .then(maybe_mount);
     619           44 :             }
     620           46 :         },
     621           46 :         Inits: [
     622           46 :             init_teardown_usage(client, usage),
     623           46 :             unlock_before_format
     624            3 :                 ? init_existing_passphrase(block, true, type => { existing_passphrase_type = type })
     625           45 :                 : null
     626           46 :         ]
     627           46 :     });
     628           46 : }
        

Generated by: LCOV version 2.0-1