-
-
Notifications
You must be signed in to change notification settings - Fork 501
/
dietpi-imager
executable file
·787 lines (701 loc) · 35 KB
/
dietpi-imager
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
#!/bin/bash
{
#////////////////////////////////////
# DietPi Image creation/finalise Script
#
#////////////////////////////////////
# Created by Daniel Knight / [email protected] / dietpi.com
# Updated by MichaIng / [email protected] / dietpi.com
# Clonezilla integration by sal666
#
#////////////////////////////////////
# - Create new .img file from drive
# or use an existing .img file
# or use Clonezilla to generate a bootable installer ISO from drive for x86_64 systems
# - Minimises root partition and filesystem
# - Compresses the final image ready for release
#////////////////////////////////////
# Import DietPi-Globals ---------------------------------------------------------------
if [[ -f '/boot/dietpi/func/dietpi-globals' ]]
then
. /boot/dietpi/func/dietpi-globals
else
[[ $G_GITOWNER && $G_GITBRANCH ]] || { echo '[FAILED] You must export or pass G_GITOWNER and G_GITBRANCH to the script'; exit 1; }
curl -sSf "https://raw.githubusercontent.com/$G_GITOWNER/DietPi/$G_GITBRANCH/dietpi/func/dietpi-globals" -o /tmp/dietpi-globals || exit 1
# shellcheck disable=SC1091
. /tmp/dietpi-globals
G_EXEC rm /tmp/dietpi-globals
read -r debian_version < /etc/debian_version
case $debian_version in
'11.'*|'bullseye/sid') G_DISTRO=6;;
'12.'*|'bookworm/sid') G_DISTRO=7;;
'13.'*|'trixie/sid') G_DISTRO=8;;
*) G_DIETPI-NOTIFY 1 "Unsupported distro version \"$debian_version\". Aborting ..."; exit 1;;
esac
# Ubuntu ships with /etc/debian_version from Debian testing, hence we assume one version lower.
grep -q '^ID=ubuntu' /etc/os-release && ((G_DISTRO--))
(( $G_DISTRO < 6 )) && { G_DIETPI-NOTIFY 1 'Unsupported Ubuntu version. Aborting ...'; exit 1; }
fi
readonly G_PROGRAM_NAME='DietPi-Imager'
G_CHECK_ROOT_USER
G_CHECK_ROOTFS_RW
readonly FP_ORIGIN=$PWD # Store origin dir
G_INIT
G_EXEC cd "$FP_ORIGIN" # Process everything in origin dir instead of /tmp/$G_PROGRAM_NAME
# Import DietPi-Globals ---------------------------------------------------------------
readonly FP_MNT_TMP="/tmp/${G_PROGRAM_NAME}_mnt"
readonly CLONEZILLA_REPO='https://sourceforge.net/projects/clonezilla/files/clonezilla_live_stable'
readonly DIETPI_REPO="https://raw.githubusercontent.com/$G_GITOWNER/DietPi/$G_GITBRANCH"
Error_Exit()
{
G_DIETPI-NOTIFY 1 "$1"
exit 1
}
##########################################
# Process inputs
##########################################
SOURCE_TYPE='Drive'
FP_SOURCE_IMG=
PART_TABLE_TYPE=
#FP_ROOT_DEV=
ROOT_FS_TYPE=
#CLONING_TOOL=
OUTPUT_IMG_EXT='img'
#OUTPUT_IMG_NAME=
[[ $MOUNT_IT == 'On' ]] || MOUNT_IT='Off'
[[ $SKIP_FIRSTBOOT_RESIZE == 1 ]] || SKIP_FIRSTBOOT_RESIZE=0
[[ $SHRINK_ONLY == 1 ]] || SHRINK_ONLY=0
[[ $SKIP_ARCHIVE == 1 ]] || SKIP_ARCHIVE=0
ADD_DOS_PART=0 # trailing FAT partition for first boot config files, automatically imported and partition removed on first boot
CONFIGS_TO_BOOT=0 # for new RPi kernel/firmware stack where a boot FAT partition exists, but is mounted to /boot/firmware instead of /boot
SIGN_PASS=
while (( $# ))
do
case $1 in
'--add-dos-part') ADD_DOS_PART=1;;
'--configs-to-boot') CONFIGS_TO_BOOT=1;;
'--sign') shift; SIGN_PASS=$1;;
*)
if [[ -b $1 ]]
then
FP_SOURCE=$1
elif [[ -f $1 ]]
then
SOURCE_TYPE='Image'
FP_SOURCE_IMG=$1
elif [[ $1 ]]
then
Error_Exit "Input source $1 does not exist, aborting..."
fi
;;
esac
shift
done
Unmount_tmp()
{
G_EXEC sync
G_SLEEP 1 # Give the system 1 second to avoid "mount is busy"
G_EXEC umount -R "$FP_MNT_TMP"
}
Delete_Loopback(){ [[ $FP_SOURCE_IMG ]] && losetup "$FP_SOURCE" &> /dev/null && G_EXEC losetup -d "$FP_SOURCE"; }
G_EXIT_CUSTOM()
{
findmnt "$FP_MNT_TMP" > /dev/null && Unmount_tmp
[[ -d $FP_MNT_TMP ]] && G_EXEC rmdir "$FP_MNT_TMP"
Delete_Loopback
[[ -e 'tmpiso' ]] && G_EXEC rm -R tmpiso
}
Run_fsck()
{
if [[ $ROOT_FS_TYPE == 'ext4' ]]
then
G_EXEC_OUTPUT=1 G_EXEC e2fsck -fyD "$FP_ROOT_DEV"
elif [[ $ROOT_FS_TYPE == 'f2fs' ]]
then
G_EXEC_OUTPUT=1 G_EXEC fsck.f2fs -f "$FP_ROOT_DEV"
elif [[ $ROOT_FS_TYPE == 'btrfs' ]]
then
G_EXEC_OUTPUT=1 G_EXEC btrfs check --repair "$FP_ROOT_DEV"
else
Error_Exit "Unsupported root filesystem type ($ROOT_FS_TYPE), aborting..."
fi
}
Menu_Source_Type()
{
main_menu_choice='Source type' # On cancel, keep this entry selected
G_WHIP_MENU_ARRAY=(
'Drive' ': The OS is stored on an attached drive.'
'Image' ': The OS is stored as an image file.'
)
G_WHIP_DEFAULT_ITEM=$SOURCE_TYPE
G_WHIP_MENU 'Please select how the input OS is stored:' || return 0
SOURCE_TYPE=$G_WHIP_RETURNED_VALUE
Delete_Loopback
FP_SOURCE_IMG=
FP_SOURCE=
FP_ROOT_DEV=
Menu_Source_Path # Directly open this menu next
}
Menu_Source_Path()
{
main_menu_choice='Source path' # On cancel, keep this entry selected
if [[ $SOURCE_TYPE == 'Drive' ]]
then
# Detect drives with a partition table, containing a partition with and ext4, F2FS or Btrfs filesystem, excluding the hosts root filesystem drive
mapfile -t G_WHIP_MENU_ARRAY < <(mawk -v root="$(lsblk -npo PKNAME "$G_ROOTFS_DEV")" '$1!=root && $2~/^(ext4|f2fs|btrfs)$/ {print $1"\n"$1"_details"}' < <(lsblk -rnpo PKNAME,FSTYPE) | sort -u)
if [[ ! ${G_WHIP_MENU_ARRAY[0]} ]]
then
G_DIETPI-NOTIFY 1 'No drive with an ext4, F2FS or Btrfs formatted partition found, aborting...'
G_DIETPI-NOTIFY 2 'NB: This is the list of available block devices:'
lsblk -npo NAME,SIZE,MAJ:MIN,FSTYPE,MOUNTPOINT,MODEL
read -rp 'Press any key to return to menu...'
return 1
fi
# Visually separate dev name and size and add model and serial
for ((i=1;i<${#G_WHIP_MENU_ARRAY[@]};i+=2)); do G_WHIP_MENU_ARRAY[$i]=": $(lsblk -drno SIZE,MODEL,SERIAL "${G_WHIP_MENU_ARRAY[$i-1]}")"; done
G_WHIP_DEFAULT_ITEM=$FP_SOURCE
G_WHIP_MENU 'Please select the drive you wish to create the image from:
\nNB: All mounted partitions of the selected drive will be unmounted.' || return 0
FP_SOURCE=$G_WHIP_RETURNED_VALUE
FP_ROOT_DEV=
G_DIETPI-NOTIFY 2 "Unmounting all filesystems below selected $FP_SOURCE ..."
local mountpoint
for i in "$FP_SOURCE"?*
do
mountpoint=$(findmnt -no TARGET "$i")
[[ $mountpoint ]] && G_EXEC umount -R "$mountpoint"
done
else
# Open DietPi-Explorer for image file selection
/boot/dietpi/dietpi-explorer 1 || { G_DIETPI-NOTIFY 1 'No image file selected, aborting...'; read -rp 'Press any key to return to menu...'; return 1; }
FP_SOURCE_IMG=$(</tmp/.dietpi-explorer_selected_location)
FP_ROOT_DEV=
rm /tmp/.dietpi-explorer_selected_location
[[ -f $FP_SOURCE_IMG ]] || { G_DIETPI-NOTIFY 1 "Selected image file ($FP_SOURCE_IMG) does not exist, aborting..."; read -rp 'Press any key to return to menu...'; return 1; }
# Create loopback device from .img file
G_EXEC modprobe loop
Delete_Loopback # Prevent doubled loop device
FP_SOURCE=$(losetup -f)
G_EXEC_NOEXIT=1 G_EXEC losetup "$FP_SOURCE" "$FP_SOURCE_IMG" || return 1
G_EXEC_NOEXIT=1 G_EXEC partprobe "$FP_SOURCE" || return 1
G_EXEC_NOEXIT=1 G_EXEC partx -u "$FP_SOURCE" || return 1
G_DIETPI-NOTIFY 0 "Attached the image ($FP_SOURCE_IMG) as loopback device: $FP_SOURCE"
G_SLEEP 0.5 # Give the root filesystem a little time to be detected
fi
Menu_Source_RootFS # Directly open this menu next
}
Menu_Source_RootFS()
{
main_menu_choice='Source rootfs' # On cancel, keep this entry selected
# Detect partitions and list for selection
# Coders NB: read/mapfile cannot be easily used here since we need to parse multiple lines and split at newline AND space.
# shellcheck disable=SC2207
G_WHIP_MENU_ARRAY=($(lsblk -rnpo NAME,FSTYPE "$FP_SOURCE"?* | mawk '$2~/^(ext4|f2fs|btrfs)$/'))
# Visually separate dev name and size and add FS type
for ((i=1;i<${#G_WHIP_MENU_ARRAY[@]};i+=2)); do G_WHIP_MENU_ARRAY[$i]=": $(lsblk -drno SIZE,FSTYPE "${G_WHIP_MENU_ARRAY[$i-1]}")"; done
G_WHIP_DEFAULT_ITEM=$FP_ROOT_DEV
G_WHIP_MENU 'Please select the OS root partition:' || return
FP_ROOT_DEV=$G_WHIP_RETURNED_VALUE
Menu_Target_Type # Directly open this menu next
}
Menu_Target_Type()
{
main_menu_choice='Target type' # On cancel, keep this entry selected
G_WHIP_MENU_ARRAY=(
'dd' ': Create an .img file to flash to target system drive directly.'
'Clonezilla' ': Create an installer .iso file to boot from removeable media. (x86_64 only!)'
)
G_WHIP_DEFAULT_ITEM=$CLONING_TOOL
G_WHIP_MENU 'Please select which cloning tool to use:
- dd: A regular system image is created which must be flashed to the target system drive directly.
This can be compared with regular SD card images like Raspbian Lite or Armbian ones.
Usually those can be flashed to and booted from eMMC as well.
- Clonezilla: An installer ISO image is created which must be flashed to an external/USB/removeable drive.
Boot from the external drive will launch Clonezilla and allow you to install DietPi to any internal drive.
This is required e.g. for UEFI images.
NB: Only compatible with x86_64 systems!' || return
CLONING_TOOL=$G_WHIP_RETURNED_VALUE
[[ $CLONING_TOOL == 'dd' ]] && OUTPUT_IMG_EXT='img' || OUTPUT_IMG_EXT='iso'
Menu_Target_Name # Directly open this menu next
}
Menu_Target_Name()
{
main_menu_choice='Target name' # On cancel, keep this entry selected
G_WHIP_DEFAULT_ITEM=$OUTPUT_IMG_NAME
G_WHIP_INPUTBOX 'Please enter a name for the new image:\n - DietPi_<device>-<arch>-<distro>\n - E.g.: DietPi_RPi-ARMv8-Bookworm' || return
OUTPUT_IMG_NAME=$G_WHIP_RETURNED_VALUE
# Check for existing file, in case offer backup. Skip if source is image file and matches output file already.
if [[ $PWD/$OUTPUT_IMG_NAME.$OUTPUT_IMG_EXT != "$FP_SOURCE_IMG" && -f $OUTPUT_IMG_NAME.$OUTPUT_IMG_EXT ]]
then
G_WHIP_BUTTON_OK_TEXT='Overwrite'
G_WHIP_BUTTON_CANCEL_TEXT='Backup'
G_WHIP_YESNO "[WARNING] $PWD/$OUTPUT_IMG_NAME.$OUTPUT_IMG_EXT already exists
\nDo you want to overwrite or backup the existing file to $PWD/$OUTPUT_IMG_NAME.$OUTPUT_IMG_EXT.bak?" || mv "$OUTPUT_IMG_NAME.$OUTPUT_IMG_EXT"{,.bak}
fi
main_menu_choice='Mount' # Select this entry next
}
Menu_Main()
{
G_WHIP_MENU_ARRAY=(
'Source type' ": [${SOURCE_TYPE:=Drive}] Select how the input OS is stored"
'Source path' ": [${FP_SOURCE_IMG:-$FP_SOURCE}] Select the input $SOURCE_TYPE"
)
[[ $FP_SOURCE ]] && G_WHIP_MENU_ARRAY+=('Source rootfs' ": [$FP_ROOT_DEV] Select input OS root partition")
G_WHIP_MENU_ARRAY+=(
'Target type' ": [${CLONING_TOOL:=dd}] Select output image type"
'Target name' ": [${OUTPUT_IMG_NAME:=DietPi_RPi-ARMv8-Bookworm}] Choose the output image name"
'' '●─'
'Mount' ": [$MOUNT_IT] Review or edit drive content before image creation"
)
[[ $FP_SOURCE && $FP_ROOT_DEV ]] && G_WHIP_MENU_ARRAY+=('' '●─' 'Start' ": Start creating $OUTPUT_IMG_NAME.$OUTPUT_IMG_EXT")
G_WHIP_DEFAULT_ITEM=$main_menu_choice
G_WHIP_BUTTON_CANCEL_TEXT='Exit'
G_WHIP_MENU 'Select input parameters and hit "Start" to continue image creation:' || exit 0
case $G_WHIP_RETURNED_VALUE in
'Source type') Menu_Source_Type;;
'Source path') Menu_Source_Path;;
'Source rootfs') Menu_Source_RootFS;;
'Target type') Menu_Target_Type;;
'Target name') Menu_Target_Name;;
'Mount') [[ $MOUNT_IT == 'Off' ]] && MOUNT_IT='On' || MOUNT_IT='Off';;
'Start') main_menu_choice='Start';;
*) :;;
esac
}
Main(){
# Dependencies
G_AG_CHECK_INSTALL_PREREQ parted fdisk zerofree xz-utils
# Skip menu if all inputs are provided via environment variables
if [[ ( $SOURCE_TYPE$FP_SOURCE == 'Drive'?* || $SOURCE_TYPE$FP_SOURCE_IMG == 'Image'?* ) && $FP_ROOT_DEV && $CLONING_TOOL =~ ^(dd|Clonezilla)$ && $OUTPUT_IMG_NAME ]]
then
if [[ $SOURCE_TYPE == 'Image' ]]
then
# Create loopback device from .img file
G_EXEC modprobe loop
Delete_Loopback # Prevent doubled loop device
FP_SOURCE=$(losetup -f)
G_EXEC losetup "$FP_SOURCE" "$FP_SOURCE_IMG"
G_EXEC partprobe "$FP_SOURCE"
G_EXEC partx -u "$FP_SOURCE"
G_DIETPI-NOTIFY 0 "Mounted the image ($FP_SOURCE_IMG) as loopback device: $FP_SOURCE"
FP_ROOT_DEV="${FP_SOURCE}p${FP_ROOT_DEV: -1}"
fi
[[ $CLONING_TOOL == 'dd' ]] && OUTPUT_IMG_EXT='img' || OUTPUT_IMG_EXT='iso'
G_DIETPI-NOTIFY 0 "\e[0mCreating minified image from:
- $SOURCE_TYPE: ${FP_SOURCE_IMG:-$FP_SOURCE}
- Root device: $FP_ROOT_DEV
- Via $CLONING_TOOL to $OUTPUT_IMG_NAME.$OUTPUT_IMG_EXT
- With intermediate mounting turned $MOUNT_IT"
G_SLEEP 0.5 # Give the root filesystem a little time to be detected
else
local main_menu_choice
Menu_Source_Type
until [[ $main_menu_choice == 'Start' ]]
do
Menu_Main
done
unset -v main_menu_choice
fi
# Detect partition table type, failsafe detection of MBR to debug possibly other/unknown wording/partition table types
PART_TABLE_TYPE=$(lsblk -no PTTYPE "$FP_ROOT_DEV")
if [[ $PART_TABLE_TYPE == 'dos' ]]
then
G_DIETPI-NOTIFY 2 'MBR partition table detected'
# Move GPT backup partition table to end of drive
elif [[ $PART_TABLE_TYPE == 'gpt' ]]
then
G_DIETPI-NOTIFY 2 'GPT partition table detected'
else
Error_Exit "Unknown partition table type ($PART_TABLE_TYPE), aborting..."
fi
# Detect root filesystem type
ROOT_FS_TYPE=$(lsblk -no FSTYPE "$FP_ROOT_DEV")
Run_fsck
# Remount image for any required edits
G_EXEC mkdir "$FP_MNT_TMP"
G_EXEC mount "$FP_ROOT_DEV" "$FP_MNT_TMP"
# - Remove bash history and DHCP leases, which are stored on shutdown, hence cannot be removed via DietPi-PREP
G_EXEC rm -f "$FP_MNT_TMP/"{root,home/*}/.bash_history "$FP_MNT_TMP/var/lib/dhcp/"*.leases
# - Enable DietPi-FS_partition_resize to have both, old and new image being resized on next boot automatically
if [[ $SKIP_FIRSTBOOT_RESIZE != 1 && -f $FP_MNT_TMP/etc/systemd/system/dietpi-fs_partition_resize.service && ! -L $FP_MNT_TMP/etc/systemd/system/local-fs.target.wants/dietpi-fs_partition_resize.service ]]
then
[[ -d $FP_MNT_TMP/etc/systemd/system/local-fs.target.wants ]] || G_EXEC mkdir "$FP_MNT_TMP/etc/systemd/system/local-fs.target.wants"
G_EXEC ln -s {'/etc/systemd/system',"$FP_MNT_TMP/etc/systemd/system/local-fs.target.wants"}'/dietpi-fs_partition_resize.service'
fi
if [[ $MOUNT_IT == 'On' ]] && G_WHIP_MSG "The ${SOURCE_TYPE,,} has been mounted to allow you reviewing or editing its content:
- $FP_ROOT_DEV > $FP_MNT_TMP
\nAn interactive bash subshell will open.
\nPlease use the \"exit\" command when you are finished, to return to $G_PROGRAM_NAME."
then
# Prevent dietpi-login call in subshell
local reallow_dietpi_login=1
[[ $G_DIETPI_LOGIN ]] && reallow_dietpi_login=0
export G_DIETPI_LOGIN=1
G_EXEC cd "$FP_MNT_TMP"
bash &> /dev/tty < /dev/tty
G_EXEC cd "$FP_ORIGIN"
(( $reallow_dietpi_login )) && unset -v G_DIETPI_LOGIN
fi
Unmount_tmp
# Failsafe
G_EXEC partprobe "$FP_SOURCE"
G_EXEC partx -u "$FP_SOURCE"
Run_fsck
# Shrink last filesystem to minimum
local last_part_dev=$(lsblk -rnpo NAME "$FP_SOURCE" | tail -1)
local last_fs_type=$(lsblk -no FSTYPE "$last_part_dev")
if [[ $last_fs_type == 'ext4' ]]
then
# Disable and enable journal to clear it and allow further size reduction
G_EXEC tune2fs -O '^has_journal' "$last_part_dev"
G_EXEC sync
G_SLEEP 1
G_EXEC tune2fs -O 'has_journal' "$last_part_dev"
G_EXEC sync
G_SLEEP 1
# Run multiple times until no change is done any more
G_DIETPI-NOTIFY 2 'Shrinking last filesystem to minimum size...'
local out last_fs_size=$(tune2fs -l "$last_part_dev" | mawk '/^Block count/{print $3;exit}') # blocks
while :
do
resize2fs -Mp "$last_part_dev" 2>&1 | tee /tmp/resize2fs_out
if out=$(grep -im1 'nothing to do!' /tmp/resize2fs_out)
then
rm /tmp/resize2fs_out
FS_SIZE=$(mawk '{print $5}' <<< "$out") # blocks
BLOCK_SIZE=${out%%k) *} BLOCK_SIZE=${BLOCK_SIZE##*\(} # KiB
# Re-add 4 MiB if it would be still smaller than before, which was required on Raspbian Buster for successful boot, else leave original size
if (( $last_fs_size > $FS_SIZE + 4096/$BLOCK_SIZE )) # blocks
then
FS_SIZE=$(( $FS_SIZE + 4096/$BLOCK_SIZE )) # blocks
G_DIETPI-NOTIFY 0 "Reducing last filesystem size to $(( $FS_SIZE * $BLOCK_SIZE / 1024 + 1 )) MiB"
else
FS_SIZE=$last_fs_size
G_DIETPI-NOTIFY 0 "Leaving last filesystem size at $(( $FS_SIZE * $BLOCK_SIZE / 1024 + 1 )) MiB"
fi
G_EXEC resize2fs "$last_part_dev" "$FS_SIZE"
FS_SIZE=$(( $FS_SIZE * $BLOCK_SIZE * 2 )) # blocks => 512 byte sectors
break
elif out=$(grep -im1 'no such file or directory' /tmp/resize2fs_out)
then
Error_Exit 'Partition not found, aborting...'
fi
done
# F2FS does not support shrinking: https://www.reddit.com/r/archlinux/comments/bpp77f/shrinking_a_f2fs_partition/
# Hence copy all data outside, remove and re-create a smaller filesystem, then copy data back in, as long as disk usage is not >=95% already.
### The UUID changes and there is currently no way to change it back, hence only store current filesystem size and skip shrinking...
elif [[ $last_fs_type == 'f2fs' ]] # && ! $(lsblk -rno FSUSE% "$last_part_dev") =~ ^(9[5-9]|100)%$ ]]
then
FS_SIZE=$(lsblk -rnbo SIZE "$last_part_dev") # bytes
FS_SIZE=$(( $FS_SIZE / 512 )) # bytes => sectors
#local usage=$(lsblk -rnbo FSUSED "$last_part_dev") # bytes
#local sector_size=$(lsblk -rnbo LOG-SEC "$last_part_dev") # bytes
#FS_SIZE=$(( ( $usage + 4*1024**2 ) / $sector_size )) # bytes + 4 MiB buffer => sectors
#G_DIETPI-NOTIFY 2 'Copying last filesystem content to temporary directory'
#G_EXEC mkdir "${FP_MNT_TMP}_backup"
#G_EXEC mount -o ro "$last_part_dev" "$FP_MNT_TMP"
#G_EXEC cp -a "$FP_MNT_TMP/." "${FP_MNT_TMP}_backup/"
#G_EXEC umount "$FP_MNT_TMP"
#G_DIETPI-NOTIFY 2 'Purging last filesystem'
#G_EXEC dd if=/dev/zero of="$last_part_dev" bs=4K count=10
#G_DIETPI-NOTIFY 2 'Re-creating smaller last filesystem' # Probably sload.f2fs can replace this? https://manpages.debian.org/sload.f2fs
#G_EXEC_OUTPUT=1 G_EXEC mkfs.f2fs -w "$sector_size" "$last_part_dev" "$FS_SIZE"
#G_DIETPI-NOTIFY 2 'Moving last filesystem content back'
#G_EXEC mount "$last_part_dev" "$FP_MNT_TMP"
#G_EXEC cp -a "${FP_MNT_TMP}_backup/." "$FP_MNT_TMP/"
#G_EXEC rm -R "${FP_MNT_TMP}_backup"
#Unmount_tmp
#FS_SIZE=$(( $FS_SIZE * $sector_size / 512 )) # sectors => 512 bytes sectors
elif [[ $last_fs_type == 'btrfs' ]]
then
G_DIETPI-NOTIFY 2 'Shrinking last filesystem to minimum size...'
G_EXEC mount "$last_part_dev" "$FP_MNT_TMP"
# Obtain current filesystem size
local last_fs_size=$(findmnt -Ufnrbo SIZE -M "$FP_MNT_TMP") # bytes
# Obtain minimal filesystem size + 4 MiB buffer
FS_SIZE=$(( $(btrfs inspect-internal min-dev-size "$FP_MNT_TMP" | mawk '{print $1}') + 4*1024**2 )) # bytes
# Shrink filesystem only if it would actually become smaller
if (( $FS_SIZE < $last_fs_size ))
then
G_EXEC_OUTPUT=1 G_EXEC btrfs filesystem resize "$FS_SIZE" "$FP_MNT_TMP"
else
FS_SIZE=$last_fs_size
fi
Unmount_tmp
FS_SIZE=$(( $FS_SIZE / 512 )) # bytes => 512 byte sectors
fi
Run_fsck
G_DIETPI-NOTIFY 2 'Overriding filesystems free space with zeros to purge removed data and allow better compression...'
while read -r path type
do
[[ $type ]] || continue
if [[ $type == 'ext'[234] ]]
then
# Disable and enable journal on ext3 and ext4 to clear it, when not last partition (where it was done already)
if [[ $type != 'ext2' && $path != "$last_part_dev" ]]
then
G_EXEC tune2fs -O '^has_journal' "$path"
G_EXEC sync
G_SLEEP 1
G_EXEC tune2fs -O 'has_journal' "$path"
G_EXEC sync
G_SLEEP 1
fi
[[ ( -t 0 || -t 1 ) && $TERM != 'dumb' ]] && G_EXEC_OUTPUT=1
G_EXEC zerofree -v "$path"
else
G_EXEC mount "$path" "$FP_MNT_TMP"
G_EXEC_NOHALT=1 G_EXEC_OUTPUT=1 G_EXEC fstrim -v --quiet-unsupported "$FP_MNT_TMP"
Unmount_tmp
fi
# shellcheck disable=SC2015
[[ $path == "$FP_ROOT_DEV" ]] && Run_fsck || G_EXEC_OUTPUT=1 G_EXEC fsck -y "$path"
done < <(lsblk -rnpo NAME,FSTYPE "$FP_SOURCE"?*)
G_EXEC rmdir "$FP_MNT_TMP"
# Only resize partition when new size would be less than current size
if (( $(<"/sys/class/block/${last_part_dev##*/}/size") > $FS_SIZE ))
then
G_DIETPI-NOTIFY 2 "Shrinking last partition to: $(( $FS_SIZE / 2048 + 1 )) MiB"
G_EXEC_OUTPUT=1 G_EXEC eval "sfdisk --no-reread --no-tell-kernel -fN${last_part_dev: -1} '$FP_SOURCE' <<< ',$FS_SIZE'"
G_EXEC partprobe "$FP_SOURCE"
G_EXEC partx -u "$FP_SOURCE"
fi
# Derive target image size from last partition end
# - WARNING: this assumes that the partitions in the table are in order (which we do in other places as well)
local last_part_end=$(sfdisk -qlo End "$FP_SOURCE" | tail -1) # 512 byte sectors
IMAGE_SIZE=$last_part_end
# Add space for GPT backup partition table, or 1 sector for MBR
if [[ $PART_TABLE_TYPE == 'gpt' ]]
then
# Obtain first usable LBA, which defines the size of the GPT backup, else use 34 sectors as default: https://github.com/MichaIng/DietPi/issues/7024
local gpt_size=$(sgdisk -p "$FP_SOURCE" 2>&1 | mawk -F[\ ,] '/^First usable sector/{print $5}')
# shellcheck disable=SC2015
(( $gpt_size )) && ((IMAGE_SIZE+=$gpt_size)) || ((IMAGE_SIZE+=34))
else
((IMAGE_SIZE++))
fi
((IMAGE_SIZE*=512)) # 512 byte sectors => bytes
# RPi: Move configs to boot FAT partition to allow easier edit from Windows/macOS
if (( $CONFIGS_TO_BOOT ))
then
local fat_mountpoint=$(mktemp -d)
local root_mountpoint=$(mktemp -d)
G_EXEC mount "${FP_ROOT_DEV::-1}1" "$fat_mountpoint"
G_EXEC mount "$FP_ROOT_DEV" "$root_mountpoint"
G_DIETPI-NOTIFY 2 'Copying dietpi.txt and other config files to the DIETPISETUP partition'
for f in 'dietpi.txt' 'dietpi-wifi.txt' 'Automation_Custom_PreScript.sh' 'Automation_Custom_Script.sh' 'unattended_pivpn.conf'
do
[[ -f $root_mountpoint/boot/$f ]] || continue
G_EXEC cp "$root_mountpoint/boot/$f" "$fat_mountpoint/"
TZ=UTC G_EXEC touch -t '197001010000' "$fat_mountpoint/$f"
TZ=UTC G_EXEC touch -t '197001010001' "$root_mountpoint/boot/$f"
done
G_EXEC umount "$root_mountpoint" "$fat_mountpoint"
G_EXEC rmdir "$root_mountpoint" "$fat_mountpoint"
# Add trailing FAT partition to simplify first run setup if requested
elif (( $ADD_DOS_PART ))
then
G_DIETPI-NOTIFY 2 'Adding a 1 MiB FAT partition to simplify first run setup'
((IMAGE_SIZE+=1048576))
# Increase source image size if required
[[ $SOURCE_TYPE == 'Image' ]] && (( $(stat -c '%s' "$FP_SOURCE_IMG") < $IMAGE_SIZE )) && G_EXEC truncate -s "$IMAGE_SIZE" "$FP_SOURCE_IMG" && G_EXEC losetup -c "$FP_SOURCE"
# Add new DOS partition
local start=$(( $last_part_end + 1 ))
local type='EBD0A0A2-B9E5-4433-87C0-68B6B72699C7' # https://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_type_GUIDs
[[ $PART_TABLE_TYPE == 'dos' ]] && type='c'
G_EXEC eval "sfdisk -a '$FP_SOURCE' <<< 'start=$start,size=2048,type=$type'" # size in sectors
G_EXEC partprobe "$FP_SOURCE"
G_EXEC partx -u "$FP_SOURCE"
# create a FAT filesystem and add config files to it
local new_dos_part=$(sfdisk -l "$FP_SOURCE" | mawk "/ $start /{print \$1;exit}")
G_EXE_OUTPUT=1 G_EXEC mkfs.fat -n DIETPISETUP "$new_dos_part"
local fat_mountpoint=$(mktemp -d)
local root_mountpoint=$(mktemp -d)
G_EXEC mount "$new_dos_part" "$fat_mountpoint"
G_EXEC mount "$FP_ROOT_DEV" "$root_mountpoint"
G_DIETPI-NOTIFY 2 'Copying dietpi.txt and other config files to the DIETPISETUP partition'
for f in 'dietpi.txt' 'dietpi-wifi.txt' 'dietpiEnv.txt' 'boot.ini' 'extlinux/extlinux.conf' 'Automation_Custom_PreScript.sh' 'Automation_Custom_Script.sh' 'unattended_pivpn.conf'
do
[[ -f $root_mountpoint/boot/$f ]] || continue
G_EXEC cp "$root_mountpoint/boot/$f" "$fat_mountpoint/"
TZ=UTC G_EXEC touch -t '202101010001' "$fat_mountpoint/${f#extlinux/}"
TZ=UTC G_EXEC touch -t '202101010002' "$root_mountpoint/boot/$f"
done
cat << '_EOF_' > "$fat_mountpoint/README.txt"
DietPi config partition
This FAT partition is a place for relevant configuration files to pre-configure and automate your DietPi setup.
Those files will be copied into the root filesystem on first boot, if modified, to become effective, and the partition will be removed.
Apart of editing the existing files, you can also create the following for further automation:
- Automation_Custom_PreScript.sh
- Automation_Custom_Script.sh
- unattended_pivpn.conf
For details, please check our documentation and dietpi.txt itself:
https://dietpi.com/docs/usage/#how-to-do-an-automatic-base-installation-at-first-boot-dietpi-automation
_EOF_
G_EXEC umount "$root_mountpoint" "$fat_mountpoint"
G_EXEC rmdir "$root_mountpoint" "$fat_mountpoint"
fi
# Exit now if source shall be shrunk only
(( $SHRINK_ONLY )) && exit 0
# Image file source and dd target
if [[ $FP_SOURCE_IMG && $CLONING_TOOL == 'dd' ]]
then
# Clear loop
Delete_Loopback
G_DIETPI-NOTIFY 2 "Truncating final image file to actually used size: $(( $IMAGE_SIZE / 1024**2 + 1 )) MiB"
G_EXEC truncate -s "$IMAGE_SIZE" "$FP_SOURCE_IMG"
# Rename if source image != output image yet
[[ $(readlink -f "$PWD/$OUTPUT_IMG_NAME.$OUTPUT_IMG_EXT") != "$(readlink -f "$FP_SOURCE_IMG")" ]] && G_EXEC mv "$FP_SOURCE_IMG" "$OUTPUT_IMG_NAME.$OUTPUT_IMG_EXT"
# Check for sufficient free disk space to store the xz archive with 100 MiB buffer
(( $SKIP_ARCHIVE )) || G_CHECK_FREESPACE . $(( $IMAGE_SIZE * 15/100 / 1024**2 + 100 )) || exit 1
# Drive source and dd target
elif [[ $CLONING_TOOL == 'dd' ]]
then
# Check for sufficient free disk space to store the image and in case the xz archive with 100 MiB buffer
local free_space_percent=100
(( $SKIP_ARCHIVE )) || free_space_percent=115 # 15% image size for xz archive
G_CHECK_FREESPACE . $(( $IMAGE_SIZE * $free_space_percent/100 / 1024**2 + 100 )) || exit 1
G_DIETPI-NOTIFY 2 "Creating final image with actually used size: $(( $IMAGE_SIZE / 1024**2 + 1 )) MiB"
G_EXEC_OUTPUT=1 G_EXEC dd if="$FP_SOURCE" of="$OUTPUT_IMG_NAME.$OUTPUT_IMG_EXT" bs=1M status=progress count=$(( $IMAGE_SIZE / 1024**2 + 1 ))
# Clonezilla target
else
G_DIETPI-NOTIFY 2 'Creating final image with Clonezilla'
# Install required packages
G_AG_CHECK_INSTALL_PREREQ unzip clonezilla partclone xz-utils syslinux-common xorriso isolinux
# - Bullseye/Focal: We need Clonezilla 5.x for loop device support
if dpkg --compare-versions "$(dpkg-query -Wf '${Version}' clonezilla 2> /dev/null)" lt 5
then
G_EXEC curl -sSf 'https://deb.debian.org/debian/pool/main/c/clonezilla/clonezilla_5.3.17-2_all.deb' -o clonezilla.deb
G_EXEC dpkg -i ./clonezilla.deb
G_EXEC rm clonezilla.deb
fi
# Get latest version of Clonezilla Live
CLONEZILLA_VERSION=$(curl -sSf "$CLONEZILLA_REPO/" | mawk -F\" '/class="folder "/{print $2}' | head -1)
[[ $CLONEZILLA_VERSION ]] || Error_Exit 'Could not retrieve latest Clonezilla Live version string, aborting...'
CLONEZILLA_URL="$CLONEZILLA_REPO/$CLONEZILLA_VERSION/clonezilla-live-$CLONEZILLA_VERSION-amd64.zip/download"
# Check for sufficient free disk space to store the bundled Clonezille Live + DietPi directory and ISO with 100 MiB buffer
# - Get Clonezilla Live ISO size, which matches sufficiently well the unpacked archive: Remove trailing carriage return
CLONEZILLA_SIZE=$(curl -sSfIL "${CLONEZILLA_URL/amd64.zip/amd64.iso}" | mawk '/^[Cc]ontent-[Ll]ength:/{print $2}' | tail -1); CLONEZILLA_SIZE=${CLONEZILLA_SIZE%$'\r'}
(( $CLONEZILLA_SIZE )) || Error_Exit 'Could not retrieve Clonezilla Live size, aborting...'
NEEDED_FREE_SPACE=$(( ( $CLONEZILLA_SIZE + $IMAGE_SIZE * 20/100 ) * 2 / 1024**2 + 100 )) REMOVE_IMG=0
# If free space is insufficient and the source is an image on the same filesystem, check whether it fits when we remove the source image before generating the ISO
if ! G_CHECK_FREESPACE . "$NEEDED_FREE_SPACE"
then
[[ $FP_SOURCE_IMG && $(findmnt -Ufnro TARGET -T "$FP_SOURCE_IMG") == $(findmnt -Ufnro TARGET -T .) ]] || exit 1
G_DIETPI-NOTIFY 2 'Insufficient free space for ISO directory + file, checking whether it would be sufficient after removing source image file...'
G_CHECK_FREESPACE . $(( $NEEDED_FREE_SPACE - $IMAGE_SIZE / 1024**2 )) || exit 1
REMOVE_IMG=1
fi
# Download
G_EXEC_DESC="Downloading Clonezilla Live v$CLONEZILLA_VERSION" G_EXEC_OUTPUT=1 G_EXEC curl -fL "$CLONEZILLA_URL" -o clonezilla.zip
# Extract
[[ -e 'tmpiso' ]] && G_EXEC rm -R tmpiso
G_EXEC unzip clonezilla.zip -d 'tmpiso'
G_EXEC rm clonezilla.zip
# Clone disk
G_EXEC mkdir -p tmpiso/home/partimag
G_EXEC_DESC='Cloning disk with Clonezilla' G_EXEC_OUTPUT=1 G_EXEC ocs-sr -or "$PWD/tmpiso/home/partimag" -nogui -fsck-y -q2 -b -j2 -z5p -i 4096 -senc -sc savedisk "$OUTPUT_IMG_NAME" "${FP_SOURCE##*/}"
# Remove loop device
Delete_Loopback
# For the sake of privacy, remove some non vital files that contain SNs and UUIDs
G_EXEC rm -f "tmpiso/home/partimag/$OUTPUT_IMG_NAME/"{Info*txt,*list,clonezilla-img}
# Check image
G_EXEC_DESC='Checking Clonezilla image' G_EXEC_OUTPUT=1 G_EXEC ocs-chkimg -or "$PWD/tmpiso/home/partimag" -nogui -b "$OUTPUT_IMG_NAME"
### Prepare custom files used by the installer when booting in UEFI mode ###
# Create a GRUB theme for the main menu
G_EXEC curl -sSf "$DIETPI_REPO/.build/images/Clonezilla/dietpi-background_768p.png" -o tmpiso/boot/grub/dietpibg.png
G_EXEC curl -sSf "$DIETPI_REPO/.build/images/Clonezilla/select_bkg_c.png" -o tmpiso/boot/grub/select_bkg_c.png
cat << '_EOF_' > tmpiso/boot/grub/theme.txt
title-text: ""
desktop-image: "dietpibg.png"
desktop-image-scale-method: "crop"
terminal-font: "Unifont Regular 16"
terminal-width: "100%"
terminal-height: "100%"
message-color: "#ffffff"
+ boot_menu {
width = 60%
height = 80%
item_spacing = 10
item_color = "#000000"
selected_item_color = "#ffffff"
selected_item_pixmap_style = "select_bkg_*.png"
}
_EOF_
# Make the original Clonezilla Live menu a submenu of a simplified DietPi install main menu
G_EXEC mv tmpiso/boot/grub/{grub,clonezilla}.cfg
sed '/^menuentry /,$d' tmpiso/boot/grub/clonezilla.cfg > tmpiso/boot/grub/grub.cfg
sed -n '/menuentry .*Safe graphic/,/}/s/^ //p' tmpiso/boot/grub/clonezilla.cfg >> tmpiso/boot/grub/grub.cfg
# shellcheck disable=SC2016
sed --follow-symlinks -i -e '/^set timeout=/c\set timeout="-1"' -e '/^set pref=/a\set theme=\$pref/theme.txt' -e '/^menuentry /c\menuentry "Install DietPi" {' \
-e 's/locales= /locales=C.UTF-8 /' -e 's/keyboard-layouts= /keyboard-layouts=gb /' -e 's/ocs-live-general/ocs-live-restore/' \
-e "s|ocs_live_extra_param=\"\"|ocs_live_extra_param=\"-icds -k1 -r -e2 -j2 -b -p poweroff restoredisk $OUTPUT_IMG_NAME ask_user\"|" \
-e 's/ocs_live_batch="no"/ocs_live_batch="yes"/' tmpiso/boot/grub/grub.cfg
cat << '_EOF_' >> tmpiso/boot/grub/grub.cfg
submenu "Clonezilla live" { configfile /boot/grub/clonezilla.cfg }
menuentry "Power off" { halt }
_EOF_
### Prepare custom files used by the installer when booting in BIOS/CSM mode ###
# Make the original Clonezilla Live menu a submenu of a simplified DietPi install main menu
G_EXEC curl -sSf "$DIETPI_REPO/.build/images/Clonezilla/dietpi-background_480p.png" -o tmpiso/syslinux/dietpibg.png
G_EXEC cp /usr/lib/syslinux/modules/bios/poweroff.c32 tmpiso/syslinux/
G_EXEC mv tmpiso/syslinux/{syslinux,clonezilla}.cfg
sed --follow-symlinks -i '/^MENU TITLE/c\MENU TITLE Clonezilla live' tmpiso/syslinux/clonezilla.cfg
sed '/^label /,$d' tmpiso/syslinux/clonezilla.cfg > tmpiso/syslinux/syslinux.cfg
sed -n '/^label .*framebuffer/,/ENDTEXT/p' tmpiso/syslinux/clonezilla.cfg >> tmpiso/syslinux/syslinux.cfg
sed --follow-symlinks -i -e '/^timeout /c\timeout 0' -e 's|\(MENU BACKGROUND\) .*|\1 dietpibg.png|' -e '/^MENU TITLE /c\MENU TABMSG' \
-e '/menu title/d' -e '/^say /d' -e '/MENU MARGIN/a\MENU HSHIFT 80\n MENU COLOR BORDER 0 #00000000 #00000000 none' \
-e '/^label /c\label Install DietPi' -e '/^ MENU LABEL /c\ MENU LABEL Install DietPi' -e '/^ TEXT HELP/,/^ ENDTEXT/d' \
-e 's/locales= /locales=C.UTF-8 /' -e 's/keyboard-layouts= /keyboard-layouts=gb /' -e 's/ocs-live-general/ocs-live-restore/' \
-e "s|ocs_live_extra_param=\"\"|ocs_live_extra_param=\"-icds -k1 -r -e2 -j2 -b -p poweroff restoredisk $OUTPUT_IMG_NAME ask_user\"|" \
-e 's/ocs_live_batch="no"/ocs_live_batch="yes"/' tmpiso/syslinux/syslinux.cfg
cat << '_EOF_' >> tmpiso/syslinux/syslinux.cfg
MENU BEGIN Clonezilla live
INCLUDE clonezilla.cfg
MENU END
label Power off
MENU LABEL Power off
COM32 poweroff.c32
MENU END
_EOF_
G_EXEC cp tmpiso/syslinux/{syslinux,isolinux}.cfg
# Removing source image if required
(( $REMOVE_IMG )) && G_EXEC rm "$FP_SOURCE_IMG"
# Generate ISO file with Clonezilla Live + DietPi image
G_EXEC_DESC="Generating $OUTPUT_IMG_NAME.$OUTPUT_IMG_EXT" G_EXEC_OUTPUT=1 G_EXEC xorriso \
-as mkisofs -R -r -J -joliet-long -l -iso-level 3 -isohybrid-mbr /usr/lib/ISOLINUX/isohdpfx.bin -partition_offset 16 \
-publisher 'DietPi - Lightweight justice for your SBC; https://dietpi.com/;' -volid 'DIETPI_INSTALLER' \
-A "clonezilla-live-$CLONEZILLA_VERSION-amd64" -b syslinux/isolinux.bin -c syslinux/boot.cat -no-emul-boot -boot-load-size 4 \
-boot-info-table -eltorito-alt-boot --efi-boot boot/grub/efi.img -isohybrid-gpt-basdat -isohybrid-apm-hfsplus \
-o "$OUTPUT_IMG_NAME.$OUTPUT_IMG_EXT" tmpiso
G_EXEC rm -R tmpiso
fi
# Move GPT backup partition table to end of drive
if [[ $CLONING_TOOL != 'Clonezilla' && $PART_TABLE_TYPE == 'gpt' ]]
then
G_EXEC_DESC='Re-creating GPT backup partition table and header at end of image' G_EXEC_OUTPUT=1 G_EXEC sgdisk -e "$OUTPUT_IMG_NAME.$OUTPUT_IMG_EXT"
G_EXEC sync
fi
# Exit now when archive shall be skipped
(( $SKIP_ARCHIVE )) && exit 0
# Generate xz archive
[[ -f $OUTPUT_IMG_NAME.$OUTPUT_IMG_EXT.xz ]] && G_EXEC rm "$OUTPUT_IMG_NAME.$OUTPUT_IMG_EXT.xz"
G_EXEC_DESC='Creating final xz archive' G_EXEC xz -9e -T0 -M75% -k "$OUTPUT_IMG_NAME.$OUTPUT_IMG_EXT"
G_EXEC_DESC='Generating SHA256 hash' G_EXEC eval "sha256sum '$OUTPUT_IMG_NAME.$OUTPUT_IMG_EXT.xz' > '$OUTPUT_IMG_NAME.$OUTPUT_IMG_EXT.xz.sha256'"
local signature=() sig_text=''
[[ $SIGN_PASS ]] && { G_DIETPI-NOTIFY 2 'Signing archive ...'; gpg --batch --pinentry-mode loopback --passphrase "$SIGN_PASS" -b --armor "$OUTPUT_IMG_NAME.$OUTPUT_IMG_EXT.xz" || exit 1; signature=("$OUTPUT_IMG_NAME.$OUTPUT_IMG_EXT.xz.asc") sig_text="\nSignature: $PWD/${signature[*]}"; }
G_DIETPI-NOTIFY 0 "DietPi-Imager has successfully finished.
Image file: $PWD/$OUTPUT_IMG_NAME.$OUTPUT_IMG_EXT
xz archive: $PWD/$OUTPUT_IMG_NAME.$OUTPUT_IMG_EXT.xz
SHA256 hash: $PWD/$OUTPUT_IMG_NAME.$OUTPUT_IMG_EXT.xz.sha256$sig_text"
# Upload archive automatically if there is an upload.sh in the same directory
[[ -x 'upload.sh' ]] && G_EXEC_OUTPUT=1 G_EXEC ./upload.sh "$OUTPUT_IMG_NAME.$OUTPUT_IMG_EXT.xz"{,.sha256} "${signature[@]}" && G_EXEC rm -R "$OUTPUT_IMG_NAME.$OUTPUT_IMG_EXT.xz"{,.sha256} "${signature[@]}"
}
#/////////////////////////////////////////////////////////////////////////////////////
# Main
#/////////////////////////////////////////////////////////////////////////////////////
Main
#-----------------------------------------------------------------------------------
exit 0
#-----------------------------------------------------------------------------------
}