Share your shell/bash/bat scripts

Been using these on termux when I’m too lazy to leave my bed. Repacking has not been extensively tested. Haven’t flashed any yet.

If someone made a TUI, that’d be cool.

install-dependencies.sh
#!/bin/bash

# Android ROM Tools - Termux Dependency Installer
# Installs all required packages for unpacking/repacking Android images

set -e

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color

print_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

print_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

print_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

print_header() {
    echo -e "${CYAN}================================${NC}"
    echo -e "${CYAN}$1${NC}"
    echo -e "${CYAN}================================${NC}"
}

# Check if running in Termux
if [ ! -d "/data/data/com.termux" ]; then
    print_error "This script is designed for Termux only"
    exit 1
fi

print_header "Android ROM Tools Installer"
echo ""
print_info "This script will install all dependencies for:"
echo "  - super.img unpacking/repacking"
echo "  - ext4 partition unpacking/repacking"
echo ""

# Update package lists
print_info "Updating package lists..."
pkg update -y

# Install required packages
print_header "Installing Required Packages"

PACKAGES=(
    # Core utilities
    "coreutils"

    # Sparse image tools
    "android-tools"  # Contains simg2img, img2simg, lpunpack, lpmake, etc.

    # ext4 filesystem tools
    "e2fsprogs"      # Contains debugfs, mke2fs, etc.

    # Additional utilities
    "util-linux"     # Contains various utilities
)

for pkg in "${PACKAGES[@]}"; do
    print_info "Installing $pkg..."
    pkg install -y "$pkg" 2>/dev/null || print_warn "$pkg may already be installed or unavailable"
done

echo ""
print_header "Verifying Installation"

# Verify tools are installed
TOOLS=(
    "simg2img:Sparse to raw image converter"
    "img2simg:Raw to sparse image converter"
    "lpunpack:Super partition unpacker"
    "lpmake:Super partition creator"
    "debugfs:ext4 filesystem debugger/extractor"
    "mke2fs.android:Android ext4 filesystem creator"
    "e2fsdroid:ext4 image populator"
    "ext2simg:ext4 to sparse converter"
)

ALL_OK=1
for tool_info in "${TOOLS[@]}"; do
    tool="${tool_info%%:*}"
    desc="${tool_info#*:}"
    if command -v "$tool" &> /dev/null; then
        echo -e "  ${GREEN}✓${NC} $tool - $desc"
    else
        echo -e "  ${RED}✗${NC} $tool - $desc (NOT FOUND)"
        ALL_OK=0
    fi
done

echo ""

if [ "$ALL_OK" -eq 1 ]; then
    print_header "Installation Complete!"
    echo ""
    print_info "All tools installed successfully."
    echo ""
    echo "Available scripts:"
    echo "  ./unpack_super.sh  - Unpack super.img to partition images"
    echo "  ./repack_super.sh  - Repack partition images to super.img"
    echo "  ./unpack_ext4.sh   - Extract files from ext4 images"
    echo "  ./repack_ext4.sh   - Create ext4 images from directories"
    echo ""
    echo "Example workflow:"
    echo "  1. ./unpack_super.sh super.img"
    echo "  2. ./unpack_ext4.sh super_unpacked/system_a.img"
    echo "  3. (make modifications)"
    echo "  4. ./repack_ext4.sh system_a_extracted -o system_a.img"
    echo "  5. ./repack_super.sh super_unpacked -o super_new.img -s"
else
    print_error "Some tools could not be installed."
    print_error "Try running 'pkg update && pkg upgrade' first."
fi
unpack-super.sh
#!/bin/bash

# Android super.img unpacker script
# Handles both sparse and raw super images

set -e

RAW_IMG=""

# Cleanup function to ensure super_raw.img is always deleted
cleanup() {
    if [ -n "$RAW_IMG" ] && [ -f "$RAW_IMG" ]; then
        rm -f "$RAW_IMG"
    fi
}

# Trap to run cleanup on exit, error, or interrupt
trap cleanup EXIT ERR INT TERM

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

print_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

print_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

print_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

