Skip to content

Commit d0fbc13

Browse files
committed
Add rd.kiwi.install.retain_last deployment option
Instructs an OEM installation to retain the contents of the last partition on the target disk. This setting is only useful if the last partition does not belong to the main OS e.g. an extra data partition added via the spare_part attribute in the type setup of the image description. The implementation also checks if the start address of the last partition on the target disk matches with the start adress of the image to be deployed. Only if they match the data on the last partition can be retained.
1 parent 203da3d commit d0fbc13

File tree

2 files changed

+196
-9
lines changed

2 files changed

+196
-9
lines changed

doc/source/concept_and_workflow/customize_the_boot_process.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,17 @@ the available kernel boot parameters for these modules:
222222
Note that options starting with `rd.kiwi` are not passed to avoid
223223
side effects.
224224

225+
``rd.kiwi.install.retain_last``
226+
Instructs an OEM installation to retain the contents of the
227+
last partition on the target disk. This setting is only useful
228+
if the last partition does not belong to the main OS e.g. an
229+
extra data partition added via the `spare_part` attribute in
230+
the type setup of the image description. The implementation
231+
also checks if the start address of the last partition on the
232+
target disk matches with the start adress of the image to be
233+
deployed. Only if they match the data on the last partition
234+
can be retained.
235+
225236
``rd.kiwi.oem.luks.reencrypt``
226237
For OEM LUKS2 encrypted disk images. If set, reencrypts the disk
227238
prior an eventual resize and therefore creates a new key pool and

dracut/modules.d/55kiwi-dump/kiwi-dump-image.sh

