#!/bin/sh -e

##########################################################################
#   Synopsis:
#       devpub-mount [/dev/]partition
#
#   Description:
#       .B devpub-mount
#       is a script for mounting external media on NetBSD.  It is
#       normally invoked by /libexec/devpubd-hooks/03-devpub-mount,
#       which is run by the devpubd(8) service upon creation of
#       a new device node such as /dev/sd0.  This typically occurs
#       when a USB drive is inserted, for example.
#
#       The device name should contain a filesystem recognized
#       by NetBSD or by fusefs, such as EXFAT, FAT32, FAS16, NTFS,
#       ISO 9660 (CDs), UDF (DVDs), of FFS (NetBSD native).
#
#       The mount point for a device is /media/device-name, e.g.
#       /dev/sd0e is mounted on /media/sd0e.
#
#       The configuration file /usr/pkg/etc/devpub-mount.conf
#       can be used to control
#       ownership and permissions on the mount point, and the program
#       invoked upon a successful mount.  Defaults are shown below.
#       
#       .nf
#       .na
#       MEDIA_MANAGER=/usr/pkg/bin/qmediamanager
#       GROUP=operator
#       MODE=775
#       .ad
#       .di
#
#       The auto-automount-setup(1) script, part of sysutils/auto-admin
#       will configure a NetBSD system to use devpub-mount.
#       
#   Arguments:
#       device  Name of device node, with or without /dev/ prefix
#       
#   Returns:
#       0 upon successful mount, non-zero error codes otherwise
#
#   Examples:
#       devpub-mount sd0e
#
#   Files:
#       /usr/pkg/etc/devpub-mount.conf
#       /libexec/devpubd-hooks/03-devpub-mount
#
#   See also:
#       devpubd(8), mount(8), qmediamanager(1), npmount(1)
#       
#   History:
#   Date        Name        Modification
#   2023-06-15  J Bacon     Begin
##########################################################################

usage()
{
    printf "Usage: $0 [/dev/]partition\n"
    exit 1
}


##########################################################################
#   Function description:
#       Launch chosen media manager program on the local X11 display
#       
#   History:
#   Date        Name        Modification
#   2023-06-15  J Bacon     Begin
##########################################################################

media_manager()
{
    if [ $# != 3 ]; then
	printf "Usage: media_manager mount-point partition fs-type\n" >> /dev/stderr
	exit 1
    fi
    mount_point=$1
    device=$2
    fs_type=$3

    # This fails under SDDM:
    # DISPLAY_ID=$(ps -ax -p `pgrep bin/X` | fgrep bin/X | awk '{ print $6 }')
    # ps -axw -p `pgrep Xorg` | fgrep libexec/Xorg
    # 1413  -  S    0:09.75 /usr/local/libexec/Xorg -nolisten tcp -auth /var/run/sddm/{f5f14042-f00a-4038-9de7-94f125def9a0} -background 
    DISPLAY_ID=:0

    # Debug
    printf "DISPLAY_ID = $DISPLAY_ID\n" >> $log

    # Build command to run following mount
    : ${MEDIA_MANAGER:="qmediamanager mount-point device fs-type"}
    no_tabs=$(echo "$MEDIA_MANAGER" | tr '\t' ' ')
    cmd=$(echo "$no_tabs" | cut -d ' ' -f 1)
    for arg in $(echo "$no_tabs" | cut -d ' ' -f 2-); do
	printf "arg = $arg\n"
	case $arg in
	mount-point)
	    cmd="$cmd $mount_point"
	    ;;
	
	device)
	    cmd="$cmd $device"
	    ;;
	
	fs-type)
	    cmd="$cmd $fs_type"
	    ;;
	
	*)
	    cmd="$cmd $arg"
	    ;;
	esac
    done
    
    printf "cmd = $cmd\n" >> $log
    
    # FIXME: Determine owner of :0
    display_users=$(ps aewwj | grep "DISPLAY=${DISPLAY_ID}" | awk '{ print $1 }' | sort -u)
    for user in $display_users; do
	if su -l $user -c "env DISPLAY=$DISPLAY_ID $cmd"; then
	    break;
	fi
    done
}


try_mount()
{
    partition=$1
    mount_point=/media/${partition#/dev/}
    mkdir -p $mount_point
    
    # FIXME: chown and chgrp don't work on many filesystems
    # Find a way to set ownership and perms
    if [ -n "$GROUP" ]; then
	chgrp $GROUP $mount_point
    fi
    if [ -n "$MODE" ]; then
	chmod $MODE $mount_point
    fi
    
    ##########################################################################
    #   Determining filesystem type if not straightforward.  The fstyp
    #   command is extremely limited.  We simply try supported filesystems
    #   where fstyp cannot assist.
    ##########################################################################
    
    printf "$partition $mount_point\n" >> $log
    
    if [ "$(fstyp $partition)" = msdosfs ] && /sbin/mount_msdos $partition $mount_point 2>> $log; then
	printf "Mounted FAT.\n" >> $log
	media_manager $mount_point $partition fat 2>> $log
    elif [ "$(fstyp $partition)" = cd9660 ] && /sbin/mount_cd9660 $partition $mount_point 2>> $log; then
	printf "Mounted cd9660.\n" >> $log
	media_manager $mount_point $partition cd9660 2>> $log
    elif [ "$(fstyp $partition)" = ntfs ] && /sbin/mount_ntfs $partition $mount_point 2>> $log; then
	printf "Mounted NTFS.\n" >> $log
	media_manager $mount_point $partition ntfs 2>> $log
    elif [ "$(fstyp $partition)" = ufs ] && /sbin/mount $partition $mount_point 2>> $log; then
	printf "Mounted UFS.\n" >> $log
	media_manager $mount_point $partition ufs 2>> $log
    elif /usr/pkg/sbin/mount.exfat $partition $mount_point 2>> $log; then
	printf "Mounted exfat.\n" >> $log
	media_manager $mount_point $partition exfat 2>> $log
    elif /sbin/mount_udf $partition $mount_point 2>> $log; then
	printf "Mounted UDF.\n" >> $log
	media_manager $mount_point $partition udf 2>> $log
    else
	printf "Could not mount $partition.\n" >> $log
	# Notify user about normal partitions (sd0a, sd0b, ...) that
	# cannot be mounted.
	if echo $partition | grep -Eq "sd[0-9]+[a-z]+"; then
	    media_manager $mount_point $partition "unknown"
	fi
	return 1
    fi
}


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

if [ $# != 1 ]; then
    usage
fi
partition=$1
if ! echo $partition | grep -q '^/dev/'; then
    partition=/dev/$partition
fi
log=/var/log/devpub-mount/${partition#/dev/*}
mkdir -p $(dirname $log)
rm -f $log

conf_file=/usr/pkg/etc/devpub-mount.conf
if [ -e $conf_file ]; then
    . $conf_file
fi
try_mount $partition
