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 : }
|