improvements to dialog
This commit is contained in:
311
cleanup.sh
311
cleanup.sh
@@ -38,79 +38,274 @@ echo " Forensic Disk Cleanup Tool"
|
|||||||
echo "=========================================="
|
echo "=========================================="
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Show current loop devices
|
# Function to get user loop devices (excluding system paths)
|
||||||
print_info "Current loop devices:"
|
get_user_loop_devices() {
|
||||||
losetup -l
|
losetup -l -n -O NAME,BACK-FILE | grep -v "/var/lib/snapd" | grep -v "/snap/" | grep -v "^$" | awk '{if (NF >= 2) print $0}'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to display user loop devices nicely
|
||||||
|
show_user_loop_devices() {
|
||||||
|
local devices=$(get_user_loop_devices)
|
||||||
|
|
||||||
|
if [ -z "$devices" ]; then
|
||||||
|
echo "No user loop devices found (system devices filtered out)"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Active disk images:"
|
||||||
|
echo ""
|
||||||
|
printf "%-15s %s\n" "LOOP DEVICE" "IMAGE FILE"
|
||||||
|
echo "------------------------------------------------------------"
|
||||||
|
|
||||||
|
while IFS= read -r line; do
|
||||||
|
local device=$(echo "$line" | awk '{print $1}')
|
||||||
|
local file=$(echo "$line" | awk '{$1=""; print $0}' | sed 's/^ *//')
|
||||||
|
printf "%-15s %s\n" "$device" "$file"
|
||||||
|
done <<< "$devices"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
read -p "Enter the disk image filename to clean up (or 'all' for all loop devices): " TARGET
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
if [ "$TARGET" = "all" ]; then
|
# Function to unmount all partitions of a loop device
|
||||||
print_warning "This will unmount and detach ALL loop devices!"
|
unmount_loop_partitions() {
|
||||||
read -p "Are you sure? (yes/no): " CONFIRM
|
local loop_device=$1
|
||||||
|
local unmounted=0
|
||||||
|
|
||||||
if [ "$CONFIRM" = "yes" ]; then
|
# Try both naming conventions
|
||||||
# Get all loop devices
|
for part in ${loop_device}p* ${loop_device}[0-9]*; do
|
||||||
LOOP_DEVICES=$(losetup -l -n -O NAME | tail -n +2)
|
if [ -e "$part" ]; then
|
||||||
|
local mount_point=$(findmnt -n -o TARGET "$part" 2>/dev/null || true)
|
||||||
for LOOP in $LOOP_DEVICES; do
|
if [ -n "$mount_point" ]; then
|
||||||
print_info "Processing $LOOP..."
|
print_info "Unmounting $part from $mount_point"
|
||||||
|
if umount "$part"; then
|
||||||
# Try to unmount all partitions
|
print_success "Unmounted $part"
|
||||||
for PART in ${LOOP}p* ${LOOP}[0-9]*; do
|
unmounted=$((unmounted + 1))
|
||||||
if [ -e "$PART" ]; then
|
|
||||||
MOUNT_POINT=$(findmnt -n -o TARGET "$PART" 2>/dev/null || true)
|
|
||||||
if [ -n "$MOUNT_POINT" ]; then
|
|
||||||
print_info "Unmounting $PART from $MOUNT_POINT"
|
|
||||||
umount "$PART" || print_warning "Failed to unmount $PART"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Detach loop device
|
|
||||||
print_info "Detaching $LOOP"
|
|
||||||
losetup -d "$LOOP" || print_warning "Failed to detach $LOOP"
|
|
||||||
done
|
|
||||||
|
|
||||||
print_success "Cleanup complete"
|
|
||||||
else
|
else
|
||||||
|
print_warning "Failed to unmount $part"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
return $unmounted
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to detach loop device
|
||||||
|
detach_loop_device() {
|
||||||
|
local loop_device=$1
|
||||||
|
|
||||||
|
print_info "Detaching $loop_device"
|
||||||
|
|
||||||
|
# Check if device still exists in losetup output
|
||||||
|
if ! losetup -l | grep -q "^$loop_device "; then
|
||||||
|
print_success "Loop device already detached"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if losetup -d "$loop_device"; then
|
||||||
|
print_success "Detached $loop_device"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
print_error "Failed to detach $loop_device"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Automatic mode
|
||||||
|
auto_cleanup() {
|
||||||
|
local devices=$(get_user_loop_devices)
|
||||||
|
|
||||||
|
if [ -z "$devices" ]; then
|
||||||
|
print_info "No user loop devices to clean up"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "The following loop devices will be cleaned up:"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
local count=0
|
||||||
|
while IFS= read -r line; do
|
||||||
|
local device=$(echo "$line" | awk '{print $1}')
|
||||||
|
local file=$(echo "$line" | awk '{$1=""; print $0}' | sed 's/^ *//')
|
||||||
|
echo " [$((count+1))] $device -> $file"
|
||||||
|
count=$((count+1))
|
||||||
|
done <<< "$devices"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
read -p "Clean up all $count device(s)? (yes/no): " confirm
|
||||||
|
|
||||||
|
if [ "$confirm" != "yes" ]; then
|
||||||
print_info "Cancelled"
|
print_info "Cancelled"
|
||||||
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
local success=0
|
||||||
|
local failed=0
|
||||||
|
|
||||||
|
while IFS= read -r line; do
|
||||||
|
local device=$(echo "$line" | awk '{print $1}')
|
||||||
|
local file=$(echo "$line" | awk '{$1=""; print $0}' | sed 's/^ *//')
|
||||||
|
|
||||||
|
echo "Processing: $device"
|
||||||
|
unmount_loop_partitions "$device"
|
||||||
|
|
||||||
|
if detach_loop_device "$device"; then
|
||||||
|
success=$((success+1))
|
||||||
else
|
else
|
||||||
if [ ! -f "$TARGET" ]; then
|
failed=$((failed+1))
|
||||||
print_error "File not found: $TARGET"
|
fi
|
||||||
exit 1
|
echo ""
|
||||||
|
done <<< "$devices"
|
||||||
|
|
||||||
|
echo "=========================================="
|
||||||
|
print_success "Cleaned up: $success device(s)"
|
||||||
|
if [ $failed -gt 0 ]; then
|
||||||
|
print_warning "Failed: $failed device(s)"
|
||||||
|
fi
|
||||||
|
echo "=========================================="
|
||||||
|
}
|
||||||
|
|
||||||
|
# Manual mode - specific file
|
||||||
|
manual_cleanup() {
|
||||||
|
local target=$1
|
||||||
|
|
||||||
|
if [ ! -f "$target" ]; then
|
||||||
|
print_error "File not found: $target"
|
||||||
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Find loop device associated with this file
|
# Find loop device associated with this file
|
||||||
LOOP_DEVICE=$(losetup -l -n -O NAME,BACK-FILE | grep "$(realpath $TARGET)" | awk '{print $1}')
|
local loop_device=$(losetup -l -n -O NAME,BACK-FILE | grep "$(realpath $target)" | awk '{print $1}')
|
||||||
|
|
||||||
if [ -z "$LOOP_DEVICE" ]; then
|
if [ -z "$loop_device" ]; then
|
||||||
print_warning "No loop device found for $TARGET"
|
print_warning "No loop device found for: $target"
|
||||||
|
print_info "The file may already be detached"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_info "Found loop device: $loop_device"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
unmount_loop_partitions "$loop_device"
|
||||||
|
detach_loop_device "$loop_device"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
print_success "Cleanup complete for: $target"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Interactive mode
|
||||||
|
interactive_cleanup() {
|
||||||
|
local devices=$(get_user_loop_devices)
|
||||||
|
|
||||||
|
if [ -z "$devices" ]; then
|
||||||
|
print_info "No user loop devices to clean up"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Select a device to clean up:"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
local -a device_array
|
||||||
|
local -a file_array
|
||||||
|
local count=0
|
||||||
|
|
||||||
|
while IFS= read -r line; do
|
||||||
|
local device=$(echo "$line" | awk '{print $1}')
|
||||||
|
local file=$(echo "$line" | awk '{$1=""; print $0}' | sed 's/^ *//')
|
||||||
|
device_array[$count]=$device
|
||||||
|
file_array[$count]=$file
|
||||||
|
echo " [$((count+1))] $device -> $file"
|
||||||
|
count=$((count+1))
|
||||||
|
done <<< "$devices"
|
||||||
|
|
||||||
|
echo " [a] Clean up ALL"
|
||||||
|
echo " [q] Quit"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
read -p "Enter selection: " selection
|
||||||
|
|
||||||
|
if [ "$selection" = "q" ]; then
|
||||||
|
print_info "Cancelled"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$selection" = "a" ]; then
|
||||||
|
echo ""
|
||||||
|
auto_cleanup
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate numeric input
|
||||||
|
if ! [[ "$selection" =~ ^[0-9]+$ ]] || [ "$selection" -lt 1 ] || [ "$selection" -gt $count ]; then
|
||||||
|
print_error "Invalid selection"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local idx=$((selection-1))
|
||||||
|
local device="${device_array[$idx]}"
|
||||||
|
local file="${file_array[$idx]}"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
print_info "Cleaning up: $device -> $file"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
unmount_loop_partitions "$device"
|
||||||
|
detach_loop_device "$device"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
print_success "Cleanup complete"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main menu
|
||||||
|
main() {
|
||||||
|
# Check if any user loop devices exist
|
||||||
|
if ! show_user_loop_devices; then
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
print_info "Found loop device: $LOOP_DEVICE"
|
echo "Cleanup Options:"
|
||||||
|
echo " 1) Select specific device (interactive)"
|
||||||
# Try to unmount all partitions
|
echo " 2) Clean up all user devices (automatic)"
|
||||||
for PART in ${LOOP_DEVICE}p* ${LOOP_DEVICE}[0-9]*; do
|
echo " 3) Enter filename manually"
|
||||||
if [ -e "$PART" ]; then
|
echo " 4) Quit"
|
||||||
MOUNT_POINT=$(findmnt -n -o TARGET "$PART" 2>/dev/null || true)
|
echo ""
|
||||||
if [ -n "$MOUNT_POINT" ]; then
|
read -p "Select option [1-4]: " option
|
||||||
print_info "Unmounting $PART from $MOUNT_POINT"
|
|
||||||
umount "$PART" || print_warning "Failed to unmount $PART"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Detach loop device
|
|
||||||
print_info "Detaching $LOOP_DEVICE"
|
|
||||||
losetup -d "$LOOP_DEVICE"
|
|
||||||
|
|
||||||
print_success "Cleanup complete for $TARGET"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
print_info "Current loop devices after cleanup:"
|
|
||||||
losetup -l
|
case $option in
|
||||||
|
1)
|
||||||
|
interactive_cleanup
|
||||||
|
;;
|
||||||
|
2)
|
||||||
|
auto_cleanup
|
||||||
|
;;
|
||||||
|
3)
|
||||||
|
read -p "Enter disk image filename: " filename
|
||||||
echo ""
|
echo ""
|
||||||
|
manual_cleanup "$filename"
|
||||||
|
;;
|
||||||
|
4)
|
||||||
|
print_info "Cancelled"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
print_error "Invalid option"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Show final state
|
||||||
|
if get_user_loop_devices >/dev/null 2>&1; then
|
||||||
|
echo "Remaining loop devices:"
|
||||||
|
show_user_loop_devices
|
||||||
|
else
|
||||||
|
print_success "All user loop devices cleaned up"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run main
|
||||||
|
main
|
||||||
638
pseudodisk.sh
638
pseudodisk.sh
@@ -1,7 +1,8 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Forensic Practice Disk Image Creator
|
# Forensic Practice Disk Image Creator - Enhanced Version
|
||||||
# Creates disk images with various filesystems for forensic analysis practice
|
# Creates disk images with various filesystems for forensic analysis practice
|
||||||
|
# Now with improved UX, sanity checks, and extended filesystem support
|
||||||
|
|
||||||
set -e # Exit on error
|
set -e # Exit on error
|
||||||
|
|
||||||
@@ -10,6 +11,8 @@ RED='\033[0;31m'
|
|||||||
GREEN='\033[0;32m'
|
GREEN='\033[0;32m'
|
||||||
YELLOW='\033[1;33m'
|
YELLOW='\033[1;33m'
|
||||||
BLUE='\033[0;34m'
|
BLUE='\033[0;34m'
|
||||||
|
CYAN='\033[0;36m'
|
||||||
|
MAGENTA='\033[0;35m'
|
||||||
NC='\033[0m' # No Color
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
# Function to print colored messages
|
# Function to print colored messages
|
||||||
@@ -29,6 +32,45 @@ print_error() {
|
|||||||
echo -e "${RED}[ERROR]${NC} $1"
|
echo -e "${RED}[ERROR]${NC} $1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print_note() {
|
||||||
|
echo -e "${CYAN}[NOTE]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_tip() {
|
||||||
|
echo -e "${MAGENTA}[TIP]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Filesystem size constraints (in MB)
|
||||||
|
declare -A FS_MIN_SIZE
|
||||||
|
FS_MIN_SIZE["fat12"]=1
|
||||||
|
FS_MIN_SIZE["fat16"]=5
|
||||||
|
FS_MIN_SIZE["fat32"]=33
|
||||||
|
FS_MIN_SIZE["exfat"]=1
|
||||||
|
FS_MIN_SIZE["ntfs"]=7
|
||||||
|
FS_MIN_SIZE["ext2"]=1
|
||||||
|
FS_MIN_SIZE["ext3"]=1
|
||||||
|
FS_MIN_SIZE["ext4"]=1
|
||||||
|
FS_MIN_SIZE["xfs"]=16
|
||||||
|
FS_MIN_SIZE["hfsplus"]=8
|
||||||
|
FS_MIN_SIZE["apfs"]=1
|
||||||
|
FS_MIN_SIZE["swap"]=1
|
||||||
|
FS_MIN_SIZE["unallocated"]=1
|
||||||
|
|
||||||
|
declare -A FS_MAX_SIZE
|
||||||
|
FS_MAX_SIZE["fat12"]=16
|
||||||
|
FS_MAX_SIZE["fat16"]=2048
|
||||||
|
FS_MAX_SIZE["fat32"]=2097152 # 2TB in theory, but practical limit
|
||||||
|
FS_MAX_SIZE["exfat"]=16777216 # 16 TB practical
|
||||||
|
FS_MAX_SIZE["ntfs"]=16777216 # 16 TB+
|
||||||
|
FS_MAX_SIZE["ext2"]=16777216
|
||||||
|
FS_MAX_SIZE["ext3"]=16777216
|
||||||
|
FS_MAX_SIZE["ext4"]=16777216
|
||||||
|
FS_MAX_SIZE["xfs"]=16777216
|
||||||
|
FS_MAX_SIZE["hfsplus"]=2097152 # 2TB
|
||||||
|
FS_MAX_SIZE["apfs"]=16777216
|
||||||
|
FS_MAX_SIZE["swap"]=128000 # 128GB practical max
|
||||||
|
FS_MAX_SIZE["unallocated"]=16777216 # No real limit
|
||||||
|
|
||||||
# Check if running as root
|
# Check if running as root
|
||||||
check_root() {
|
check_root() {
|
||||||
if [ "$EUID" -ne 0 ]; then
|
if [ "$EUID" -ne 0 ]; then
|
||||||
@@ -59,11 +101,11 @@ check_filesystem_tools() {
|
|||||||
echo "Checking filesystem tool availability..."
|
echo "Checking filesystem tool availability..."
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# NTFS
|
# FAT12/16
|
||||||
if command -v mkfs.ntfs >/dev/null 2>&1; then
|
if command -v mkfs.fat >/dev/null 2>&1 || command -v mkfs.vfat >/dev/null 2>&1; then
|
||||||
echo -e " ${GREEN}✓${NC} NTFS (mkfs.ntfs available)"
|
echo -e " ${GREEN}✓${NC} FAT12/16 (mkfs.fat available)"
|
||||||
else
|
else
|
||||||
echo -e " ${YELLOW}✗${NC} NTFS (install: sudo apt-get install ntfs-3g)"
|
echo -e " ${YELLOW}✗${NC} FAT12/16 (install: sudo apt-get install dosfstools)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# FAT32
|
# FAT32
|
||||||
@@ -77,7 +119,14 @@ check_filesystem_tools() {
|
|||||||
if command -v mkfs.exfat >/dev/null 2>&1; then
|
if command -v mkfs.exfat >/dev/null 2>&1; then
|
||||||
echo -e " ${GREEN}✓${NC} exFAT (mkfs.exfat available)"
|
echo -e " ${GREEN}✓${NC} exFAT (mkfs.exfat available)"
|
||||||
else
|
else
|
||||||
echo -e " ${YELLOW}✗${NC} exFAT (install: sudo apt-get install exfat-fuse exfat-utils)"
|
echo -e " ${YELLOW}✗${NC} exFAT (install: sudo apt-get install exfatprogs)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# NTFS
|
||||||
|
if command -v mkfs.ntfs >/dev/null 2>&1; then
|
||||||
|
echo -e " ${GREEN}✓${NC} NTFS (mkfs.ntfs available)"
|
||||||
|
else
|
||||||
|
echo -e " ${YELLOW}✗${NC} NTFS (install: sudo apt-get install ntfs-3g)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ext2/3/4
|
# ext2/3/4
|
||||||
@@ -94,6 +143,20 @@ check_filesystem_tools() {
|
|||||||
echo -e " ${YELLOW}✗${NC} XFS (install: sudo apt-get install xfsprogs)"
|
echo -e " ${YELLOW}✗${NC} XFS (install: sudo apt-get install xfsprogs)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# HFS+
|
||||||
|
if command -v mkfs.hfsplus >/dev/null 2>&1; then
|
||||||
|
echo -e " ${GREEN}✓${NC} HFS+ (mkfs.hfsplus available)"
|
||||||
|
else
|
||||||
|
echo -e " ${YELLOW}✗${NC} HFS+ (install: sudo apt-get install hfsprogs)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# APFS
|
||||||
|
if command -v mkfs.apfs >/dev/null 2>&1; then
|
||||||
|
echo -e " ${GREEN}✓${NC} APFS (mkfs.apfs available)"
|
||||||
|
else
|
||||||
|
echo -e " ${YELLOW}✗${NC} APFS (limited Linux support - not recommended)"
|
||||||
|
fi
|
||||||
|
|
||||||
# swap
|
# swap
|
||||||
if command -v mkswap >/dev/null 2>&1; then
|
if command -v mkswap >/dev/null 2>&1; then
|
||||||
echo -e " ${GREEN}✓${NC} swap (mkswap available)"
|
echo -e " ${GREEN}✓${NC} swap (mkswap available)"
|
||||||
@@ -104,11 +167,125 @@ check_filesystem_tools() {
|
|||||||
echo ""
|
echo ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Validate filesystem label
|
||||||
|
validate_label() {
|
||||||
|
local fs=$1
|
||||||
|
local label=$2
|
||||||
|
|
||||||
|
case $fs in
|
||||||
|
fat12|fat16|fat32|vfat)
|
||||||
|
if [ ${#label} -gt 11 ]; then
|
||||||
|
print_error "FAT label must be 11 characters or less"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
# FAT labels should be uppercase and no lowercase allowed
|
||||||
|
if [[ "$label" =~ [a-z] ]]; then
|
||||||
|
print_warning "FAT labels are typically uppercase. Converting..."
|
||||||
|
echo "${label^^}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
ntfs)
|
||||||
|
if [ ${#label} -gt 32 ]; then
|
||||||
|
print_error "NTFS label must be 32 characters or less"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
ext2|ext3|ext4)
|
||||||
|
if [ ${#label} -gt 16 ]; then
|
||||||
|
print_error "ext2/3/4 label must be 16 characters or less"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
xfs)
|
||||||
|
if [ ${#label} -gt 12 ]; then
|
||||||
|
print_error "XFS label must be 12 characters or less"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
exfat)
|
||||||
|
if [ ${#label} -gt 15 ]; then
|
||||||
|
print_error "exFAT label must be 15 characters or less"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
hfsplus)
|
||||||
|
if [ ${#label} -gt 27 ]; then
|
||||||
|
print_error "HFS+ label must be 27 characters or less"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "$label"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if size is appropriate for filesystem
|
||||||
|
validate_fs_size() {
|
||||||
|
local fs=$1
|
||||||
|
local size=$2
|
||||||
|
|
||||||
|
if [ "$size" = "remaining" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local min=${FS_MIN_SIZE[$fs]}
|
||||||
|
local max=${FS_MAX_SIZE[$fs]}
|
||||||
|
|
||||||
|
if [ -n "$min" ] && [ "$size" -lt "$min" ]; then
|
||||||
|
print_error "Partition size ${size}MB is too small for $fs (minimum: ${min}MB)"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$max" ] && [ "$size" -gt "$max" ]; then
|
||||||
|
print_warning "Partition size ${size}MB exceeds recommended maximum for $fs (${max}MB)"
|
||||||
|
read -p "Continue anyway? (y/n): " continue
|
||||||
|
if [ "$continue" != "y" ]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Specific warnings
|
||||||
|
case $fs in
|
||||||
|
fat12)
|
||||||
|
if [ "$size" -gt 16 ]; then
|
||||||
|
print_error "FAT12 cannot exceed 16MB"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
fat16)
|
||||||
|
if [ "$size" -lt 16 ]; then
|
||||||
|
print_warning "Partition is small enough for FAT12, but you selected FAT16"
|
||||||
|
fi
|
||||||
|
if [ "$size" -gt 2048 ]; then
|
||||||
|
print_error "FAT16 cannot exceed 2GB (2048MB)"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
fat32)
|
||||||
|
if [ "$size" -lt 33 ]; then
|
||||||
|
print_error "FAT32 requires at least 33MB"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
xfs)
|
||||||
|
if [ "$size" -lt 16 ]; then
|
||||||
|
print_error "XFS requires at least 16MB"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
# Display banner
|
# Display banner
|
||||||
show_banner() {
|
show_banner() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "=========================================="
|
echo "=========================================="
|
||||||
echo " Forensic Disk Image Creator"
|
echo " Forensic Disk Image Creator"
|
||||||
|
echo " Enhanced Edition v2.0"
|
||||||
echo "=========================================="
|
echo "=========================================="
|
||||||
echo ""
|
echo ""
|
||||||
}
|
}
|
||||||
@@ -119,11 +296,23 @@ get_filename() {
|
|||||||
read -p "Enter output filename (default: forensic_disk.dd): " FILENAME
|
read -p "Enter output filename (default: forensic_disk.dd): " FILENAME
|
||||||
FILENAME=${FILENAME:-forensic_disk.dd}
|
FILENAME=${FILENAME:-forensic_disk.dd}
|
||||||
|
|
||||||
|
# Validate filename
|
||||||
|
if [[ "$FILENAME" =~ [^a-zA-Z0-9._-] ]]; then
|
||||||
|
print_warning "Filename contains special characters. This may cause issues."
|
||||||
|
read -p "Continue with this filename? (y/n): " continue
|
||||||
|
if [ "$continue" != "y" ]; then
|
||||||
|
get_filename
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -f "$FILENAME" ]; then
|
if [ -f "$FILENAME" ]; then
|
||||||
read -p "File already exists. Overwrite? (y/n): " OVERWRITE
|
print_warning "File already exists: $FILENAME"
|
||||||
|
read -p "Overwrite? (y/n): " OVERWRITE
|
||||||
if [ "$OVERWRITE" != "y" ]; then
|
if [ "$OVERWRITE" != "y" ]; then
|
||||||
print_info "Exiting..."
|
print_info "Please choose a different filename"
|
||||||
exit 0
|
get_filename
|
||||||
|
return
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -136,29 +325,41 @@ get_disk_size() {
|
|||||||
echo " 2) 500 MB (medium)"
|
echo " 2) 500 MB (medium)"
|
||||||
echo " 3) 1 GB (standard)"
|
echo " 3) 1 GB (standard)"
|
||||||
echo " 4) 5 GB (large)"
|
echo " 4) 5 GB (large)"
|
||||||
echo " 5) Custom size"
|
echo " 5) 10 GB (very large)"
|
||||||
|
echo " 6) Custom size"
|
||||||
echo ""
|
echo ""
|
||||||
read -p "Select disk size [1-5]: " SIZE_CHOICE
|
read -p "Select disk size [1-6]: " SIZE_CHOICE
|
||||||
|
|
||||||
case $SIZE_CHOICE in
|
case $SIZE_CHOICE in
|
||||||
1) DISK_SIZE_MB=100 ;;
|
1) DISK_SIZE_MB=100 ;;
|
||||||
2) DISK_SIZE_MB=500 ;;
|
2) DISK_SIZE_MB=500 ;;
|
||||||
3) DISK_SIZE_MB=1024 ;;
|
3) DISK_SIZE_MB=1024 ;;
|
||||||
4) DISK_SIZE_MB=5120 ;;
|
4) DISK_SIZE_MB=5120 ;;
|
||||||
5)
|
5) DISK_SIZE_MB=10240 ;;
|
||||||
|
6)
|
||||||
read -p "Enter size in MB: " DISK_SIZE_MB
|
read -p "Enter size in MB: " DISK_SIZE_MB
|
||||||
if ! [[ "$DISK_SIZE_MB" =~ ^[0-9]+$ ]] || [ "$DISK_SIZE_MB" -lt 10 ]; then
|
if ! [[ "$DISK_SIZE_MB" =~ ^[0-9]+$ ]] || [ "$DISK_SIZE_MB" -lt 10 ]; then
|
||||||
print_error "Invalid size. Must be at least 10 MB"
|
print_error "Invalid size. Must be at least 10 MB"
|
||||||
exit 1
|
get_disk_size
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
if [ "$DISK_SIZE_MB" -gt 102400 ]; then
|
||||||
|
print_warning "Very large disk size (>100GB). This may take a while."
|
||||||
|
read -p "Continue? (y/n): " continue
|
||||||
|
if [ "$continue" != "y" ]; then
|
||||||
|
get_disk_size
|
||||||
|
return
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
print_error "Invalid choice"
|
print_error "Invalid choice"
|
||||||
exit 1
|
get_disk_size
|
||||||
|
return
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
print_info "Selected disk size: ${DISK_SIZE_MB} MB"
|
print_info "Selected disk size: ${DISK_SIZE_MB} MB ($(echo "scale=2; $DISK_SIZE_MB/1024" | bc) GB)"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Get initialization method
|
# Get initialization method
|
||||||
@@ -166,18 +367,29 @@ get_init_method() {
|
|||||||
echo ""
|
echo ""
|
||||||
echo "Initialization Method:"
|
echo "Initialization Method:"
|
||||||
echo " 1) /dev/zero (Fast, zeros - forensically predictable)"
|
echo " 1) /dev/zero (Fast, zeros - forensically predictable)"
|
||||||
echo " 2) /dev/random (Slow, random data - more realistic)"
|
echo " 2) /dev/urandom (Slow, random data - more realistic)"
|
||||||
echo " 3) fallocate (Fastest, sparse file)"
|
echo " 3) fallocate (Fastest, sparse file - testing only)"
|
||||||
|
echo ""
|
||||||
|
print_tip "For forensic practice, /dev/zero (option 1) is recommended"
|
||||||
echo ""
|
echo ""
|
||||||
read -p "Select initialization method [1-3]: " INIT_CHOICE
|
read -p "Select initialization method [1-3]: " INIT_CHOICE
|
||||||
|
|
||||||
case $INIT_CHOICE in
|
case $INIT_CHOICE in
|
||||||
1) INIT_METHOD="zero" ;;
|
1) INIT_METHOD="zero" ;;
|
||||||
2) INIT_METHOD="random" ;;
|
2)
|
||||||
3) INIT_METHOD="fallocate" ;;
|
INIT_METHOD="random"
|
||||||
|
print_warning "Random initialization can be VERY slow for large disks"
|
||||||
|
estimated_time=$(echo "scale=0; $DISK_SIZE_MB/10" | bc)
|
||||||
|
print_info "Estimated time: ~${estimated_time} seconds"
|
||||||
|
;;
|
||||||
|
3)
|
||||||
|
INIT_METHOD="fallocate"
|
||||||
|
print_warning "Sparse files may not be suitable for all forensic scenarios"
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
print_error "Invalid choice"
|
print_error "Invalid choice"
|
||||||
exit 1
|
get_init_method
|
||||||
|
return
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
@@ -191,14 +403,25 @@ get_partition_scheme() {
|
|||||||
echo " 1) GPT (GUID Partition Table) - Modern, Windows 10/11 default"
|
echo " 1) GPT (GUID Partition Table) - Modern, Windows 10/11 default"
|
||||||
echo " 2) MBR (Master Boot Record) - Legacy, compatible with older systems"
|
echo " 2) MBR (Master Boot Record) - Legacy, compatible with older systems"
|
||||||
echo ""
|
echo ""
|
||||||
|
print_tip "GPT is recommended for modern systems and disks >2TB"
|
||||||
|
echo ""
|
||||||
read -p "Select partition scheme [1-2]: " PARTITION_CHOICE
|
read -p "Select partition scheme [1-2]: " PARTITION_CHOICE
|
||||||
|
|
||||||
case $PARTITION_CHOICE in
|
case $PARTITION_CHOICE in
|
||||||
1) PARTITION_SCHEME="gpt" ;;
|
1) PARTITION_SCHEME="gpt" ;;
|
||||||
2) PARTITION_SCHEME="msdos" ;;
|
2)
|
||||||
|
PARTITION_SCHEME="msdos"
|
||||||
|
if [ "$DISK_SIZE_MB" -gt 2097152 ]; then
|
||||||
|
print_error "MBR does not support disks larger than 2TB"
|
||||||
|
print_info "Please select GPT or reduce disk size"
|
||||||
|
get_partition_scheme
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
print_error "Invalid choice"
|
print_error "Invalid choice"
|
||||||
exit 1
|
get_partition_scheme
|
||||||
|
return
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
@@ -212,7 +435,12 @@ get_partition_count() {
|
|||||||
|
|
||||||
if ! [[ "$PARTITION_COUNT" =~ ^[1-4]$ ]]; then
|
if ! [[ "$PARTITION_COUNT" =~ ^[1-4]$ ]]; then
|
||||||
print_error "Invalid number. Must be between 1 and 4"
|
print_error "Invalid number. Must be between 1 and 4"
|
||||||
exit 1
|
get_partition_count
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$PARTITION_COUNT" -gt 1 ]; then
|
||||||
|
print_note "The last partition will automatically use all remaining space"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
print_info "Creating $PARTITION_COUNT partition(s)"
|
print_info "Creating $PARTITION_COUNT partition(s)"
|
||||||
@@ -221,6 +449,8 @@ get_partition_count() {
|
|||||||
# Get partition configurations
|
# Get partition configurations
|
||||||
get_partition_configs() {
|
get_partition_configs() {
|
||||||
PARTITION_CONFIGS=()
|
PARTITION_CONFIGS=()
|
||||||
|
local total_allocated=0
|
||||||
|
local available_space=$((DISK_SIZE_MB - 2)) # Reserve 2MB for partition table
|
||||||
|
|
||||||
for i in $(seq 1 $PARTITION_COUNT); do
|
for i in $(seq 1 $PARTITION_COUNT); do
|
||||||
echo ""
|
echo ""
|
||||||
@@ -228,106 +458,244 @@ get_partition_configs() {
|
|||||||
echo " Partition $i Configuration"
|
echo " Partition $i Configuration"
|
||||||
echo "=========================================="
|
echo "=========================================="
|
||||||
|
|
||||||
|
if [ $i -gt 1 ]; then
|
||||||
|
print_info "Available space: ${available_space}MB"
|
||||||
|
fi
|
||||||
|
|
||||||
# Get filesystem
|
# Get filesystem
|
||||||
echo ""
|
echo ""
|
||||||
echo "Filesystem Type:"
|
echo "Filesystem Type:"
|
||||||
echo " 1) NTFS (Windows default)"
|
echo " 1) FAT12 (Very small, <16MB, legacy)"
|
||||||
echo " 2) FAT32 (Universal compatibility)"
|
echo " 2) FAT16 (Small, 16MB-2GB, legacy)"
|
||||||
echo " 3) exFAT (Modern, large file support)"
|
echo " 3) FAT32 (Universal, 32MB+, good compatibility)"
|
||||||
echo " 4) ext4 (Linux default)"
|
echo " 4) exFAT (Modern, large files, cross-platform)"
|
||||||
echo " 5) ext3 (Older Linux)"
|
echo " 5) NTFS (Windows default, journaling)"
|
||||||
echo " 6) ext2 (Legacy Linux, no journaling)"
|
echo " 6) ext2 (Linux legacy, no journaling)"
|
||||||
echo " 7) XFS (High-performance Linux)"
|
echo " 7) ext3 (Linux, journaling)"
|
||||||
echo " 8) swap (Linux swap space)"
|
echo " 8) ext4 (Linux default, modern)"
|
||||||
|
echo " 9) XFS (High-performance Linux)"
|
||||||
|
echo " 10) HFS+ (macOS legacy)"
|
||||||
|
echo " 11) APFS (macOS modern - limited Linux support)"
|
||||||
|
echo " 12) swap (Linux swap space)"
|
||||||
|
echo " 13) unallocated (Empty space - for forensic practice)"
|
||||||
echo ""
|
echo ""
|
||||||
read -p "Select filesystem for partition $i [1-8]: " FS_CHOICE
|
read -p "Select filesystem for partition $i [1-13]: " FS_CHOICE
|
||||||
|
|
||||||
case $FS_CHOICE in
|
case $FS_CHOICE in
|
||||||
1)
|
1)
|
||||||
PART_FS="ntfs"
|
PART_FS="fat12"
|
||||||
if ! command -v mkfs.ntfs >/dev/null 2>&1; then
|
if ! command -v mkfs.fat >/dev/null 2>&1; then
|
||||||
print_error "mkfs.ntfs not found. Install: sudo apt-get install ntfs-3g"
|
print_error "mkfs.fat not found. Install: sudo apt-get install dosfstools"
|
||||||
exit 1
|
get_partition_configs
|
||||||
|
return
|
||||||
fi
|
fi
|
||||||
|
print_note "FAT12 is limited to <16MB partitions"
|
||||||
;;
|
;;
|
||||||
2)
|
2)
|
||||||
|
PART_FS="fat16"
|
||||||
|
if ! command -v mkfs.fat >/dev/null 2>&1; then
|
||||||
|
print_error "mkfs.fat not found. Install: sudo apt-get install dosfstools"
|
||||||
|
get_partition_configs
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
print_note "FAT16 is limited to 16MB-2GB partitions"
|
||||||
|
;;
|
||||||
|
3)
|
||||||
PART_FS="vfat"
|
PART_FS="vfat"
|
||||||
if ! command -v mkfs.vfat >/dev/null 2>&1; then
|
if ! command -v mkfs.vfat >/dev/null 2>&1; then
|
||||||
print_error "mkfs.vfat not found. Install: sudo apt-get install dosfstools"
|
print_error "mkfs.vfat not found. Install: sudo apt-get install dosfstools"
|
||||||
exit 1
|
get_partition_configs
|
||||||
fi
|
return
|
||||||
;;
|
|
||||||
3)
|
|
||||||
PART_FS="exfat"
|
|
||||||
if ! command -v mkfs.exfat >/dev/null 2>&1; then
|
|
||||||
print_error "mkfs.exfat not found. Install: sudo apt-get install exfat-fuse exfat-utils"
|
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
4)
|
4)
|
||||||
PART_FS="ext4"
|
PART_FS="exfat"
|
||||||
if ! command -v mkfs.ext4 >/dev/null 2>&1; then
|
if ! command -v mkfs.exfat >/dev/null 2>&1; then
|
||||||
print_error "mkfs.ext4 not found. Install: sudo apt-get install e2fsprogs"
|
print_error "mkfs.exfat not found. Install: sudo apt-get install exfatprogs"
|
||||||
exit 1
|
get_partition_configs
|
||||||
|
return
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
5)
|
5)
|
||||||
PART_FS="ext3"
|
PART_FS="ntfs"
|
||||||
if ! command -v mkfs.ext3 >/dev/null 2>&1; then
|
if ! command -v mkfs.ntfs >/dev/null 2>&1; then
|
||||||
print_error "mkfs.ext3 not found. Install: sudo apt-get install e2fsprogs"
|
print_error "mkfs.ntfs not found. Install: sudo apt-get install ntfs-3g"
|
||||||
exit 1
|
get_partition_configs
|
||||||
|
return
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
6)
|
6)
|
||||||
PART_FS="ext2"
|
PART_FS="ext2"
|
||||||
if ! command -v mkfs.ext2 >/dev/null 2>&1; then
|
if ! command -v mkfs.ext2 >/dev/null 2>&1; then
|
||||||
print_error "mkfs.ext2 not found. Install: sudo apt-get install e2fsprogs"
|
print_error "mkfs.ext2 not found. Install: sudo apt-get install e2fsprogs"
|
||||||
exit 1
|
get_partition_configs
|
||||||
|
return
|
||||||
fi
|
fi
|
||||||
|
print_note "ext2 has no journaling - faster but less crash-resistant"
|
||||||
;;
|
;;
|
||||||
7)
|
7)
|
||||||
PART_FS="xfs"
|
PART_FS="ext3"
|
||||||
if ! command -v mkfs.xfs >/dev/null 2>&1; then
|
if ! command -v mkfs.ext3 >/dev/null 2>&1; then
|
||||||
print_error "mkfs.xfs not found. Install: sudo apt-get install xfsprogs"
|
print_error "mkfs.ext3 not found. Install: sudo apt-get install e2fsprogs"
|
||||||
exit 1
|
get_partition_configs
|
||||||
|
return
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
8)
|
8)
|
||||||
|
PART_FS="ext4"
|
||||||
|
if ! command -v mkfs.ext4 >/dev/null 2>&1; then
|
||||||
|
print_error "mkfs.ext4 not found. Install: sudo apt-get install e2fsprogs"
|
||||||
|
get_partition_configs
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
9)
|
||||||
|
PART_FS="xfs"
|
||||||
|
if ! command -v mkfs.xfs >/dev/null 2>&1; then
|
||||||
|
print_error "mkfs.xfs not found. Install: sudo apt-get install xfsprogs"
|
||||||
|
get_partition_configs
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
print_note "XFS requires at least 16MB"
|
||||||
|
;;
|
||||||
|
10)
|
||||||
|
PART_FS="hfsplus"
|
||||||
|
if ! command -v mkfs.hfsplus >/dev/null 2>&1; then
|
||||||
|
print_error "mkfs.hfsplus not found. Install: sudo apt-get install hfsprogs"
|
||||||
|
get_partition_configs
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
print_warning "HFS+ support on Linux is limited"
|
||||||
|
;;
|
||||||
|
11)
|
||||||
|
PART_FS="apfs"
|
||||||
|
print_warning "APFS has very limited Linux support and may not work properly"
|
||||||
|
read -p "Continue anyway? (y/n): " continue
|
||||||
|
if [ "$continue" != "y" ]; then
|
||||||
|
get_partition_configs
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
12)
|
||||||
PART_FS="swap"
|
PART_FS="swap"
|
||||||
if ! command -v mkswap >/dev/null 2>&1; then
|
if ! command -v mkswap >/dev/null 2>&1; then
|
||||||
print_error "mkswap not found. Install: sudo apt-get install util-linux"
|
print_error "mkswap not found. Install: sudo apt-get install util-linux"
|
||||||
exit 1
|
get_partition_configs
|
||||||
|
return
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
|
13)
|
||||||
|
PART_FS="unallocated"
|
||||||
|
print_note "Unallocated space - useful for practicing partition recovery"
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
print_error "Invalid choice"
|
print_error "Invalid choice"
|
||||||
exit 1
|
get_partition_configs
|
||||||
|
return
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# Get size
|
# Get size
|
||||||
if [ $i -lt $PARTITION_COUNT ]; then
|
if [ $i -lt $PARTITION_COUNT ]; then
|
||||||
|
while true; do
|
||||||
|
if [ $i -eq $((PARTITION_COUNT - 1)) ]; then
|
||||||
|
# Second to last partition - show what will be left
|
||||||
|
print_tip "Press Enter to use remaining space (${available_space}MB) or specify size"
|
||||||
|
read -p "Size for partition $i in MB (default: remaining): " PART_SIZE
|
||||||
|
else
|
||||||
read -p "Size for partition $i in MB: " PART_SIZE
|
read -p "Size for partition $i in MB: " PART_SIZE
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Handle default to remaining space
|
||||||
|
if [ -z "$PART_SIZE" ] && [ $i -eq $((PARTITION_COUNT - 1)) ]; then
|
||||||
|
PART_SIZE="remaining"
|
||||||
|
print_info "Partition $i will use remaining space (~${available_space}MB)"
|
||||||
|
|
||||||
|
# Validate remaining space for filesystem
|
||||||
|
if ! validate_fs_size "$PART_FS" "$available_space"; then
|
||||||
|
print_error "Remaining space (${available_space}MB) is not suitable for $PART_FS"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
if ! [[ "$PART_SIZE" =~ ^[0-9]+$ ]] || [ "$PART_SIZE" -lt 1 ]; then
|
if ! [[ "$PART_SIZE" =~ ^[0-9]+$ ]] || [ "$PART_SIZE" -lt 1 ]; then
|
||||||
print_error "Invalid size"
|
print_error "Invalid size. Enter a number or press Enter for remaining space"
|
||||||
exit 1
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate size for filesystem
|
||||||
|
if ! validate_fs_size "$PART_FS" "$PART_SIZE"; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if size exceeds available space
|
||||||
|
if [ "$PART_SIZE" -ge "$available_space" ]; then
|
||||||
|
print_error "Not enough space. Available: ${available_space}MB"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Leave at least 10MB for the last partition
|
||||||
|
if [ $i -eq $((PARTITION_COUNT - 1)) ]; then
|
||||||
|
remaining=$((available_space - PART_SIZE))
|
||||||
|
if [ "$remaining" -lt 10 ]; then
|
||||||
|
print_error "Not enough space left for last partition (need at least 10MB)"
|
||||||
|
print_tip "Press Enter to use remaining ${available_space}MB instead"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
break
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$PART_SIZE" != "remaining" ]; then
|
||||||
|
total_allocated=$((total_allocated + PART_SIZE))
|
||||||
|
available_space=$((available_space - PART_SIZE))
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
PART_SIZE="remaining"
|
PART_SIZE="remaining"
|
||||||
print_info "Partition $i will use remaining space"
|
print_info "Partition $i will use remaining space (~${available_space}MB)"
|
||||||
|
|
||||||
|
# Validate remaining space for filesystem
|
||||||
|
if ! validate_fs_size "$PART_FS" "$available_space"; then
|
||||||
|
print_error "Remaining space (${available_space}MB) is not suitable for $PART_FS"
|
||||||
|
get_partition_configs
|
||||||
|
return
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Get label (skip for swap)
|
# Get label (skip for swap and unallocated)
|
||||||
if [ "$PART_FS" != "swap" ]; then
|
if [ "$PART_FS" != "swap" ] && [ "$PART_FS" != "unallocated" ]; then
|
||||||
|
while true; do
|
||||||
read -p "Volume label for partition $i (default: PART$i): " PART_LABEL
|
read -p "Volume label for partition $i (default: PART$i): " PART_LABEL
|
||||||
PART_LABEL=${PART_LABEL:-PART$i}
|
PART_LABEL=${PART_LABEL:-PART$i}
|
||||||
|
|
||||||
|
# Validate label
|
||||||
|
validated_label=$(validate_label "$PART_FS" "$PART_LABEL")
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
PART_LABEL="$validated_label"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
else
|
else
|
||||||
PART_LABEL=""
|
PART_LABEL=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
PARTITION_CONFIGS+=("$PART_FS|$PART_SIZE|$PART_LABEL")
|
PARTITION_CONFIGS+=("$PART_FS|$PART_SIZE|$PART_LABEL")
|
||||||
|
|
||||||
|
if [ "$PART_FS" = "swap" ]; then
|
||||||
|
print_info "Partition $i: $PART_FS, ${PART_SIZE}MB"
|
||||||
|
elif [ "$PART_FS" = "unallocated" ]; then
|
||||||
|
print_info "Partition $i: $PART_FS, ${PART_SIZE}MB (no filesystem)"
|
||||||
|
else
|
||||||
print_info "Partition $i: $PART_FS, ${PART_SIZE}MB, label='$PART_LABEL'"
|
print_info "Partition $i: $PART_FS, ${PART_SIZE}MB, label='$PART_LABEL'"
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Final sanity check
|
||||||
|
if [ "$total_allocated" -gt "$((DISK_SIZE_MB - 10))" ]; then
|
||||||
|
print_warning "Partitions use almost all disk space. This may cause issues."
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Create the disk image
|
# Create the disk image
|
||||||
@@ -340,15 +708,15 @@ create_disk_image() {
|
|||||||
fallocate -l ${DISK_SIZE_MB}M "$FILENAME"
|
fallocate -l ${DISK_SIZE_MB}M "$FILENAME"
|
||||||
else
|
else
|
||||||
print_warning "fallocate not available, falling back to /dev/zero"
|
print_warning "fallocate not available, falling back to /dev/zero"
|
||||||
dd if=/dev/zero of="$FILENAME" bs=1M count=$DISK_SIZE_MB status=progress
|
dd if=/dev/zero of="$FILENAME" bs=1M count=$DISK_SIZE_MB status=progress 2>&1 | grep -v "records"
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
zero)
|
zero)
|
||||||
dd if=/dev/zero of="$FILENAME" bs=1M count=$DISK_SIZE_MB status=progress
|
dd if=/dev/zero of="$FILENAME" bs=1M count=$DISK_SIZE_MB status=progress 2>&1 | grep -v "records"
|
||||||
;;
|
;;
|
||||||
random)
|
random)
|
||||||
print_warning "Using /dev/urandom - this will be SLOW!"
|
print_warning "Using /dev/urandom - this will be SLOW!"
|
||||||
dd if=/dev/urandom of="$FILENAME" bs=1M count=$DISK_SIZE_MB status=progress
|
dd if=/dev/urandom of="$FILENAME" bs=1M count=$DISK_SIZE_MB status=progress 2>&1 | grep -v "records"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
@@ -359,6 +727,13 @@ create_disk_image() {
|
|||||||
setup_loop_device() {
|
setup_loop_device() {
|
||||||
print_info "Setting up loop device..."
|
print_info "Setting up loop device..."
|
||||||
LOOP_DEVICE=$(losetup -f)
|
LOOP_DEVICE=$(losetup -f)
|
||||||
|
|
||||||
|
if [ -z "$LOOP_DEVICE" ]; then
|
||||||
|
print_error "No free loop devices available"
|
||||||
|
print_info "Try: sudo modprobe loop max_loop=16"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
losetup "$LOOP_DEVICE" "$FILENAME"
|
losetup "$LOOP_DEVICE" "$FILENAME"
|
||||||
print_success "Loop device created: $LOOP_DEVICE"
|
print_success "Loop device created: $LOOP_DEVICE"
|
||||||
}
|
}
|
||||||
@@ -378,18 +753,40 @@ create_partitions() {
|
|||||||
if [ "$size" = "remaining" ]; then
|
if [ "$size" = "remaining" ]; then
|
||||||
end="100%"
|
end="100%"
|
||||||
else
|
else
|
||||||
end="${start_mb}MiB + ${size}MiB"
|
|
||||||
end=$(echo "$start_mb + $size" | bc)
|
end=$(echo "$start_mb + $size" | bc)
|
||||||
end="${end}MiB"
|
end="${end}MiB"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
print_info "Creating partition $part_num: ${start_mb}MiB -> $end"
|
print_info "Creating partition $part_num: ${start_mb}MiB -> $end"
|
||||||
|
|
||||||
if [ "$fs" = "swap" ]; then
|
# Set partition type based on filesystem
|
||||||
|
case $fs in
|
||||||
|
swap)
|
||||||
parted -s "$LOOP_DEVICE" mkpart primary linux-swap "${start_mb}MiB" "$end"
|
parted -s "$LOOP_DEVICE" mkpart primary linux-swap "${start_mb}MiB" "$end"
|
||||||
else
|
;;
|
||||||
|
fat12|fat16|vfat)
|
||||||
|
parted -s "$LOOP_DEVICE" mkpart primary fat32 "${start_mb}MiB" "$end"
|
||||||
|
;;
|
||||||
|
ntfs)
|
||||||
|
parted -s "$LOOP_DEVICE" mkpart primary ntfs "${start_mb}MiB" "$end"
|
||||||
|
;;
|
||||||
|
ext2|ext3|ext4)
|
||||||
|
parted -s "$LOOP_DEVICE" mkpart primary ext4 "${start_mb}MiB" "$end"
|
||||||
|
;;
|
||||||
|
xfs)
|
||||||
|
parted -s "$LOOP_DEVICE" mkpart primary xfs "${start_mb}MiB" "$end"
|
||||||
|
;;
|
||||||
|
hfsplus)
|
||||||
|
parted -s "$LOOP_DEVICE" mkpart primary hfs+ "${start_mb}MiB" "$end"
|
||||||
|
;;
|
||||||
|
unallocated)
|
||||||
|
# Don't create a partition for unallocated space - just leave it empty
|
||||||
|
print_info "Leaving space unallocated (no partition entry)"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
parted -s "$LOOP_DEVICE" mkpart primary "${start_mb}MiB" "$end"
|
parted -s "$LOOP_DEVICE" mkpart primary "${start_mb}MiB" "$end"
|
||||||
fi
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
if [ "$size" != "remaining" ]; then
|
if [ "$size" != "remaining" ]; then
|
||||||
start_mb=$(echo "$start_mb + $size" | bc)
|
start_mb=$(echo "$start_mb + $size" | bc)
|
||||||
@@ -399,7 +796,7 @@ create_partitions() {
|
|||||||
done
|
done
|
||||||
|
|
||||||
# Inform kernel about partition table changes
|
# Inform kernel about partition table changes
|
||||||
partprobe "$LOOP_DEVICE"
|
partprobe "$LOOP_DEVICE" 2>/dev/null || true
|
||||||
sleep 2
|
sleep 2
|
||||||
|
|
||||||
print_success "Partitions created"
|
print_success "Partitions created"
|
||||||
@@ -412,6 +809,12 @@ format_partitions() {
|
|||||||
for config in "${PARTITION_CONFIGS[@]}"; do
|
for config in "${PARTITION_CONFIGS[@]}"; do
|
||||||
IFS='|' read -r fs size label <<< "$config"
|
IFS='|' read -r fs size label <<< "$config"
|
||||||
|
|
||||||
|
# Skip unallocated space - no partition to format
|
||||||
|
if [ "$fs" = "unallocated" ]; then
|
||||||
|
print_info "Skipping unallocated space (no partition to format)"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
# Determine partition device name
|
# Determine partition device name
|
||||||
PARTITION="${LOOP_DEVICE}p${part_num}"
|
PARTITION="${LOOP_DEVICE}p${part_num}"
|
||||||
if [ ! -e "$PARTITION" ]; then
|
if [ ! -e "$PARTITION" ]; then
|
||||||
@@ -420,6 +823,7 @@ format_partitions() {
|
|||||||
|
|
||||||
if [ ! -e "$PARTITION" ]; then
|
if [ ! -e "$PARTITION" ]; then
|
||||||
print_error "Cannot find partition device for partition $part_num"
|
print_error "Cannot find partition device for partition $part_num"
|
||||||
|
print_info "Expected: ${LOOP_DEVICE}p${part_num} or ${LOOP_DEVICE}${part_num}"
|
||||||
cleanup
|
cleanup
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@@ -427,23 +831,39 @@ format_partitions() {
|
|||||||
print_info "Formatting partition $part_num ($PARTITION) with $fs filesystem..."
|
print_info "Formatting partition $part_num ($PARTITION) with $fs filesystem..."
|
||||||
|
|
||||||
case $fs in
|
case $fs in
|
||||||
ntfs)
|
fat12)
|
||||||
mkfs.ntfs -f -L "$label" "$PARTITION"
|
# FAT12 requires specific cluster size
|
||||||
|
mkfs.fat -F 12 -n "$label" "$PARTITION" 2>&1 | grep -v "^mkfs.fat"
|
||||||
|
;;
|
||||||
|
fat16)
|
||||||
|
# FAT16
|
||||||
|
mkfs.fat -F 16 -n "$label" "$PARTITION" 2>&1 | grep -v "^mkfs.fat"
|
||||||
;;
|
;;
|
||||||
vfat)
|
vfat)
|
||||||
mkfs.vfat -n "$label" "$PARTITION"
|
# FAT32
|
||||||
|
mkfs.vfat -F 32 -n "$label" "$PARTITION" 2>&1 | grep -v "^mkfs.fat"
|
||||||
|
;;
|
||||||
|
ntfs)
|
||||||
|
mkfs.ntfs -f -L "$label" "$PARTITION" 2>&1 | grep -E "^(Cluster|Creating|mkntfs completed)"
|
||||||
;;
|
;;
|
||||||
exfat)
|
exfat)
|
||||||
mkfs.exfat -n "$label" "$PARTITION"
|
mkfs.exfat -n "$label" "$PARTITION" 2>&1 | grep -v "^exfatprogs"
|
||||||
;;
|
;;
|
||||||
ext2|ext3|ext4)
|
ext2|ext3|ext4)
|
||||||
mkfs."$fs" -L "$label" "$PARTITION"
|
mkfs."$fs" -L "$label" "$PARTITION" 2>&1 | grep -E "^(Creating|Writing|mke2fs)"
|
||||||
;;
|
;;
|
||||||
xfs)
|
xfs)
|
||||||
mkfs.xfs -f -L "$label" "$PARTITION"
|
mkfs.xfs -f -L "$label" "$PARTITION" 2>&1 | grep -v "^meta-data"
|
||||||
|
;;
|
||||||
|
hfsplus)
|
||||||
|
mkfs.hfsplus -v "$label" "$PARTITION" 2>&1
|
||||||
|
;;
|
||||||
|
apfs)
|
||||||
|
print_warning "APFS formatting on Linux is not well supported"
|
||||||
|
print_info "Skipping format for APFS partition"
|
||||||
;;
|
;;
|
||||||
swap)
|
swap)
|
||||||
mkswap -L "SWAP$part_num" "$PARTITION"
|
mkswap -L "SWAP$part_num" "$PARTITION" 2>&1 | grep "^Setting up"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
@@ -472,9 +892,9 @@ mount_filesystems() {
|
|||||||
for config in "${PARTITION_CONFIGS[@]}"; do
|
for config in "${PARTITION_CONFIGS[@]}"; do
|
||||||
IFS='|' read -r fs size label <<< "$config"
|
IFS='|' read -r fs size label <<< "$config"
|
||||||
|
|
||||||
# Skip swap partitions
|
# Skip swap, apfs, and unallocated filesystems
|
||||||
if [ "$fs" = "swap" ]; then
|
if [ "$fs" = "swap" ] || [ "$fs" = "apfs" ] || [ "$fs" = "unallocated" ]; then
|
||||||
print_info "Skipping mount for swap partition $part_num"
|
print_info "Skipping mount for $fs partition $part_num"
|
||||||
part_num=$((part_num + 1))
|
part_num=$((part_num + 1))
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
@@ -488,10 +908,28 @@ mount_filesystems() {
|
|||||||
mkdir -p "$MOUNT_POINT"
|
mkdir -p "$MOUNT_POINT"
|
||||||
|
|
||||||
print_info "Mounting partition $part_num to $MOUNT_POINT..."
|
print_info "Mounting partition $part_num to $MOUNT_POINT..."
|
||||||
mount "$PARTITION" "$MOUNT_POINT"
|
|
||||||
|
|
||||||
|
# Use appropriate mount options
|
||||||
|
case $fs in
|
||||||
|
ntfs)
|
||||||
|
mount -t ntfs-3g "$PARTITION" "$MOUNT_POINT" 2>&1 || \
|
||||||
|
mount "$PARTITION" "$MOUNT_POINT" 2>&1
|
||||||
|
;;
|
||||||
|
hfsplus)
|
||||||
|
mount -t hfsplus "$PARTITION" "$MOUNT_POINT" 2>&1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
mount "$PARTITION" "$MOUNT_POINT" 2>&1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
print_success "Partition $part_num mounted at: $MOUNT_POINT"
|
print_success "Partition $part_num mounted at: $MOUNT_POINT"
|
||||||
MOUNT_POINTS+=("$MOUNT_POINT")
|
MOUNT_POINTS+=("$MOUNT_POINT")
|
||||||
|
else
|
||||||
|
print_warning "Failed to mount partition $part_num"
|
||||||
|
rmdir "$MOUNT_POINT" 2>/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
part_num=$((part_num + 1))
|
part_num=$((part_num + 1))
|
||||||
done
|
done
|
||||||
@@ -506,7 +944,7 @@ show_summary() {
|
|||||||
echo "=========================================="
|
echo "=========================================="
|
||||||
echo ""
|
echo ""
|
||||||
echo "Image File: $(realpath $FILENAME)"
|
echo "Image File: $(realpath $FILENAME)"
|
||||||
echo "Size: ${DISK_SIZE_MB} MB"
|
echo "Size: ${DISK_SIZE_MB} MB ($(echo "scale=2; $DISK_SIZE_MB/1024" | bc) GB)"
|
||||||
echo "Init Method: $INIT_METHOD"
|
echo "Init Method: $INIT_METHOD"
|
||||||
echo "Partition Scheme: $PARTITION_SCHEME"
|
echo "Partition Scheme: $PARTITION_SCHEME"
|
||||||
echo "Loop Device: $LOOP_DEVICE"
|
echo "Loop Device: $LOOP_DEVICE"
|
||||||
@@ -514,21 +952,27 @@ show_summary() {
|
|||||||
echo "Partitions:"
|
echo "Partitions:"
|
||||||
|
|
||||||
local part_num=1
|
local part_num=1
|
||||||
|
local config_num=1
|
||||||
for config in "${PARTITION_CONFIGS[@]}"; do
|
for config in "${PARTITION_CONFIGS[@]}"; do
|
||||||
IFS='|' read -r fs size label <<< "$config"
|
IFS='|' read -r fs size label <<< "$config"
|
||||||
|
|
||||||
|
if [ "$fs" = "unallocated" ]; then
|
||||||
|
echo " [$config_num] unallocated space (${size}MB) - not partitioned"
|
||||||
|
else
|
||||||
PARTITION="${LOOP_DEVICE}p${part_num}"
|
PARTITION="${LOOP_DEVICE}p${part_num}"
|
||||||
if [ ! -e "$PARTITION" ]; then
|
if [ ! -e "$PARTITION" ]; then
|
||||||
PARTITION="${LOOP_DEVICE}${part_num}"
|
PARTITION="${LOOP_DEVICE}${part_num}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$fs" = "swap" ]; then
|
if [ "$fs" = "swap" ]; then
|
||||||
echo " [$part_num] $PARTITION - $fs (${size}MB)"
|
echo " [$config_num] $PARTITION - $fs (${size}MB)"
|
||||||
else
|
else
|
||||||
echo " [$part_num] $PARTITION - $fs (${size}MB) - '$label'"
|
echo " [$config_num] $PARTITION - $fs (${size}MB) - '$label'"
|
||||||
|
fi
|
||||||
|
part_num=$((part_num + 1))
|
||||||
fi
|
fi
|
||||||
|
|
||||||
part_num=$((part_num + 1))
|
config_num=$((config_num + 1))
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ ${#MOUNT_POINTS[@]} -gt 0 ]; then
|
if [ ${#MOUNT_POINTS[@]} -gt 0 ]; then
|
||||||
@@ -553,7 +997,13 @@ show_summary() {
|
|||||||
echo " xxd $FILENAME | less"
|
echo " xxd $FILENAME | less"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Analyze with forensic tools:"
|
echo "Analyze with forensic tools:"
|
||||||
echo " mmls $FILENAME"
|
echo " mmls $FILENAME # View partitions"
|
||||||
|
echo " fsstat -o 2048 $FILENAME # Filesystem details"
|
||||||
|
echo " fls -o 2048 -r $FILENAME # List files"
|
||||||
|
echo ""
|
||||||
|
echo "View specific structures:"
|
||||||
|
echo " xxd -l 512 $FILENAME # Boot sector"
|
||||||
|
echo " xxd -s 0x1BE -l 64 $FILENAME # MBR partition table"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Clean up (when done):"
|
echo "Clean up (when done):"
|
||||||
if [ ${#MOUNT_POINTS[@]} -gt 0 ]; then
|
if [ ${#MOUNT_POINTS[@]} -gt 0 ]; then
|
||||||
@@ -563,6 +1013,8 @@ show_summary() {
|
|||||||
fi
|
fi
|
||||||
echo " sudo losetup -d $LOOP_DEVICE"
|
echo " sudo losetup -d $LOOP_DEVICE"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
|
print_tip "Remember to unmount filesystems and detach loop device when finished!"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Trap to ensure cleanup on exit
|
# Trap to ensure cleanup on exit
|
||||||
@@ -582,12 +1034,13 @@ main() {
|
|||||||
get_partition_count
|
get_partition_count
|
||||||
get_partition_configs
|
get_partition_configs
|
||||||
|
|
||||||
|
# Show final summary and confirm
|
||||||
echo ""
|
echo ""
|
||||||
echo "=========================================="
|
echo "=========================================="
|
||||||
echo " Summary"
|
echo " Configuration Summary"
|
||||||
echo "=========================================="
|
echo "=========================================="
|
||||||
echo "Filename: $FILENAME"
|
echo "Filename: $FILENAME"
|
||||||
echo "Size: ${DISK_SIZE_MB} MB"
|
echo "Size: ${DISK_SIZE_MB} MB ($(echo "scale=2; $DISK_SIZE_MB/1024" | bc) GB)"
|
||||||
echo "Init Method: $INIT_METHOD"
|
echo "Init Method: $INIT_METHOD"
|
||||||
echo "Partition Scheme: $PARTITION_SCHEME"
|
echo "Partition Scheme: $PARTITION_SCHEME"
|
||||||
echo "Partitions: $PARTITION_COUNT"
|
echo "Partitions: $PARTITION_COUNT"
|
||||||
@@ -597,6 +1050,8 @@ main() {
|
|||||||
IFS='|' read -r fs size label <<< "$config"
|
IFS='|' read -r fs size label <<< "$config"
|
||||||
if [ "$fs" = "swap" ]; then
|
if [ "$fs" = "swap" ]; then
|
||||||
echo " [$i] $fs (${size}MB)"
|
echo " [$i] $fs (${size}MB)"
|
||||||
|
elif [ "$fs" = "unallocated" ]; then
|
||||||
|
echo " [$i] $fs (${size}MB) - no partition"
|
||||||
else
|
else
|
||||||
echo " [$i] $fs (${size}MB) - '$label'"
|
echo " [$i] $fs (${size}MB) - '$label'"
|
||||||
fi
|
fi
|
||||||
@@ -606,10 +1061,11 @@ main() {
|
|||||||
read -p "Proceed with creation? (y/n): " CONFIRM
|
read -p "Proceed with creation? (y/n): " CONFIRM
|
||||||
|
|
||||||
if [ "$CONFIRM" != "y" ]; then
|
if [ "$CONFIRM" != "y" ]; then
|
||||||
print_info "Cancelled"
|
print_info "Operation cancelled"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
create_disk_image
|
create_disk_image
|
||||||
setup_loop_device
|
setup_loop_device
|
||||||
create_partitions
|
create_partitions
|
||||||
|
|||||||
Reference in New Issue
Block a user