forked from MichaIng/DietPi
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdietpi-drive_manager
executable file
·2005 lines (1453 loc) · 73.5 KB
/
dietpi-drive_manager
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
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/bin/bash
{
#////////////////////////////////////
# DietPi Drive Manager
#
#////////////////////////////////////
# Created by Daniel Knight / [email protected] / dietpi.com
#
#////////////////////////////////////
#
# Info:
# - Location: /boot/dietpi/dietpi-drive_manager
#
# Usage:
# - <empty> = Interactive menu
# - 1 = Select an available drive mount which is then saved to: /tmp/dietpi-drive_manager_selmnt
# - 3 = Scan for new drives and re-create fstab non-interactively, then exit
# - 4 = Reset /etc/fstab with currently attached local drives and /tmp + /var/log tmpfs mount. Used by: DietPi-Installer
#
#////////////////////////////////////
# Import DietPi-Globals --------------------------------------------------------------
. /boot/dietpi/func/dietpi-globals
readonly G_PROGRAM_NAME='DietPi-Drive_Manager'
G_CHECK_ROOT_USER
G_INIT
# Import DietPi-Globals --------------------------------------------------------------
# Start services on exit, if stopped during operation
SERVICES_STOPPED=0
G_EXIT_CUSTOM(){ (( $SERVICES_STOPPED )) && /boot/dietpi/dietpi-services start; }
# Grab input
[[ $1 == [134] ]] && INPUT=$1 || INPUT=0
EXIT_CODE=0
# APT pre-req check flag, allows to check for required APT packages only once per session
APT_CHECK=0
# Drive menu
MENU_DRIVE_INDEX=0
MENU_DRIVE_TARGET=
# Format menu
FORMAT_GPT=1 # default GPT: https://github.com/MichaIng/DietPi/issues/531. 0=MBR
FORMAT_FILESYSTEM_TYPE=0 # 0=ext4 1=ntfs 2=fat32 3=hfs+ 4=btrfs 5=f2fs 6=exfat 7=xfs
FORMAT_COMPLETED=0
FORMAT_MODE=1 # 0=drive 1=partition
MOVE_ROOTFS=0 # Whether the formatted drive is used as rootfs
# Drive data
FP_USERDATA_CURRENT=
FP_SWAPFILE_CURRENT=
Init_New_Device(){
((index++))
aDRIVE_UUID[$index]=
aDRIVE_PART_UUID[$index]=
aDRIVE_MOUNT_SOURCE[$index]=
aDRIVE_MOUNT_TARGET[$index]=
aDRIVE_SOURCE_DEVICE[$index]=
aDRIVE_FSTYPE[$index]=
aDRIVE_SIZE_TOTAL[$index]=
aDRIVE_SIZE_USED[$index]=
aDRIVE_SIZE_PERCENTUSED[$index]=
aDRIVE_ISFILESYSTEM[$index]=0
aDRIVE_ISMOUNTED[$index]=0
aDRIVE_ISREADONLY_CURRENTLY[$index]=0
aDRIVE_ISNETWORKED[$index]=0
aDRIVE_ISROM[$index]=0
aDRIVE_ISPARTITIONTABLE[$index]=0
aDRIVE_ISACCESS[$index]=1
}
Destroy(){
unset -v aDRIVE_UUID aDRIVE_PART_UUID
unset -v aDRIVE_MOUNT_SOURCE aDRIVE_MOUNT_TARGET
unset -v aDRIVE_SOURCE_DEVICE aDRIVE_FSTYPE
unset -v aDRIVE_SIZE_TOTAL aDRIVE_SIZE_USED
unset -v aDRIVE_SIZE_PERCENTUSED
unset -v aDRIVE_ISFILESYSTEM aDRIVE_ISMOUNTED
unset -v aDRIVE_ISREADONLY_CURRENTLY aDRIVE_ISNETWORKED
unset -v aDRIVE_ISROM aDRIVE_ISPARTITIONTABLE aDRIVE_ISACCESS
}
Init_Drives_and_Refresh(){
# Trigger automounts to assure those are detected as mounted
ls -d /mnt/*/. &> /dev/null
# Reset current index and delete arrays
local i index=-1
Destroy
# Obtain actual user data location on disk (follow symlinks)
FP_USERDATA_CURRENT=$(readlink -f /mnt/dietpi_userdata)
# Swap file location
FP_SWAPFILE_CURRENT=$(sed -n '/^[[:blank:]]*AUTO_SETUP_SWAPFILE_LOCATION=/{s/^[^=]*=//p;q}' /boot/dietpi.txt)
# Create tmp fstab
local fp_fstab_tmp='.fstab'
cp -a /etc/fstab "$fp_fstab_tmp"
# Special mounts
local swap_mounts tmpfs_mounts misc_mounts net_mounts
# Mode 4: Force reset/clean fstab (DietPi-Installer)
if (( $INPUT == 4 )); then
local var_log_size=$(sed -n '/^[[:blank:]]*AUTO_SETUP_RAMLOG_MAXSIZE=/{s/^[^=]*=//p;q}' /boot/dietpi.txt)
tmpfs_mounts="tmpfs /tmp tmpfs noatime,lazytime,nodev,nosuid,mode=1777
tmpfs /var/log tmpfs size=${var_log_size:-50}M,noatime,lazytime,nodev,nosuid"
# Else: Grab current mounts
else
swap_mounts=$(grep '^[[:blank:]]*[^#].*[[:blank:]]swap[[:blank:]]' "$fp_fstab_tmp")
tmpfs_mounts=$(grep '^[[:blank:]]*tmpfs[[:blank:]]' "$fp_fstab_tmp")
# ecryptfs, vboxsf, glusterfs, mergerfs, bind, Btrfs subvolume mounts
misc_mounts=$(grep -E '^[[:blank:]]*[^#].*([[:blank:]](ecryptfs|vboxsf|glusterfs|(fuse\.)?mergerfs)[[:blank:]]|[[:blank:],]bind[[:blank:],]|[[:blank:]]btrfs[[:blank:]]+(.+,)?subvol=)' "$fp_fstab_tmp")
# CurlFtpFS, CIFS/SMB/Samba, NFS, SSHFS
net_mounts=$(grep -E '^[[:blank:]]*(curlftpfs|sshfs#|[^#].*[[:blank:]](cifs|nfs4?|fuse.sshfs)[[:blank:]])' "$fp_fstab_tmp")
fi
echo "# You can use \"dietpi-drive_manager\" to setup mounts.
# NB: It overwrites and re-creates physical drive mount entries on use.
#----------------------------------------------------------------
# NETWORK
#----------------------------------------------------------------
$net_mounts
#----------------------------------------------------------------
# TMPFS
#----------------------------------------------------------------
$tmpfs_mounts
#----------------------------------------------------------------
# MISC: ecryptfs, vboxsf, glusterfs, mergerfs, bind, Btrfs subvolume
#----------------------------------------------------------------
$misc_mounts
#----------------------------------------------------------------
# SWAP SPACE
#----------------------------------------------------------------
$swap_mounts
#----------------------------------------------------------------
# PHYSICAL DRIVES
#----------------------------------------------------------------" > "$fp_fstab_tmp"
G_DIETPI-NOTIFY 2 'Detecting drives, please wait...'
# Detect mounted drives via df
# - Exclude special treated fs types: tmpfs, ecryptfs, vboxsf, glusterfs
# - Workaround for /dev/root on RPi: Replace with actual device path $G_ROOTFS_DEV
# - Only detect mounts with "/" in source path, which excludes other special/pseudo fs types
# - Remove duplicates, e.g. from bind mounts and due to /dev/root conversion: https://github.com/MichaIng/DietPi/issues/2013#issuecomment-417413867
while read -r line
do
Init_New_Device
aDRIVE_ISMOUNTED[$index]=1
aDRIVE_ISFILESYSTEM[$index]=1
aDRIVE_MOUNT_SOURCE[$index]=$line
aDRIVE_MOUNT_TARGET[$index]=$(findmnt -Ufnro TARGET -S "${aDRIVE_MOUNT_SOURCE[$index]}") # Use only first result since bind mounts lead to multiple matches
aDRIVE_SIZE_TOTAL[$index]=$(findmnt -Ufnro SIZE -M "${aDRIVE_MOUNT_TARGET[$index]}")
aDRIVE_SIZE_USED[$index]=$(findmnt -Ufnro USED -M "${aDRIVE_MOUNT_TARGET[$index]}")
aDRIVE_SIZE_PERCENTUSED[$index]=$(findmnt -Ufnro USE% -M "${aDRIVE_MOUNT_TARGET[$index]}")
# Physical
if [[ ${aDRIVE_MOUNT_SOURCE[$index]} == '/dev/'* ]]; then
G_DIETPI-NOTIFY 2 " - Detected mounted physical drive: ${aDRIVE_MOUNT_SOURCE[$index]} > ${aDRIVE_MOUNT_TARGET[$index]}"
aDRIVE_SOURCE_DEVICE[$index]=$(Return_Drive_Without_Partitions "${aDRIVE_MOUNT_SOURCE[$index]}")
[[ ${aDRIVE_MOUNT_SOURCE[$index]} == /dev/${aDRIVE_SOURCE_DEVICE[$index]} ]] || aDRIVE_ISPARTITIONTABLE[$index]=1
[[ -b ${aDRIVE_MOUNT_SOURCE[$index]} ]] || aDRIVE_ISACCESS[$index]=0 # continue
aDRIVE_UUID[$index]=$(findmnt -Ufnro UUID -M "${aDRIVE_MOUNT_TARGET[$index]}")
(( ${aDRIVE_ISPARTITIONTABLE[$index]} )) && aDRIVE_PART_UUID[$index]=$(findmnt -Ufnro PARTUUID -M "${aDRIVE_MOUNT_TARGET[$index]}")
# blkid is required here, as findmnt will show "fuseblk" for NTFS filesytems, which is a correct result but cannot be used in fstab or for mounting the drive.
aDRIVE_FSTYPE[$index]=$(blkid -s TYPE -o value -c /dev/null "${aDRIVE_MOUNT_SOURCE[$index]}")
# Network
else
G_DIETPI-NOTIFY 2 " - Detected mounted network drive: ${aDRIVE_MOUNT_SOURCE[$index]} > ${aDRIVE_MOUNT_TARGET[$index]}"
aDRIVE_ISNETWORKED[$index]=1
# findmnt is required here, as blkid works only for physical block devices
aDRIVE_FSTYPE[$index]=$(findmnt -Ufnro FSTYPE -M "${aDRIVE_MOUNT_TARGET[$index]}")
fi
# R/O mounted?
# NB: We can't use -m1 for initial check as results can be:
# root@DietPi:~# cat /proc/mounts | grep ' / '
# rootfs / rootfs rw 0 0
# /dev/mmcblk0p2 / ext4 ro,noatime,discard,data=ordered 0 0
if grep -q "[[:blank:]]${aDRIVE_MOUNT_TARGET[$index]}[[:blank:]].*[[:blank:]]ro," /proc/mounts; then
aDRIVE_ISREADONLY_CURRENTLY[$index]=1
# RootFS R/W check
if [[ ${aDRIVE_MOUNT_TARGET[$index]} == '/' ]]; then
if G_WHIP_YESNO "RootFS is currently set to \"Read Only (R/O)\". $G_PROGRAM_NAME requires \"Read Write (R/W)\" access to function.\n\nWould you like to re-enable R/W access on RootFS?"; then
G_EXEC mount -v -o remount,rw "${aDRIVE_MOUNT_TARGET[$index]}"
aDRIVE_ISREADONLY_CURRENTLY[$index]=0
G_DIETPI-NOTIFY 0 'Remounted RootFS with R/W access'
else
G_DIETPI-NOTIFY 1 "RootFS is currently set to R/O. $G_PROGRAM_NAME requires R/W access to function. Aborting..."
G_DIETPI-NOTIFY 2 'Rerun "dietpi-drive_manager" to enable RootFS R/W access.'
exit 1
fi
fi
fi
# Add only physical drives to fstab, network drives are handled outside of this loop
if [[ ${aDRIVE_ISNETWORKED[$index]} == 0 ]]; then
# Skip if block device path does not exist, e.g. rootfs within a container
(( ${aDRIVE_ISACCESS[$index]} )) || { G_DIETPI-NOTIFY 2 " - Skipping /etc/fstab entry as system as no access to ${aDRIVE_MOUNT_SOURCE[$index]}"; continue; }
# Print error when physical drive has not UUID, as we cannot add it to fstab then
[[ ${aDRIVE_UUID[$index]} ]] || { G_DIETPI-NOTIFY 1 " - Skipping /etc/fstab entry as ${aDRIVE_MOUNT_SOURCE[$index]} has not UUID"; continue; }
# R/W or R/O?
# - Add rw flag to mount options. This should be default but seems to be not in rare cases: https://github.com/MichaIng/DietPi/issues/3268
local options=',rw'
(( ${aDRIVE_ISREADONLY_CURRENTLY[$index]} )) && options=',ro'
# Additional FS-specific options
# - NTFS: Enable POSIX permissions and prevent splitting write buffers into 4k chunks: https://manpages.debian.org/ntfs-3g#OPTIONS
if [[ ${aDRIVE_FSTYPE[$index]} == 'ntfs' ]]
then
options+=',permissions,big_writes'
# - exFAT: Grant (only) "dietpi" group R/W access: https://github.com/MichaIng/DietPi/issues/4680
elif [[ ${aDRIVE_FSTYPE[$index]} == 'exfat' ]]
then
getent group dietpi > /dev/null && options+=',gid=dietpi,fmask=0002,dmask=0002'
fi
# Root/BootFS dependant flags
# - fsck flag for RootFS, to allow check on reboot and for BootFS, since corruption here is most critical and fsck finishes in no time
# - nofail: Allow boot to continue, if mount fails, not wanted for Root/BootFS
# - x-systemd.automount: [ 1166.110202] systemd-fstab-generator[3512]: Ignoring automount option for root device
# /boot is removed from local-fs.target by this (on Buster only?), allowing it to mount after RAMdisk starts and unmount before it stops.
# Source device entry
local dev_entry="UUID=${aDRIVE_UUID[$index]}"
if [[ ${aDRIVE_MOUNT_TARGET[$index]} =~ ^/(boot(/efi)?)?$ ]]; then
# On RPi we need to use PARTUUID for Root/BootFS
(( $G_HW_MODEL > 9 )) || dev_entry="PARTUUID=${aDRIVE_PART_UUID[$index]}"
[[ ${aDRIVE_MOUNT_TARGET[$index]} == '/' ]] && options+=' 0 1' || options+=' 0 2' # dump + fsck flag
else
options+=',nofail,noauto,x-systemd.automount'
fi
echo "$dev_entry ${aDRIVE_MOUNT_TARGET[$index]} ${aDRIVE_FSTYPE[$index]:-auto} noatime,lazytime$options" >> "$fp_fstab_tmp"
fi
done < <(df -a --output=source --exclude-type=tmpfs --exclude-type=ecryptfs --exclude-type=vboxsf --exclude-type=glusterfs | sed "\|^/dev/root$|c$G_ROOTFS_DEV" | mawk '/\// && !x[$0]++')
# Check blkid for unmounted filesystems
while read -r line
do
[[ $line ]] || continue
# Exclude drives already found (mounted)
for i in "${aDRIVE_MOUNT_SOURCE[@]}"
do
[[ $i == "$line"* ]] && continue 2
done
# Failsafe: Must have a valid UUID! But blkid should print only drives with filesystems.
local uuid=$(blkid -s UUID -o value -c /dev/null "$line")
[[ $uuid ]] || continue
G_DIETPI-NOTIFY 2 " - Detected unmounted drive: $line"
Init_New_Device
aDRIVE_UUID[$index]=$uuid
aDRIVE_MOUNT_SOURCE[$index]=$line
aDRIVE_MOUNT_TARGET[$index]="/mnt/${aDRIVE_UUID[$index]}"
aDRIVE_SOURCE_DEVICE[$index]=$(Return_Drive_Without_Partitions "${aDRIVE_MOUNT_SOURCE[$index]}")
[[ ${aDRIVE_MOUNT_SOURCE[$index]} == /dev/${aDRIVE_SOURCE_DEVICE[$index]} ]] || aDRIVE_ISPARTITIONTABLE[$index]=1
(( ${aDRIVE_ISPARTITIONTABLE[$index]} )) && aDRIVE_PART_UUID[$index]=$(blkid -s PARTUUID -o value -c /dev/null "${aDRIVE_MOUNT_SOURCE[$index]}")
aDRIVE_FSTYPE[$index]=$(blkid -s TYPE -o value -c /dev/null "${aDRIVE_MOUNT_SOURCE[$index]}")
[[ ${aDRIVE_FSTYPE[$index]} ]] && aDRIVE_ISFILESYSTEM[$index]=1
done < <(blkid -o device -c /dev/null)
# Find unformatted drives
# - Exclude mtdblock devices: https://github.com/MichaIng/DietPi/issues/2067#issuecomment-422400520
while read -r line
do
[[ $line ]] || continue
# Exclude drives already found (formatted)
for i in "${aDRIVE_SOURCE_DEVICE[@]}"
do
[[ $line == $i* ]] && continue 2
done
G_DIETPI-NOTIFY 2 " - Detected unformatted drive: /dev/$line"
Init_New_Device
aDRIVE_MOUNT_SOURCE[$index]="/dev/$line"
aDRIVE_MOUNT_TARGET[$index]="/tmp/$line"
aDRIVE_SOURCE_DEVICE[$index]=$line
[[ -b ${aDRIVE_MOUNT_SOURCE[$index]} ]] || aDRIVE_ISACCESS[$index]=0
done < <(lsblk -nro NAME | sed '/^mtdblock[0-9]/d')
# Set required global flags and deps for all drives found
local deps=()
for i in "${!aDRIVE_MOUNT_SOURCE[@]}"
do
# Detect and set ROM drives
[[ ${aDRIVE_MOUNT_SOURCE[$i]} == '/dev/sr'* ]] && aDRIVE_ISROM[$i]=1
# Collect required APT packages for FS R/W access
if [[ ${aDRIVE_FSTYPE[$i]} == 'ext'[2-4] ]]; then
deps+=('e2fsprogs')
elif [[ ${aDRIVE_FSTYPE[$i]} == 'ntfs' ]]; then
deps+=('ntfs-3g')
elif [[ ${aDRIVE_FSTYPE[$i]} =~ 'hfs' ]]; then
deps+=('hfsplus')
elif [[ ${aDRIVE_FSTYPE[$i]} == 'exfat' ]]; then
# Install exFAT FUSE driver if the kernel does not support it natively yet, else purge it
# - Container: Assume host supports it
if (( $G_HW_MODEL == 75 )) || modprobe -nq exfat
then
dpkg-query -s 'exfat-fuse' &> /dev/null && G_AGP exfat-fuse
[[ -L '/sbin/mount.exfat' && ! -e '/sbin/mount.exfat' ]] && G_EXEC rm /sbin/mount.exfat
else
deps+=('exfat-fuse')
fi
fi
done
# Remove x-systemd.automount if not supported by kernel: https://github.com/MichaIng/DietPi/issues/1607#issuecomment-372030565
# - Container: Assume host supports it (relevant for network drives)
if (( $G_HW_MODEL != 75 )) && ! modprobe -nq autofs4
then
sed -Ei '/x-systemd\.automount/s/,(noauto|x-systemd\.automount)//g' "$fp_fstab_tmp"
G_DIETPI-NOTIFY 2 'autofs4 module not available in kernel, x-systemd.automount has been disabled, all drives will be mounted at boot instead'
fi
Update_Menu_Drive_Index
# Move new fstab in place and reload systemd generators
G_EXEC mv "$fp_fstab_tmp" /etc/fstab
G_EXEC systemctl daemon-reload
# Install required APT packages for FS R/W access
[[ $APT_CHECK == 0 && ${deps[0]} ]] && G_AG_CHECK_INSTALL_PREREQ "${deps[@]}" && APT_CHECK=1
# Workaround for exfat-fuse on Bullseye: https://github.com/MichaIng/DietPi/issues/5166
[[ $G_DISTRO -ge 6 && -e '/sbin/mount.exfat-fuse' && ! -e '/sbin/mount.exfat' ]] && G_EXEC ln -sf mount.exfat-fuse /sbin/mount.exfat
G_EXEC sync
}
Update_Menu_Drive_Index(){
local i
[[ $MENU_DRIVE_TARGET ]] && for i in "${!aDRIVE_MOUNT_TARGET[@]}"
do
[[ $MENU_DRIVE_TARGET == "${aDRIVE_MOUNT_TARGET[$i]}" ]] || continue
MENU_DRIVE_INDEX=$i
break
done
}
# $1=source
Return_Drive_Without_Partitions(){
local drive=${1#/dev/}
# IDE/SATA/SCSI/VirtIO
if [[ $1 == /dev/[shv]d[a-z][1-9] ]]; then
echo "${drive%[0-9]}"
# MMC/NVMe/loop
elif [[ $1 =~ ^/dev/(mmcblk|nvme[0-9]n|loop)[0-9]p[1-9]$ ]]; then
echo "${drive%p[0-9]}"
# No partition table or unknown block device type
else
echo "$drive"
fi
}
# $1=source $2=target
Mount_Drive(){
local source=$1
local target=$2
# If formatting is done to move the rootfs, continue with default mount point as it is temporary only anyway
if (( $MOVE_ROOTFS ))
then
G_WHIP_RETURNED_VALUE=$target
else
G_WHIP_DEFAULT_ITEM=$target
G_WHIP_INPUTBOX "Please enter the desired mount point.\n - Default and recommended = $target\n
NB: The path must start with /mnt/ and be unique. Spaces will be converted automatically to underscores (_)." || return 1
fi
if [[ $G_WHIP_RETURNED_VALUE == '/mnt/'* ]]
then
# Replace spaces with underscores
target=${G_WHIP_RETURNED_VALUE//[[:blank:]]/_}
else
G_WHIP_MSG "Invalid mount target location:\n - $G_WHIP_RETURNED_VALUE\n\nThe drive will now be mounted to:\n - $target"
fi
if [[ -d $target ]]
then
if [[ $(ls -A "$target") ]]
then
G_WHIP_MSG "[FAILED]:\n\nThe mount target directory already exists, and, contains data:\n - $target\n\nPlease retry, using a unique mount target location."
return 1
else
G_WHIP_YESNO "[WARNING]:\n\nThe mount target directory already exists, however, it does not contain any files or data at this time:\n - $target\n
Do you wish to ignore this warning, and, mount the drive regardless?" || return 1
fi
fi
# FS-specific mount options
local fs_type=$(blkid -s TYPE -o value "$source") options='noatime,lazytime,rw'
# - NTFS: Enable POSIX permissions and prevent splitting write buffers into 4k chunks: https://manpages.debian.org/ntfs-3g#OPTIONS
if [[ $fs_type == 'ntfs' ]]
then
options+=',permissions,big_writes'
# - exFAT: Grant (only) "dietpi" group R/W access: https://github.com/MichaIng/DietPi/issues/4680
elif [[ $fs_type == 'exfat' ]]
then
getent group dietpi > /dev/null && options+=',gid=dietpi,fmask=0002,dmask=0002'
fi
G_EXEC_NOEXIT=1 G_EXEC mkdir -p "$target" || return 1
G_EXEC_NOEXIT=1 G_EXEC mount -o "$options" "$source" "$target" || return 1
MENU_DRIVE_TARGET=$target
Init_Drives_and_Refresh
}
# $1=target
Unmount_Drive(){
local target=$1
G_EXEC_NOEXIT=1 G_EXEC umount "$target" || return 1
sed -i "\#[[:blank:]]${target}[[:blank:]]#d" /etc/fstab # Only needed for network drives currently, as unmounted physical drives won't be re-added via Init_Drives_and_Refresh
# Stop automount to unlock mount point
local automount=${target#/}
[[ $automount ]] && { automount=${automount//-/\\x2d}; automount=${automount//\//-}; }
[[ -f /run/systemd/generator/$automount.automount ]] && G_EXEC systemctl stop "$automount.automount"
G_EXEC_NOEXIT=1 G_EXEC rmdir "$target"
Init_Drives_and_Refresh
}
Resize_FS(){
if [[ ${aDRIVE_MOUNT_TARGET[$MENU_DRIVE_INDEX]} == '/' ]]; then
G_EXEC systemctl enable dietpi-fs_partition_resize
G_WHIP_YESNO 'RootFS resize will occur on next reboot.\n\nWould you like to reboot the system now?' && reboot || return
elif [[ ${aDRIVE_FSTYPE[$MENU_DRIVE_INDEX]} == ext[2-4] ]]; then
if (( ! ${aDRIVE_ISMOUNTED[$MENU_DRIVE_INDEX]} ))
then
G_DIETPI-NOTIFY 2 'Running full interactive fsck, required for unmounted ext filesystems to be resized...'
e2fsck -f "${aDRIVE_MOUNT_SOURCE[$MENU_DRIVE_INDEX]}"
fi
G_EXEC_NOEXIT=1 G_EXEC resize2fs "${aDRIVE_MOUNT_SOURCE[$MENU_DRIVE_INDEX]}"
elif [[ ${aDRIVE_FSTYPE[$MENU_DRIVE_INDEX]} == 'f2fs' ]]; then
(( ${aDRIVE_ISMOUNTED[$MENU_DRIVE_INDEX]} )) && G_EXEC_NOEXIT=1 G_EXEC umount "${aDRIVE_MOUNT_TARGET[$MENU_DRIVE_INDEX]}" || return 1
G_EXEC_NOEXIT=1 G_EXEC resize.f2fs "${aDRIVE_MOUNT_SOURCE[$MENU_DRIVE_INDEX]}"
(( ${aDRIVE_ISMOUNTED[$MENU_DRIVE_INDEX]} )) && G_EXEC_NOEXIT=1 G_EXEC mount "${aDRIVE_MOUNT_TARGET[$MENU_DRIVE_INDEX]}"
elif [[ ${aDRIVE_FSTYPE[$MENU_DRIVE_INDEX]} == 'btrfs' ]]; then
if (( ! ${aDRIVE_ISMOUNTED[$MENU_DRIVE_INDEX]} ))
then
G_EXEC_NOEXIT=1 G_EXEC mkdir -p /tmp/temporary_f2fs_mountpoint || return 1
G_EXEC_NOEXIT=1 G_EXEC mount "${aDRIVE_MOUNT_SOURCE[$MENU_DRIVE_INDEX]}" /tmp/temporary_f2fs_mountpoint || return 1
fi
G_EXEC_NOEXIT=1 G_EXEC btrfs filesystem resize max "${aDRIVE_MOUNT_TARGET[$MENU_DRIVE_INDEX]}"
if (( ! ${aDRIVE_ISMOUNTED[$MENU_DRIVE_INDEX]} ))
then
G_EXEC_NOEXIT=1 G_EXEC umount /tmp/temporary_f2fs_mountpoint
G_EXEC_NOEXIT=1 G_EXEC rmdir /tmp/temporary_f2fs_mountpoint
fi
fi
Init_Drives_and_Refresh
}
Run_Format(){
local i text_desc info_format_fs_type
local info_format_type_output='Drive format' # Used in complete message
# Failsafe: No partition table, force drive wipe - actually done in parent menu already
(( ${aDRIVE_ISPARTITIONTABLE[$MENU_DRIVE_INDEX]} )) || FORMAT_MODE=0
if (( $FORMAT_MODE )); then
text_desc=" - ${aDRIVE_MOUNT_SOURCE[$MENU_DRIVE_INDEX]}\n - UUID=${aDRIVE_UUID[$MENU_DRIVE_INDEX]}\n - Filesystem type: $format_type_text\n\nALL DATA on this PARTITION will be DELETED.\nDo you wish to continue?"
else
text_desc=" - /dev/${aDRIVE_SOURCE_DEVICE[$MENU_DRIVE_INDEX]}\n - UUID=${aDRIVE_UUID[$MENU_DRIVE_INDEX]}\n - Partition table: $partition_table_text\n - Filesystem type: $format_type_text\n\nALL DATA and PARTITIONS on this drive will be DELETED.\nDo you wish to continue?"
fi
if G_WHIP_YESNO "Ready to format:\n$text_desc"; then
# Partition format
if (( $FORMAT_MODE ))
then
info_format_type_output='Single partition format'
# Unmount
(( ${aDRIVE_ISMOUNTED[$MENU_DRIVE_INDEX]} )) && { Unmount_Drive "${aDRIVE_MOUNT_TARGET[$MENU_DRIVE_INDEX]}" || return 1; }
# Clear partition from device
G_DIETPI-NOTIFY 2 "Erasing partition: ${aDRIVE_MOUNT_SOURCE[$MENU_DRIVE_INDEX]}"
G_EXEC dd if=/dev/zero of="${aDRIVE_MOUNT_SOURCE[$MENU_DRIVE_INDEX]}" bs=4K count=1337
# Drive format: Create a new partition table
else
# Unmount and zero all partitions on device
# - Partition wipe must be done 1st, else UUIDs are still reported.
for i in "/dev/${aDRIVE_SOURCE_DEVICE[$MENU_DRIVE_INDEX]}"?*
do
[[ -b $i ]] || continue
local target=$(findmnt -Ufnro TARGET -S "$i")
[[ $target ]] && { Unmount_Drive "$target" || return 1; }
G_DIETPI-NOTIFY 2 "Writing zeros to partition: $i"
G_EXEC dd if=/dev/zero of="$i" bs=4K count=10
done
# Unmount whole drive in case of fs on drive without partition table
(( ${aDRIVE_ISMOUNTED[$MENU_DRIVE_INDEX]} )) && { Unmount_Drive "${aDRIVE_MOUNT_TARGET[$MENU_DRIVE_INDEX]}" || return 1; }
# Clear partition table from device
G_DIETPI-NOTIFY 2 "Erasing partition table: /dev/${aDRIVE_SOURCE_DEVICE[$MENU_DRIVE_INDEX]}"
G_EXEC dd if=/dev/zero of="/dev/${aDRIVE_SOURCE_DEVICE[$MENU_DRIVE_INDEX]}" bs=4K count=1337 # Block device wipe
# Create partition table type
local partition_table_type='gpt'
(( $FORMAT_GPT )) || partition_table_type='msdos'
G_DIETPI-NOTIFY 2 "Creating new $partition_table_type partition table"
G_EXEC parted -s "/dev/${aDRIVE_SOURCE_DEVICE[$MENU_DRIVE_INDEX]}" mklabel "$partition_table_type"
G_EXEC parted -s "/dev/${aDRIVE_SOURCE_DEVICE[$MENU_DRIVE_INDEX]}" mkpart primary 0% 100%
partprobe "/dev/${aDRIVE_SOURCE_DEVICE[$MENU_DRIVE_INDEX]}"
partx -u "/dev/${aDRIVE_SOURCE_DEVICE[$MENU_DRIVE_INDEX]}"
# Generate new aDRIVE_MOUNT_SOURCE location to use
# - hda1/sda1/vda1
if [[ ${aDRIVE_SOURCE_DEVICE[$MENU_DRIVE_INDEX]} == [shv]d[a-z] ]]
then
aDRIVE_MOUNT_SOURCE[$MENU_DRIVE_INDEX]="/dev/${aDRIVE_SOURCE_DEVICE[$MENU_DRIVE_INDEX]}1"
# - mmcblk0p1/nvme0n0p1/loop0p1
else
aDRIVE_MOUNT_SOURCE[$MENU_DRIVE_INDEX]="/dev/${aDRIVE_SOURCE_DEVICE[$MENU_DRIVE_INDEX]}p1"
fi
fi
# Format ext4
if (( $FORMAT_FILESYSTEM_TYPE == 0 )); then
# force
info_format_fs_type='ext4'
G_EXEC mkfs.ext4 -F -m 0 "${aDRIVE_MOUNT_SOURCE[$MENU_DRIVE_INDEX]}"
resize2fs "${aDRIVE_MOUNT_SOURCE[$MENU_DRIVE_INDEX]}"
# Format NTFS
elif (( $FORMAT_FILESYSTEM_TYPE == 1 )); then
# -f: fast format | -I: no indexing | -F: force
info_format_fs_type='NTFS'
G_EXEC mkfs.ntfs -f -I -F "${aDRIVE_MOUNT_SOURCE[$MENU_DRIVE_INDEX]}"
# Format FAT32
elif (( $FORMAT_FILESYSTEM_TYPE == 2 )); then
# -I: Use 1 partition on whole device
info_format_fs_type='FAT'
G_EXEC mkfs.fat -I "${aDRIVE_MOUNT_SOURCE[$MENU_DRIVE_INDEX]}"
# Format HFS+
elif (( $FORMAT_FILESYSTEM_TYPE == 3 )); then
info_format_fs_type='HFS+'
G_EXEC mkfs.hfsplus "${aDRIVE_MOUNT_SOURCE[$MENU_DRIVE_INDEX]}"
# Format Btrfs
elif (( $FORMAT_FILESYSTEM_TYPE == 4 )); then
# -f: force
info_format_fs_type='Btrfs'
G_EXEC mkfs.btrfs -f "${aDRIVE_MOUNT_SOURCE[$MENU_DRIVE_INDEX]}"
# Format f2fs
elif (( $FORMAT_FILESYSTEM_TYPE == 5 )); then
info_format_fs_type='F2FS'
G_EXEC mkfs.f2fs "${aDRIVE_MOUNT_SOURCE[$MENU_DRIVE_INDEX]}"
# Format exFAT
elif (( $FORMAT_FILESYSTEM_TYPE == 6 )); then
info_format_fs_type='exFAT'
G_EXEC mkfs.exfat "${aDRIVE_MOUNT_SOURCE[$MENU_DRIVE_INDEX]}"
# Format XFS
elif (( $FORMAT_FILESYSTEM_TYPE == 7 )); then
# -f: force
info_format_fs_type='XFS'
G_EXEC mkfs.xfs -f "${aDRIVE_MOUNT_SOURCE[$MENU_DRIVE_INDEX]}"
fi
G_EXEC sync # Sync to disk, as well to add a slight delay since XFS formatted filesystems do not return a UUID (below) immediately
G_DIETPI-NOTIFY 0 "Created $info_format_fs_type filesystem: ${aDRIVE_MOUNT_SOURCE[$MENU_DRIVE_INDEX]}"
FORMAT_COMPLETED=1
# Remove old mount point
[[ -e ${aDRIVE_MOUNT_TARGET[$MENU_DRIVE_INDEX]} ]] && G_EXEC_NOEXIT=1 G_EXEC rm -R "${aDRIVE_MOUNT_TARGET[$MENU_DRIVE_INDEX]}"
# Automatically mount it
local new_uuid=$(blkid -s UUID -o value -c /dev/null "${aDRIVE_MOUNT_SOURCE[$MENU_DRIVE_INDEX]}")
if ! Mount_Drive "${aDRIVE_MOUNT_SOURCE[$MENU_DRIVE_INDEX]}" "/mnt/$new_uuid"; then
MENU_DRIVE_TARGET="/mnt/$new_uuid"
Init_Drives_and_Refresh
fi
G_WHIP_MSG "[ OK ] Format completed\n
- Format Type : $info_format_type_output
- Filesystem Type : $info_format_fs_type
- Mount Source : ${aDRIVE_MOUNT_SOURCE[$MENU_DRIVE_INDEX]}
- Mount Target : $MENU_DRIVE_TARGET
- UUID : $new_uuid"
fi
}
RootFS_Move(){
(( $SERVICES_STOPPED )) || { /boot/dietpi/dietpi-services stop; SERVICES_STOPPED=1; }
# Install rsync
G_AG_CHECK_INSTALL_PREREQ rsync
# Mount rootfs to tmp mount point to allow rsync
# - rsync "-x" option prevents copying mounts content, but it copies permissions of mount point dirs according to mount options instead of those of the dir on the parent fs.
# - Since mount permissions might not be wanted for the underlying filesystem dir, we copy from a temporary mount point to assure that underlying rootfs content matches 100%.
[[ -d '/tmp/tmp_rootfs' ]] || G_EXEC mkdir /tmp/tmp_rootfs
G_EXEC mount "$G_ROOTFS_DEV" /tmp/tmp_rootfs
# Start rsync
if ! G_EXEC_NOEXIT=1 G_EXEC rsync -aHv --delete /tmp/tmp_rootfs/ "${aDRIVE_MOUNT_TARGET[$MENU_DRIVE_INDEX]}/"; then
G_DIETPI-NOTIFY 1 'Rsync has failed, RootFS transfer has been aborted.'
umount /tmp/tmp_rootfs
rmdir --ignore-fail-on-non-empty /tmp/tmp_rootfs
return 1
fi
# Remove volatile systemd service PrivateTmp dirs in /var/tmp and target drive mount point dir
rm -Rf "${aDRIVE_MOUNT_TARGET[$MENU_DRIVE_INDEX]}"/var/tmp/systemd-private-*
rmdir "${aDRIVE_MOUNT_TARGET[$MENU_DRIVE_INDEX]}${aDRIVE_MOUNT_TARGET[$MENU_DRIVE_INDEX]}"
# Update fstab
# - Remove automatic entry for target drive
G_EXEC sed -i "\@[[:blank:]]${aDRIVE_MOUNT_TARGET[$MENU_DRIVE_INDEX]}[[:blank:]]@d" "${aDRIVE_MOUNT_TARGET[$MENU_DRIVE_INDEX]}/etc/fstab"
# - Replace old with new rootfs entry
local dev_entry="UUID=${aDRIVE_UUID[$MENU_DRIVE_INDEX]}"
(( $G_HW_MODEL < 10 )) && dev_entry="PARTUUID=${aDRIVE_PART_UUID[$MENU_DRIVE_INDEX]}"
G_EXEC sed -i "\@[[:blank:]]/[[:blank:]]@c$dev_entry / ${aDRIVE_FSTYPE[$MENU_DRIVE_INDEX]} noatime,lazytime,rw 0 1" "${aDRIVE_MOUNT_TARGET[$MENU_DRIVE_INDEX]}/etc/fstab"
# Find and replace current root and rootfstype kernel command line entries
# - RPi: /boot/cmdline.txt
if (( $G_HW_MODEL < 10 ))
then
local rootfs_current=$(mawk '{for(i=1;i<=NF;i++) if($i~/^root=/) {print $i;exit}}' /boot/cmdline.txt)
G_EXEC sed -i "s#$rootfs_current#root=$dev_entry#g" /boot/cmdline.txt
local rootfstype_current=$(mawk '{for(i=1;i<=NF;i++) if($i~/^rootfstype=/) {print $i;exit}}' /boot/cmdline.txt)
[[ $rootfstype_current ]] && G_EXEC sed -i "s#$rootfstype_current#rootfstype=${aDRIVE_FSTYPE[$MENU_DRIVE_INDEX]}#g" /boot/cmdline.txt
# - Odroids: /boot/boot.ini
else
local rootfs_current=$(mawk '-F[" ]' '{for(i=1;i<=NF;i++) if($i~/^root=/) {print $i;exit}}' /boot/boot.ini)
G_EXEC sed -i "s#$rootfs_current#root=$dev_entry#g" /boot/boot.ini
local rootfstype_current=$(mawk '-F[" ]' '{for(i=1;i<=NF;i++) if($i~/^rootfstype=/) {print $i;exit}}' /boot/boot.ini)
[[ $rootfstype_current ]] && G_EXEC sed -i "s#$rootfstype_current#rootfstype=${aDRIVE_FSTYPE[$MENU_DRIVE_INDEX]}#g" /boot/boot.ini
fi
systemctl daemon-reload
sync
G_WHIP_MSG 'RootFS transfer has successfully completed.\n\nA reboot is required, please press <return> to reboot now.'
reboot
}
Toggle_WriteMode(){
local exit_status=0
local message_result=0
if (( ${aDRIVE_ISREADONLY_CURRENTLY[$MENU_DRIVE_INDEX]} )); then
message_result=$(mount -v -o remount,rw "${aDRIVE_MOUNT_SOURCE[$MENU_DRIVE_INDEX]}" 2>&1)
exit_status=$?
else
(( $SERVICES_STOPPED )) || { /boot/dietpi/dietpi-services stop; SERVICES_STOPPED=1; }
# RootFS, set fstab now, else, will not be applied to /etc/fstab during Init as already RO: https://github.com/MichaIng/DietPi/issues/2604
if [[ ${aDRIVE_MOUNT_TARGET[$MENU_DRIVE_INDEX]} == '/' ]]; then
local line_number=$(grep -n "[[:blank:]]${aDRIVE_MOUNT_TARGET[$MENU_DRIVE_INDEX]}[[:blank:]].*,rw" /etc/fstab | cut -d : -f 1)
sed -i "${line_number}s/,rw/,ro/" /etc/fstab
fi
message_result=$(mount -v -o remount,ro "${aDRIVE_MOUNT_SOURCE[$MENU_DRIVE_INDEX]}" 2>&1)
exit_status=$?
fi
(( $exit_status )) && G_WHIP_MSG "[FAILED] Could not apply\n\nError log:\n - $message_result"
Init_Drives_and_Refresh
}
TARGETMENUID=0
MENU_LASTITEM=
Menu_Main(){
# Generate menu
G_WHIP_MENU_ARRAY=()
# - Create a nice category list, to match items to their block device (eg: mmcblk0)
local acategory_list=()
local i j
for i in "${!aDRIVE_MOUNT_SOURCE[@]}"
do
local new_cat=1
for j in "${!acategory_list[@]}"
do
if [[ ${aDRIVE_SOURCE_DEVICE[$i]} == "${acategory_list[$j]}" ]]; then
new_cat=0
break
fi
done
# Add
(( $new_cat )) && acategory_list+=("${aDRIVE_SOURCE_DEVICE[$i]}")
done
# List all available drives, if no drive found, list info for user.
local drive_available=0
for i in "${!acategory_list[@]}"
do
drive_available=1
G_WHIP_MENU_ARRAY+=('' "●─ ${acategory_list[$i]} ")
for j in "${!aDRIVE_MOUNT_SOURCE[@]}"
do
if [[ ${aDRIVE_SOURCE_DEVICE[$j]} == "${acategory_list[$i]}" ]]; then
# Drive is fully mounted
if (( ${aDRIVE_ISMOUNTED[$j]} )); then
G_WHIP_MENU_ARRAY+=("${aDRIVE_MOUNT_TARGET[$j]}" ": ${aDRIVE_MOUNT_SOURCE[$j]} | ${aDRIVE_FSTYPE[$j]} | Capacity: ${aDRIVE_SIZE_TOTAL[$j]} | Used: ${aDRIVE_SIZE_USED[$j]} (${aDRIVE_SIZE_PERCENTUSED[$j]})")
# Drive has filesystem
elif (( ${aDRIVE_ISFILESYSTEM[$j]} )); then
G_WHIP_MENU_ARRAY+=("${aDRIVE_MOUNT_TARGET[$j]}" ": ${aDRIVE_MOUNT_SOURCE[$j]} | ${aDRIVE_FSTYPE[$j]} | Not mounted")
# Drive is not formatted
else
# ROM device with no ROM attached
if (( ${aDRIVE_ISROM[$j]} )); then
G_WHIP_MENU_ARRAY+=("${aDRIVE_MOUNT_TARGET[$j]}" ": ${aDRIVE_MOUNT_SOURCE[$j]} | Please insert media into the ROM device")
else
G_WHIP_MENU_ARRAY+=("${aDRIVE_MOUNT_TARGET[$j]}" ": ${aDRIVE_MOUNT_SOURCE[$j]} | No filesystem / format required")
fi
fi
fi
done
done
unset acategory_list
G_WHIP_MENU_ARRAY+=('' '●─ Global Options ')
G_WHIP_MENU_ARRAY+=('Idle Spindown' ': Set a global idle duration, before drives power down')
G_WHIP_MENU_ARRAY+=('' '●─ Add / Refresh Drives ')
G_WHIP_MENU_ARRAY+=('Add network drive' ': Select to mount networked drives')
if (( $drive_available )); then
G_WHIP_MENU_ARRAY+=('Refresh' ': Scan for recently added/removed drives')
else
G_WHIP_MENU_ARRAY+=('Refresh' ': No drives found. Insert a drive and select this option')
fi
# User data
local userdata_location_text="RootFS ($FP_USERDATA_CURRENT)"
[[ $FP_USERDATA_CURRENT == '/mnt/dietpi_userdata' ]] || userdata_location_text=$FP_USERDATA_CURRENT
G_WHIP_DEFAULT_ITEM=$MENU_LASTITEM
G_WHIP_BUTTON_CANCEL_TEXT='Exit'
if G_WHIP_MENU "Please select a drive to see available options.\n - User data location: $userdata_location_text"; then
MENU_LASTITEM=$G_WHIP_RETURNED_VALUE
# Refresh
if [[ $G_WHIP_RETURNED_VALUE == 'Refresh' ]]; then
Init_Drives_and_Refresh
elif [[ $G_WHIP_RETURNED_VALUE == 'Add network drive' ]]; then
TARGETMENUID=3 # Add network drive menu
elif [[ $G_WHIP_RETURNED_VALUE == 'Idle Spindown' ]]; then
local apm=127 # Hardcode to highest value that still allows spin-down
local current_spindown=
[[ -f '/etc/hdparm.conf' ]] && current_spindown=$(mawk '/spindown_time/{print $3;exit}' /etc/hdparm.conf)
disable_error=1 G_CHECK_VALIDINT "$current_spindown" 0 251 && G_WHIP_DEFAULT_ITEM=$current_spindown || G_WHIP_DEFAULT_ITEM=241
G_WHIP_MENU_ARRAY=('0' ': Disabled')
local minutes seconds text
for i in {12..251}
do
if (( $i < 241 )); then
minutes=$(( $i * 5 / 60 ))
seconds=$(( $i * 5 % 60 ))
text="$minutes Minute"
(( $minutes > 1 )) && text+='s'
(( $seconds )) && text+=", $seconds Seconds"
else
text=" $(( ( $i - 240 ) * 30 )) Minutes"
fi
G_WHIP_MENU_ARRAY+=("$i" ": $text")
done
if G_WHIP_MENU 'Please select an idle duration of time, before each drive is powered down:
- This will be applied to all drives on the system
- Not all drives support the feature of "hdparm" and visa versa. End results may vary.
- You can check status with "hdparm -C [sh]d[a-z]"'; then
# Since Debian Bullseye, spindown_time is not applied if APM is not supported by the drive. force_spindown_time is required to override that.
local spindown_setting='spindown_time'
(( $G_DISTRO > 5 )) && spindown_setting='force_spindown_time'
G_DIETPI-NOTIFY 2 'Applying spindown timeout to all drives now...'
hdparm -B "$apm" -S "$G_WHIP_RETURNED_VALUE" /dev/[sh]d[a-z]
G_DIETPI-NOTIFY 2 'Applying spindown timeout to /etc/hdparm.conf to be effective from next boot on...'
echo -e "apm = $apm\n$spindown_setting = $G_WHIP_RETURNED_VALUE" > /etc/hdparm.conf
fi
# Edit drive
elif [[ $G_WHIP_RETURNED_VALUE ]]; then
TARGETMENUID=1 # Drive menu
MENU_DRIVE_TARGET=$G_WHIP_RETURNED_VALUE
Update_Menu_Drive_Index
fi
else
Menu_Exit
fi
}
Notification(){
if (( $1 == 0 )); then
G_WHIP_MSG "[FAILED]\n\nYour DietPi userdata is currently located on this drive:\n - $FP_USERDATA_CURRENT\n\nThe requested option for this drive is not currently possible.\n\nPlease move your userdata elsewhere, before trying again:\nhttps://dietpi.com/docs/dietpi_tools/#quick-selections"
elif (( $1 == 1 )); then
G_WHIP_MSG "[FAILED]\n\nThe DietPi swap file is currently located on this drive:\n - $FP_SWAPFILE_CURRENT\n\nThe requested option for this drive is not currently possible.\n\nPlease move the swap file elsewhere, before trying again."
fi
}
Install_exFAT_Tools()
{
# Install FUSE driver if kernel does not support exFAT natively and on Bullseye prefer exfat-utils over exfatprogs
# - Container: Assume host supports it
local apackages=()
if (( $G_HW_MODEL == 75 )) || modprobe -q exfat
then
(( $G_DISTRO > 5 )) && apackages=('exfatprogs') || apackages=('exfat-utils') # exfatprogs not available until Bullseye
dpkg-query -s 'exfat-fuse' &> /dev/null && G_AGP exfat-fuse
else
(( $G_DISTRO > 6 )) && apackages=('exfatprogs') || apackages=('exfat-utils') # exfat-utils not available since Bookworm
apackages+=('exfat-fuse')
fi
G_AG_CHECK_INSTALL_PREREQ "${apackages[@]}"
}
# TARGETMENUID=1
Menu_Drive(){
G_WHIP_MENU_ARRAY=()
local partition_contains_userdata=0
local partition_contains_swapfile=0
local whiptail_desc="Mount target: ${aDRIVE_MOUNT_TARGET[$MENU_DRIVE_INDEX]}"
whiptail_desc+="\nMount source: ${aDRIVE_MOUNT_SOURCE[$MENU_DRIVE_INDEX]}"