@@ -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,157 @@ 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
363412}
364413
414+ function fetch_local_partition_table {
415+ local image_source=$1
416+ local parttable=/tmp/parttable
417+ sfdisk -d " ${image_source} " > " ${parttable} " 2> /dev/null
418+ echo " ${parttable} "
419+ }
420+
421+ function fetch_remote_partition_table {
422+ local image_source=$1
423+ local image_size=$2
424+ local parttable=/tmp/parttable
425+ dd if=/dev/zero of=/tmp/table bs=1 count=0 seek=" ${image_size} " & > /dev/null
426+ fetch_file " ${image_source} " 2> /dev/null | dd of=/tmp/table bs=512 count=1 conv=notrunc & > /dev/null
427+ sfdisk -d /tmp/table > " ${parttable} " 2> /dev/null
428+ echo " ${parttable} "
429+ }
430+
431+ function get_sector_size_from_table_dump {
432+ local parttable=$1
433+ sector_size=$( grep sector-size: " ${parttable} " | cut -f2 -d:)
434+ echo " ${sector_size} "
435+ }
436+
437+ function compatible_to_retain {
438+ local parttable=$1
439+ local image_target=$2
440+ local source_start
441+ local target_start
442+ source_start=$(
443+ tail -n 1 " ${parttable} " | cut -f2 -d= | cut -f1 -d,
444+ )
445+ target_start=$(
446+ sfdisk -d " ${image_target} " 2> /dev/null | \
447+ tail -n 1 | cut -f2 -d= | cut -f1 -d,
448+ )
449+ if [ -z " ${source_start} " ] || [ -z " ${target_start} " ]; then
450+ # no partition information for either source or target
451+ # broken or net new deployment on empty disk
452+ touch /tmp/retain_not_applicable
453+ return 1
454+ fi
455+ if [ ! " ${source_start} " = " ${target_start} " ]; then
456+ report_and_quit " Cannot retain partition, start address mismatch"
457+ fi
458+ return 0
459+ }
460+
461+ function get_disk_offset_retain_last_partition {
462+ local parttable=$1
463+ local next_to_last
464+ local start
465+ local size
466+ local offset
467+ next_to_last=$( tail -n 2 " ${parttable} " | head -n 1)
468+ if [ -n " ${next_to_last} " ]; then
469+ start=$( echo " ${next_to_last} " | cut -f2 -d= | cut -f1 -d,)
470+ size=$( echo " ${next_to_last} " | cut -f3 -d= | cut -f1 -d,)
471+ offset=$(( start + size))
472+ echo " ${offset} "
473+ else
474+ echo 0
475+ fi
476+ }
477+
478+ function optimize_count_for_32k_blocksize {
479+ local block_size=$1
480+ local count=$2
481+ local dump_bytes
482+ dump_bytes=$(( block_size * count))
483+ if [ $(( dump_bytes % 32768 )) -eq 0 ]; then
484+ # dump_bytes is a multiple of 32k, use it for better I/O performance
485+ count=$(( dump_bytes / 32768 ))
486+ fi
487+ echo " ${count} "
488+ }
489+
365490function dump_local_image {
366491 local image_source=$1
367492 local image_target=$2
368- local progress=$3
493+ local count=$3
494+ local block_size=$4
495+ local progress=$5
496+ if [ " ${count} " -gt 0 ]; then
497+ count=" count=${count} "
498+ else
499+ unset count
500+ fi
501+ # shellcheck disable=SC2086
369502 if [ -e " ${progress} " ]; then
370503 (
371- pv -n " ${image_source} " | dd bs=32k of=" ${image_target} " & > /dev/null
504+ pv -n " ${image_source} " | \
505+ dd bs=" ${block_size} " ${count} of=" ${image_target} " & > /dev/null
372506 ) 2> " ${progress} "
373507 else
374- dd if=" ${image_source} " bs=32k of=" ${image_target} " & > /dev/null
508+ dd \
509+ if=" ${image_source} " bs=" ${block_size} " ${count} \
510+ of=" ${image_target} " & > /dev/null
375511 fi
376512}
377513
378514function dump_remote_image {
379515 local image_source=$1
380516 local image_target=$2
381- local progress=$3
517+ local count=$3
518+ local block_size=$4
519+ local progress=$5
382520 local image_size
383521 image_size=$(( blocks * blocksize))
522+ if [ " ${count} " -gt 0 ]; then
523+ count=" count=${count} "
524+ else
525+ unset count
526+ fi
527+ # shellcheck disable=SC2086
384528 if [ -e " ${progress} " ]; then
385529 (
386530 fetch_file " ${image_source} " " ${image_size} " | \
387- dd bs=32k of=" ${image_target} " & > /dev/null
531+ dd bs=" ${block_size} " ${count} of=" ${image_target} " & > /dev/null
388532 ) 2> " ${progress} "
389533 else
390534 fetch_file " ${image_source} " | \
391- dd bs=32k of=" ${image_target} " & > /dev/null
535+ dd bs=" ${block_size} " ${count} of=" ${image_target} " & > /dev/null
392536 fi
393537}
394538
@@ -406,6 +550,13 @@ function check_image_integrity {
406550 # no verification wanted
407551 return
408552 fi
553+ if getargbool 0 rd.kiwi.install.retain_last; then
554+ if [ ! -e /tmp/retain_not_applicable ]; then
555+ # no verification possible as only a portion of
556+ # the image got deployed intentionally
557+ return
558+ fi
559+ fi
409560 if command -v pv & > /dev/null && [ " ${kiwi_oemsilentverify} " = " false" ]
410561 then
411562 # verify with dialog based progress information
0 commit comments