Lines changed: 185 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -330,15 +330,50 @@ function dump_image {
330330
local load_text="Loading ${image_basename}..."
331331
local title_text="Installation..."
332332
local dump
333+
local parttable
334+
local count_32k
335+
local image_size
336+
local count=0
337+
local block_size=32k
338+
339+
# can we dump this
340+
check_image_fits_target "${image_target}"
333341

342+
# select dump method
334343
if [ -n "${image_from_remote}" ];then
335344
dump=dump_remote_image
336345
else
337346
dump=dump_local_image
338347
fi
339348

340-
check_image_fits_target "${image_target}"
349+
# setup blocks and blocksize to retain last
350+
if getargbool 0 rd.kiwi.install.retain_last; then
351+
if [ -n "${image_from_remote}" ];then
352+
image_size=$((blocks * blocksize))
353+
parttable=$(
354+
fetch_remote_partition_table "${image_source}" "${image_size}"
355+
)
356+
else
357+
parttable=$(
358+
fetch_local_partition_table "${image_source}"
359+
)
360+
fi
361+
if compatible_to_retain "${parttable}" "${image_target}"; then
362+
count=$(get_disk_offset_retain_last_partition "${parttable}")
363+
fi
364+
if [ "${count}" -gt 0 ];then
365+
block_size=$(get_sector_size_from_table_dump "${parttable}")
366+
count_32k=$(
367+
optimize_count_for_32k_blocksize "${block_size}" "${count}"
368+
)
369+
if [ ! "${count}" = "${count_32k}" ];then
370+
count="${count_32k}"
371+
block_size=32k
372+
fi
373+
fi
374+
fi
341375

376+
# last chance to stop us
342377
if [ "${kiwi_oemunattended}" = "false" ];then
343378
local ack_dump_text="Destroying ALL data on ${image_target}, continue ?"
344379
if ! run_dialog --yesno "\"${ack_dump_text}\"" 7 80; then
@@ -347,48 +382,182 @@ function dump_image {
347382
fi
348383
fi
349384

385+
# deploy
350386
echo "${load_text} [${image_target}]..."
351387
if command -v pv &>/dev/null && [ "${kiwi_oemsilentinstall}" = "false" ]
352388
then
353389
# dump with dialog based progress information
354390
setup_progress_fifo ${progress}
355-
eval "${dump}" "${image_source}" "${image_target}" "${progress}" &
391+
eval \
392+
"${dump}" \
393+
"${image_source}" \
394+
"${image_target}" \
395+
"${count}" \
396+
"${block_size}" \
397+
"${progress}" \
398+
&
356399
run_progress_dialog "${load_text}" "${title_text}"
357400
else
358401
# dump with silently blocked console
359-
if ! eval "${dump}" "${image_source}" "${image_target}"; then
402+
if ! eval \
403+
"${dump}" \
404+
"${image_source}" \
405+
"${image_target}" \
406+
"${count}" \
407+
"${block_size}"
408+
then
360409
report_and_quit "Failed to install image"
361410
fi
362411
fi
412+
if [ "${count}" -gt 0 ]; then
413+
recreate_last_partition "${image_target}"
414+
fi
415+
}
416+
417+
function fetch_local_partition_table {
418+
local image_source=$1
419+
local parttable=/tmp/parttable
420+
sfdisk -d "${image_source}" > "${parttable}" 2>/dev/null
421+
echo "${parttable}"
422+
}
423+
424+
function fetch_remote_partition_table {
425+
local image_source=$1
426+
local image_size=$2
427+
local parttable=/tmp/parttable
428+
dd if=/dev/zero of=/tmp/table bs=1 count=0 seek="${image_size}" &>/dev/null
429+
fetch_file "${image_source}" 2>/dev/null | dd of=/tmp/table bs=512 count=1 conv=notrunc &>/dev/null
430+
sfdisk -d /tmp/table > "${parttable}" 2>/dev/null
431+
echo "${parttable}"
432+
}
433+
434+
function get_sector_size_from_table_dump {
435+
local parttable=$1
436+
sector_size=$(grep sector-size: "${parttable}" | cut -f2 -d:)
437+
echo "${sector_size}"
438+
}
439+
440+
function compatible_to_retain {
441+
local parttable=$1
442+
local image_target=$2
443+
local source_start
444+
local target_start
445+
source_start=$(
446+
tail -n 1 "${parttable}" | cut -f2 -d= | cut -f1 -d,
447+
)
448+
target_start=$(
449+
sfdisk -d "${image_target}" 2>/dev/null |\
450+
tail -n 1 | cut -f2 -d= | cut -f1 -d,
451+
)
452+
if [ -z "${source_start}" ] || [ -z "${target_start}" ];then
453+
# no partition information for either source or target
454+
# broken or net new deployment on empty disk
455+
touch /tmp/retain_not_applicable
456+
return 1
457+
fi
458+
if [ ! "${source_start}" = "${target_start}" ];then
459+
report_and_quit "Cannot retain partition, start address mismatch"
460+
fi
461+
return 0
462+
}
463+
464+
function get_disk_offset_retain_last_partition {
465+
local parttable=$1
466+
local next_to_last
467+
local start
468+
local size
469+
local offset
470+
next_to_last=$(tail -n 2 "${parttable}" | head -n 1)
471+
if [ -n "${next_to_last}" ];then
472+
start=$(echo "${next_to_last}" | cut -f2 -d= | cut -f1 -d,)
473+
size=$(echo "${next_to_last}" | cut -f3 -d= | cut -f1 -d,)
474+
offset=$((start + size))
475+
echo "${offset}"
476+
else
477+
echo 0
478+
fi
479+
}
480+
481+
function optimize_count_for_32k_blocksize {
482+
local block_size=$1
483+
local count=$2
484+
local dump_bytes
485+
dump_bytes=$((block_size * count))
486+
if [ $((${dump_bytes} % 32768)) -eq 0 ];then
487+
# dump_bytes is a multiple of 32k, use it for better I/O performance
488+
count=$((${dump_bytes} / 32768))
489+
fi
490+
echo "${count}"
491+
}
492+
493+
function recreate_last_partition {
494+
local image_target=$1
495+
local table_type
496+
table_type=$(get_partition_table_type "${image_target}")
497+
if [ "${table_type}" = "gpt" ];then
498+
relocate_gpt_at_end_of_disk "${image_target}"
499+
fi
500+
sfdisk -d "${image_target}" > /tmp/parttable 2>/dev/null
501+
head -n -1 /tmp/parttable > /tmp/parttable_1
502+
tail -n 1 /tmp/parttable > /tmp/parttable_2
503+
if [ "${table_type}" = "gpt" ];then
504+
sed -ie "s@\(/dev/.* : start=.*\), size=.*, \(type=.*, uuid=.*, name=\".*\"\)@\1, \2@" \
505+
/tmp/parttable_2
506+
else
507+
sed -ie "s@\(/dev/.* : start=.*\), size=.*, \(type=.*\)@\1, \2@" \
508+
/tmp/parttable_2
509+
fi
510+
cat /tmp/parttable_1 /tmp/parttable_2 > /tmp/parttable
511+
set_device_lock "${image_target}" \
512+
sfdisk -f "${image_target}" < /tmp/parttable
363513
}
364514

365515
function dump_local_image {
366516
local image_source=$1
367517
local image_target=$2
368-
local progress=$3
518+
local count=$3
519+
local block_size=$4
520+
local progress=$5
521+
if [ "${count}" -gt 0 ];then
522+
count="count=${count}"
523+
else
524+
unset count
525+
fi
526+
# shellcheck disable=SC2086
369527
if [ -e "${progress}" ];then
370528
(
371-
pv -n "${image_source}" | dd bs=32k of="${image_target}" &>/dev/null
529+
pv -n "${image_source}" |\
530+
dd bs="${block_size}" ${count} of="${image_target}" &>/dev/null
372531
) 2>"${progress}"
373532
else
374-
dd if="${image_source}" bs=32k of="${image_target}" &>/dev/null
533+
dd \
534+
if="${image_source}" bs="${block_size}" ${count} \
535+
of="${image_target}" &>/dev/null
375536
fi
376537
}
377538

378539
function dump_remote_image {
379540
local image_source=$1
380541
local image_target=$2
381-
local progress=$3
542+
local count=$3
543+
local block_size=$4
544+
local progress=$5
382545
local image_size
383546
image_size=$((blocks * blocksize))
547+
if [ "${count}" -gt 0 ];then
548+
count="count=${count}"
549+
else
550+
unset count
551+
fi
552+
# shellcheck disable=SC2086
384553
if [ -e "${progress}" ];then
385554
(
386555
fetch_file "${image_source}" "${image_size}" |\
387-
dd bs=32k of="${image_target}" &>/dev/null
556+
dd bs="${block_size}" ${count} of="${image_target}" &>/dev/null
388557
) 2>"${progress}"
389558
else
390559
fetch_file "${image_source}" |\
391-
dd bs=32k of="${image_target}" &>/dev/null
560+
dd bs="${block_size}" ${count} of="${image_target}" &>/dev/null
392561
fi
393562
}
394563

@@ -406,6 +575,13 @@ function check_image_integrity {
406575
# no verification wanted
407576
return
408577
fi
578+
if getargbool 0 rd.kiwi.install.retain_last; then
579+
if [ ! -e /tmp/retain_not_applicable ];then
580+
# no verification possible as only a portion of
581+
# the image got deployed intentionally
582+
return
583+
fi
584+
fi
409585
if command -v pv &>/dev/null && [ "${kiwi_oemsilentverify}" = "false" ]
410586
then
411587
# verify with dialog based progress information

0 commit comments

Comments
 (0)