#!/bin/sh
set -eu

GADGET_DIR="/sys/kernel/config/usb_gadget/isignage-flash"
CONFIG_NAME="c.1"
FUNCTION_NAME="mass_storage.0"

log() {
    printf '[otg-flash-export] %s\n' "$*"
}

mount_configfs() {
    if ! mountpoint -q /sys/kernel/config; then
        mount -t configfs none /sys/kernel/config
    fi
}

load_libcomposite() {
    if [ ! -d /sys/module/libcomposite ]; then
        modprobe libcomposite
    fi
}

root_disk() {
    root_source="$(findmnt -nro SOURCE / || true)"
    if [ -z "$root_source" ]; then
        return 1
    fi

    lsblk -dnro PKNAME "$root_source" 2>/dev/null | sed 's#^#/dev/#'
}

find_emmc_disk() {
    live_root="$(root_disk || true)"

    for path in /sys/class/block/mmcblk*; do
        [ -e "$path" ] || continue
        disk="/dev/$(basename "$path")"
        type_file="$path/device/type"
        [ -f "$type_file" ] || continue
        if [ "$(cat "$type_file")" != "MMC" ]; then
            continue
        fi
        if [ -n "$live_root" ] && [ "$disk" = "$live_root" ]; then
            continue
        fi
        printf '%s\n' "$disk"
        return 0
    done

    return 1
}

first_udc() {
    for udc in /sys/class/udc/*; do
        [ -e "$udc" ] || continue
        basename "$udc"
        return 0
    done

    return 1
}

stop_export() {
    if [ ! -d "$GADGET_DIR" ]; then
        return 0
    fi

    if [ -e "$GADGET_DIR/UDC" ]; then
        printf '' > "$GADGET_DIR/UDC" || true
    fi

    rm -f "$GADGET_DIR/configs/$CONFIG_NAME/$FUNCTION_NAME" || true
    rmdir "$GADGET_DIR/functions/$FUNCTION_NAME" 2>/dev/null || true
    rmdir "$GADGET_DIR/configs/$CONFIG_NAME/strings/0x409" 2>/dev/null || true
    rmdir "$GADGET_DIR/configs/$CONFIG_NAME" 2>/dev/null || true
    rmdir "$GADGET_DIR/strings/0x409" 2>/dev/null || true
    rmdir "$GADGET_DIR" 2>/dev/null || true
}

start_export() {
    mount_configfs
    load_libcomposite

    target_disk="$(find_emmc_disk || true)"
    if [ -z "$target_disk" ]; then
        log "no non-root eMMC disk found to export"
        exit 1
    fi

    udc="$(first_udc || true)"
    if [ -z "$udc" ]; then
        log "no USB device controller available"
        exit 1
    fi

    stop_export || true
    sync

    mkdir -p "$GADGET_DIR"
    printf '0x1d6b\n' > "$GADGET_DIR/idVendor"
    printf '0x0104\n' > "$GADGET_DIR/idProduct"
    printf '0x0100\n' > "$GADGET_DIR/bcdDevice"
    printf '0x0200\n' > "$GADGET_DIR/bcdUSB"

    mkdir -p "$GADGET_DIR/strings/0x409"
    printf 'Microworks\n' > "$GADGET_DIR/strings/0x409/manufacturer"
    printf 'iSignage OTG Flash\n' > "$GADGET_DIR/strings/0x409/product"
    cat /etc/hostname > "$GADGET_DIR/strings/0x409/serialnumber"

    mkdir -p "$GADGET_DIR/configs/$CONFIG_NAME/strings/0x409"
    printf 'Flash eMMC\n' > "$GADGET_DIR/configs/$CONFIG_NAME/strings/0x409/configuration"
    printf '250\n' > "$GADGET_DIR/configs/$CONFIG_NAME/MaxPower"

    mkdir -p "$GADGET_DIR/functions/$FUNCTION_NAME"
    printf '1\n' > "$GADGET_DIR/functions/$FUNCTION_NAME/stall"
    printf '1\n' > "$GADGET_DIR/functions/$FUNCTION_NAME/lun.0/removable"
    printf '0\n' > "$GADGET_DIR/functions/$FUNCTION_NAME/lun.0/ro"
    printf '%s\n' "$target_disk" > "$GADGET_DIR/functions/$FUNCTION_NAME/lun.0/file"

    ln -s "$GADGET_DIR/functions/$FUNCTION_NAME" "$GADGET_DIR/configs/$CONFIG_NAME/$FUNCTION_NAME"
    printf '%s\n' "$udc" > "$GADGET_DIR/UDC"

    log "exporting $target_disk via UDC $udc"
}

case "${1:-}" in
    start)
        start_export
        ;;
    stop)
        stop_export
        ;;
    restart)
        stop_export
        start_export
        ;;
    status)
        if [ -d "$GADGET_DIR" ] && [ -e "$GADGET_DIR/UDC" ] && [ -n "$(cat "$GADGET_DIR/UDC" 2>/dev/null)" ]; then
            printf 'active\n'
        else
            printf 'inactive\n'
        fi
        ;;
    *)
        printf 'usage: %s {start|stop|restart|status}\n' "$0" >&2
        exit 1
        ;;
esac
