#!/bin/sh -e

##########################################################################
#   Script description:
#       
#   Arguments:
#       
#   Returns:
#       
#   History:
#   Date        Name        Modification
#   2013-12-18  Jason Bacon Begin
##########################################################################

usage()
{
    cat << EOM

Usage: $0 [--temp-file filename] device filesystem [label]

Do not specify partition for device.  Drive will be automatically reformatted
with a single partition.  E.g. use "da1", not "da1s1" or "da1p1".

Filesystems are specified with lower case.

Label is a string of your choice to describe the media and is case-insensitive
on some filesystems (e.g. FAT).

Example:

    $0 da1 fat32 SANDISK64

Filesystems (not all filesystems are supported on all platforms):

    fat16 (Old DOS format for small drives < 2GB)
    fat32 (Old DOS format for larger drives)
    exfat (Standard for large FLASH media, recommended for portability)
    ntfs (Windows NT and later, proprietary)
    ufs2 (FreeBSD native, not readable on most other operating systems)
    ext4 (Linux native, not readable on most other operating systems)

    * Warning: A UFS2 filesystem that is removed without being properly unmounted
    will be marked "dirty" and will not mount again until cleaned with:

    fsck /dev/device

EOM
    exit 1
}


##########################################################################
#   Function description:
#       Notify user of invalid FS selection
#       
#   History:
#   Date        Name        Modification
#   2023-07-05  Charlie &,,,Begin
##########################################################################

invalid_fs()
{
    printf "\nInvalid filesystem choice: $fs\n" >> /dev/stderr
    printf "Please consider helping the project by adding support for $fs\n"
    printf "to $0 if possible.\n\n"
    pause
    exit 1
}


fdisk_add()
{
    printf "$*\n"
    case $1 in
    fat16)
	id=6
	;;
    fat32)
	id=11
	;;
    ntfs|exfat)
	id=7
	;;
    ext4)
	id=238
	;;
    ufs|ffs)
	id=default
    esac
    got_it='n'
    while [ 0"$got_it" != 0"got it" ]; do
	printf "======================================================\n"
	printf "Update partition 0.\n"
	printf "Enter sysid $id when asked.\n"
	printf "======================================================\n"
	printf "Type 'got it' to continue: "
	read got_it
    done
    
    fdisk -u $2
    return 0
}


##########################################################################
#   Function description:
#       Pause until user presses return
##########################################################################

pause()
{
    local junk
    
    printf "Press return to continue..."
    read junk
}


##########################################################################
#   Main
##########################################################################

# Create file to flag successful format
# Used by qmediamanager, which cannot get exit status through urxvt
if [ "$1" = --temp-file ]; then
    temp_file=$2
    shift
    shift
fi

case $# in
2)
    printf "Disk label? [$2] "
    read label
    if [ -z "$label" ]; then
	label="$2"
    fi
    ;;

3)
    label="$3"
    ;;

*)
    usage
    ;;

esac

device=$1
if ! echo $device | fgrep -q /dev/; then
    device=/dev/$device
fi
if [ ! -e $device ]; then
    printf "$device: No such device.\n"
    exit 1
fi

case $(auto-ostype) in
FreeBSD)
    printf "Current partition table:\n"
    printf "===========================================================\n"
    gpart show $device || true  # Should show MBR or GPT
    printf "===========================================================\n"
    
    cat << EOM

This tool is designed to quickly reformat a USB stick or other media using
a single partition and filesystem.

EOM
    printf "All data on $device will be lost.  Continue? y/[n] "
    read continue
    if [ 0"$continue" != 0y ]; then
	exit
    fi
    
    fs=$2
    
    gpart destroy -F $device 2> /dev/null || true
    
    case $fs in
    fat16|fat32)
	dd if=/dev/zero of=$device bs=2m count=1
	gpart create -s MBR $device
	gpart add -t $fs $device
	bits=${fs#fat}
	newfs_msdos -F $bits -L "$label" ${device}s1
	;;
    
    ntfs)
	dd if=/dev/zero of=$device bs=2m count=1
	gpart create -s MBR $device
	gpart add -t ntfs $device
	mkntfs --fast --label "$label" --verbose ${device}s1
	;;
    
    exfat)
	dd if=/dev/zero of=$device bs=2m count=1
	gpart create -s MBR $device
	gpart add -t ntfs $device
	mkfs.exfat -n "$label" ${device}s1
	;;
    
    ufs2)
	dd if=/dev/zero of=$device bs=2m count=1
	gpart create -s GPT $device
	gpart add -t freebsd-ufs $device
	newfs -L "$label" ${device}p1
	;;

    ext4)
	if ! which mkfs.ext4; then
	    printf "mke2fs is not available.  Run pkg install e2fsprogs-core.\n"
	    exit 1
	fi
	dd if=/dev/zero of=$device bs=2m count=1
	gpart create -s GPT $device
	gpart add -t linux-data $device
	mkfs.ext4 -L "$label" ${device}p1
	;;
    
    *)
	invalid_fs
	;;
    esac
    
    printf "New partition scheme:\n\n"
    gpart show $device
    if [ -n "$temp_file" ]; then
	touch $temp_file
    fi
    ;;

NetBSD)
    printf "Current partition table:\n"
    printf "===========================================================\n"
    gpt show $device || true  # Should show MBR or GPT
    printf "===========================================================\n"
    
    cat << EOM

This tool is designed to quickly reformat a USB stick or other media using
a single partition and filesystem.

EOM
    printf "All data on $device will be lost.  Continue? y/[n] "
    read continue
    if [ 0"$continue" != 0y ]; then
	exit
    fi
    
    fs=$2
    char_device="/dev/r${device##/dev/}"
    
    gpt destroy $device 2> /dev/null || true
    
    case $fs in
    fat16|fat32)
	dd if=/dev/zero of=$device bs=2m count=1
	fdisk_add $fs $device
	bits=${fs#fat}
	newfs_msdos -F $bits -L "$label" ${char_device}e
	;;

    # Requires fuse-exfat 1.4.0 or later
    exfat)
	if mkfs.exfat 2>&1 | fgrep 1.3.0; then
	    printf "Error: You need fuse-exfat 1.4.0 or later.\n"
	    exit 1
	fi
	dd if=/dev/zero of=$device bs=2m count=1
	fdisk_add $fs $device
	mkfs.exfat -n "$label" ${device}e
	;;
    
    # ffs and ext4 are a bit complicated
    # Disk sizes are coming out incorrect
    # disklabel must be used before newfs
    
    *)
	invalid_fs
	;;
    esac
    
    printf "New partition scheme:\n\n"
    gpt show $device
    if [ -n "$temp_file" ]; then
	touch $temp_file
    fi
    ;;

*)
    auto-unsupported-os $0
    exit 1
    ;;

esac
pause