usage() {
    echo "Usage: $0 <super.img> [output_directory]"
    echo ""
    echo "Arguments:"
    echo "  super.img         Path to the super.img file to unpack"
    echo "  output_directory  Optional output directory (default: <super_name>_unpacked)"
    exit 1
}

# Check arguments
if [ $# -lt 1 ]; then
    usage
fi

INPUT_IMG="$1"
INPUT_NAME=$(basename "$INPUT_IMG" .img)

# Set output directory
if [ -n "$2" ]; then
    OUTPUT_DIR="$2"
else
    OUTPUT_DIR="$(dirname "$INPUT_IMG")/${INPUT_NAME}_unpacked"
fi

# Check if input file exists
if [ ! -f "$INPUT_IMG" ]; then
    print_error "File not found: $INPUT_IMG"
    exit 1
fi

# Check for required tools
for tool in lpunpack simg2img; do
    if ! command -v $tool &> /dev/null; then
        print_error "$tool is required but not installed."
        exit 1
    fi
done

# Create output directory
print_info "Creating output directory: $OUTPUT_DIR"
mkdir -p "$OUTPUT_DIR"

# Check if image is sparse by reading magic bytes
# Sparse magic: 0xed26ff3a (little-endian: 3a ff 26 ed)
MAGIC=$(od -A n -t x1 -N 4 "$INPUT_IMG" | tr -d ' ')

if [ "$MAGIC" = "3aff26ed" ]; then
    print_info "Detected sparse image format"
    print_info "Converting sparse image to raw..."

    RAW_IMG="$OUTPUT_DIR/super_raw.img"
    simg2img "$INPUT_IMG" "$RAW_IMG"

    print_info "Conversion complete"
    UNPACK_IMG="$RAW_IMG"
    CLEANUP_RAW=1
else
    print_info "Detected raw image format"
    UNPACK_IMG="$INPUT_IMG"
    CLEANUP_RAW=0
fi

# Unpack partitions
print_info "Unpacking partitions with lpunpack..."
lpunpack "$UNPACK_IMG" "$OUTPUT_DIR"

# Delete super_raw.img after unpacking
if [ -n "$RAW_IMG" ] && [ -f "$RAW_IMG" ]; then
    print_info "Deleting intermediate file: super_raw.img"
    rm -f "$RAW_IMG"
fi

# List extracted partitions
echo ""
print_info "Extraction complete! Partitions extracted to: $OUTPUT_DIR"
echo ""
echo "Extracted partitions:"
ls -lh "$OUTPUT_DIR"/*.img 2>/dev/null || print_warn "No partition images found"
unpack_ext4.sh
#!/bin/bash

# Android ext4 image unpacker script
# Extracts contents from ext4 partition images without root

set -e

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

print_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

print_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

print_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

usage() {
    echo "Usage: $0 <image.img> [output_directory]"
    echo ""
    echo "Arguments:"
    echo "  image.img          Path to ext4 image file (system, vendor, product, etc.)"
    echo "  output_directory   Optional output directory (default: <image_name>_extracted)"
    echo ""
    echo "Examples:"
    echo "  $0 system_a.img"
    echo "  $0 vendor_a.img vendor_extracted"
    exit 1
}

# Check arguments
if [ $# -lt 1 ]; then
    usage
fi

INPUT_IMG="$1"
INPUT_NAME=$(basename "$INPUT_IMG" .img)

# Set output directory
if [ -n "$2" ]; then
    OUTPUT_DIR="$2"
else
    OUTPUT_DIR="$(dirname "$INPUT_IMG")/${INPUT_NAME}_extracted"
fi

# Check if input file exists
if [ ! -f "$INPUT_IMG" ]; then
    print_error "File not found: $INPUT_IMG"
    exit 1
fi

# Check for required tools
if ! command -v debugfs &> /dev/null; then
    print_error "debugfs is required but not installed."
    print_error "Install with: pkg install e2fsprogs"
    exit 1
fi

# Verify it's an ext4 image by checking magic at offset 0x438
MAGIC=$(od -A n -t x1 -N 2 -j 1080 "$INPUT_IMG" | tr -d ' ')
if [ "$MAGIC" != "53ef" ]; then
    print_error "Not a valid ext4 image (magic: $MAGIC, expected: 53ef)"
    print_error "This might be erofs or another filesystem type"
    exit 1
fi

print_info "Valid ext4 image detected"

# Create output directory
print_info "Creating output directory: $OUTPUT_DIR"
mkdir -p "$OUTPUT_DIR"

# Get absolute path for output
OUTPUT_DIR=$(cd "$OUTPUT_DIR" && pwd)

# Extract using debugfs
print_info "Extracting files from $INPUT_IMG..."
print_info "This may take a while for large images..."

# Use debugfs to recursively dump all contents
debugfs -R "rdump / \"$OUTPUT_DIR\"" "$INPUT_IMG" 2>&1 | grep -v "^debugfs:" || true

# Count extracted files
FILE_COUNT=$(find "$OUTPUT_DIR" -type f 2>/dev/null | wc -l)
DIR_COUNT=$(find "$OUTPUT_DIR" -type d 2>/dev/null | wc -l)
LINK_COUNT=$(find "$OUTPUT_DIR" -type l 2>/dev/null | wc -l)

echo ""
print_info "Extraction complete!"
print_info "Output directory: $OUTPUT_DIR"
print_info "Files: $FILE_COUNT | Directories: $DIR_COUNT | Symlinks: $LINK_COUNT"

# Show top-level contents
echo ""
echo "Top-level contents:"
ls -la "$OUTPUT_DIR" 2>/dev/null | head -20
repack_partition.sh
#!/bin/bash

# Android partition repacker script
# Repacks extracted directories back to ext4 images (sparse or raw)

set -e

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

print_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

print_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

print_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

usage() {
    echo "Usage: $0 <input_directory> [options]"
    echo ""
    echo "Arguments:"
    echo "  input_directory    Directory containing extracted filesystem"
    echo ""
    echo "Options:"
    echo "  -o, --output FILE  Output image file (default: <dir_name>.img)"
    echo "  -s, --size SIZE    Exact image size in bytes (default: auto-calculated)"
    echo "  -S, --sparse       Output sparse image instead of raw"
    echo "  -h, --help         Show this help"
    echo ""
    echo "Examples:"
    echo "  $0 system_a_extracted"
    echo "  $0 vendor_a_extracted -o vendor_new.img -S"
    echo "  $0 product_a_extracted -s 734003200 -S"
    exit 1
}

# Default values
OUTPUT_FILE=""
IMG_SIZE=""
SPARSE=0

# Parse arguments
INPUT_DIR=""
while [[ $# -gt 0 ]]; do
    case $1 in
        -o|--output)
            OUTPUT_FILE="$2"
            shift 2
            ;;
        -s|--size)
            IMG_SIZE="$2"
            shift 2
            ;;
        -S|--sparse)
            SPARSE=1
            shift
            ;;
        -h|--help)
            usage
            ;;
        -*)
            print_error "Unknown option: $1"
            usage
            ;;
        *)
            if [ -z "$INPUT_DIR" ]; then
                INPUT_DIR="$1"
            else
                print_error "Unexpected argument: $1"
                usage
            fi
            shift
            ;;
    esac
done

# Check input directory
if [ -z "$INPUT_DIR" ]; then
    print_error "Input directory is required"
    usage
fi

# Remove trailing slash
INPUT_DIR="${INPUT_DIR%/}"

if [ ! -d "$INPUT_DIR" ]; then
    print_error "Directory not found: $INPUT_DIR"
    exit 1
fi

# Set default output file
if [ -z "$OUTPUT_FILE" ]; then
    DIR_NAME=$(basename "$INPUT_DIR" | sed 's/_extracted$//')
    OUTPUT_FILE="${DIR_NAME}.img"
fi

# Check for required tools
for tool in mke2fs e2fsdroid; do
    if ! command -v $tool &> /dev/null; then
        print_error "$tool is required but not installed."
        exit 1
    fi
done

# Calculate directory size if not specified
if [ -z "$IMG_SIZE" ]; then
    print_info "Calculating directory size..."
    # Get actual content size
    CONTENT_SIZE=$(du -sb "$INPUT_DIR" | cut -f1)

    # Calculate with overhead for ext4 metadata (~5-10%)
    # Also ensure minimum size and 4K alignment
    OVERHEAD=$((CONTENT_SIZE / 10))
    [ "$OVERHEAD" -lt 10485760 ] && OVERHEAD=10485760  # Min 10MB overhead

    IMG_SIZE=$((CONTENT_SIZE + OVERHEAD))

    # Align to 4K blocks
    IMG_SIZE=$(( (IMG_SIZE + 4095) / 4096 * 4096 ))

    print_info "Content size: $(numfmt --to=iec $CONTENT_SIZE 2>/dev/null || echo $CONTENT_SIZE)"
    print_info "Image size (with overhead): $(numfmt --to=iec $IMG_SIZE 2>/dev/null || echo $IMG_SIZE)"
fi

# Calculate block count (4K blocks)
BLOCK_COUNT=$((IMG_SIZE / 4096))

print_info "Creating ext4 image: $OUTPUT_FILE"
print_info "Size: $IMG_SIZE bytes ($BLOCK_COUNT blocks)"

# Remove existing output file
rm -f "$OUTPUT_FILE"

# Create ext4 filesystem (no journal, like Android images)
print_info "Creating ext4 filesystem..."
mke2fs -t ext4 -b 4096 -m 0 -O ^has_journal,^metadata_csum -L "/" "$OUTPUT_FILE" "$BLOCK_COUNT" 2>&1 | grep -v "^$" || true

# Populate with e2fsdroid
print_info "Populating image with files..."
e2fsdroid -e -a / -f "$INPUT_DIR" "$OUTPUT_FILE"

# Convert to sparse if requested
if [ "$SPARSE" -eq 1 ]; then
    if command -v img2simg &> /dev/null; then
        print_info "Converting to sparse image..."
        TEMP_FILE="${OUTPUT_FILE}.raw"
        mv "$OUTPUT_FILE" "$TEMP_FILE"
        img2simg "$TEMP_FILE" "$OUTPUT_FILE"
        rm -f "$TEMP_FILE"
        print_info "Output format: sparse"
    else
        print_warn "img2simg not found, keeping raw image"
    fi
else
    print_info "Output format: raw"
fi

echo ""
print_info "Image created successfully: $OUTPUT_FILE"
ls -lh "$OUTPUT_FILE"
repack-super.sh
#!/bin/bash

# Android super.img repacker script
# Repacks partition images into a super.img (sparse or raw)

set -e

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

print_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

print_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

print_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

usage() {
    echo "Usage: $0 <input_directory> [options]"
    echo ""
    echo "Arguments:"
    echo "  input_directory     Directory containing partition .img files"
    echo ""
    echo "Options:"
    echo "  -o, --output FILE   Output file (default: super_repacked.img)"
    echo "  -s, --sparse        Output sparse image (default: raw)"
    echo "  -S, --size SIZE     Super partition size in bytes (default: auto)"
    echo "  -g, --group NAME    Partition group name (default: main)"
    echo "  -G, --group-size SZ Group size in bytes (default: auto)"
    echo "  -m, --metadata SIZE Metadata size (default: 65536)"
    echo "  -l, --slots COUNT   Metadata slots (default: 2)"
    echo "  -h, --help          Show this help"
    exit 1
}

# Default values
OUTPUT_FILE="super_repacked.img"
SPARSE=0
SUPER_SIZE="auto"
GROUP_NAME="main"
GROUP_SIZE=""
METADATA_SIZE=65536
METADATA_SLOTS=2

# Parse arguments
INPUT_DIR=""
while [[ $# -gt 0 ]]; do
    case $1 in
        -o|--output)
            OUTPUT_FILE="$2"
            shift 2
            ;;
        -s|--sparse)
            SPARSE=1
            shift
            ;;
        -S|--size)
            SUPER_SIZE="$2"
            shift 2
            ;;
        -g|--group)
            GROUP_NAME="$2"
            shift 2
            ;;
        -G|--group-size)
            GROUP_SIZE="$2"
            shift 2
            ;;
        -m|--metadata)
            METADATA_SIZE="$2"
            shift 2
            ;;
        -l|--slots)
            METADATA_SLOTS="$2"
            shift 2
            ;;
        -h|--help)
            usage
            ;;
        -*)
            print_error "Unknown option: $1"
            usage
            ;;
        *)
            if [ -z "$INPUT_DIR" ]; then
                INPUT_DIR="$1"
            else
                print_error "Unexpected argument: $1"
                usage
            fi
            shift
            ;;
    esac
done

# Check input directory
if [ -z "$INPUT_DIR" ]; then
    print_error "Input directory is required"
    usage
fi

if [ ! -d "$INPUT_DIR" ]; then
    print_error "Directory not found: $INPUT_DIR"
    exit 1
fi

# Check for required tools
if ! command -v lpmake &> /dev/null; then
    print_error "lpmake is required but not installed."
    exit 1
fi

# Find partition images
print_info "Scanning for partition images in: $INPUT_DIR"
PARTITIONS=()
PARTITION_ARGS=""
IMAGE_ARGS=""
TOTAL_SIZE=0

for img in "$INPUT_DIR"/*.img; do
    [ -f "$img" ] || continue

    # Skip super_raw.img if present
    basename_img=$(basename "$img")
    if [ "$basename_img" = "super_raw.img" ]; then
        continue
    fi

    # Get partition name (remove .img extension)
    part_name="${basename_img%.img}"

    # Get file size
    file_size=$(stat -c%s "$img" 2>/dev/null || stat -f%z "$img" 2>/dev/null)

    PARTITIONS+=("$part_name")
    TOTAL_SIZE=$((TOTAL_SIZE + file_size))

    print_info "Found partition: $part_name ($(numfmt --to=iec $file_size 2>/dev/null || echo $file_size bytes))"

    # Build lpmake arguments
    PARTITION_ARGS="$PARTITION_ARGS -p ${part_name}:readonly:${file_size}:${GROUP_NAME}"
    IMAGE_ARGS="$IMAGE_ARGS -i ${part_name}=${img}"
done

if [ ${#PARTITIONS[@]} -eq 0 ]; then
    print_error "No partition images found in $INPUT_DIR"
    exit 1
fi

print_info "Total partitions: ${#PARTITIONS[@]}"
print_info "Total size: $(numfmt --to=iec $TOTAL_SIZE 2>/dev/null || echo $TOTAL_SIZE bytes)"

# Calculate group size if not specified
if [ -z "$GROUP_SIZE" ]; then
    # Add 10% overhead for alignment
    GROUP_SIZE=$((TOTAL_SIZE + TOTAL_SIZE / 10))
fi

# Build lpmake command
LPMAKE_CMD="lpmake"
LPMAKE_CMD="$LPMAKE_CMD -d $SUPER_SIZE"
LPMAKE_CMD="$LPMAKE_CMD -m $METADATA_SIZE"
LPMAKE_CMD="$LPMAKE_CMD -s $METADATA_SLOTS"
LPMAKE_CMD="$LPMAKE_CMD -g ${GROUP_NAME}:${GROUP_SIZE}"
LPMAKE_CMD="$LPMAKE_CMD $PARTITION_ARGS"
LPMAKE_CMD="$LPMAKE_CMD $IMAGE_ARGS"
LPMAKE_CMD="$LPMAKE_CMD -o $OUTPUT_FILE"

if [ "$SPARSE" -eq 1 ]; then
    LPMAKE_CMD="$LPMAKE_CMD -S"
    print_info "Output format: sparse"
else
    LPMAKE_CMD="$LPMAKE_CMD -F"
    print_info "Output format: raw"
fi

# Execute lpmake
print_info "Creating super.img..."
echo ""
eval $LPMAKE_CMD

echo ""
print_info "Super image created: $OUTPUT_FILE"
ls -lh "$OUTPUT_FILE"

With all of the above in a zip:

termux-rom-tools.zip (7.2 KB)