#!/usr/bin/env bash
# shell script to remove all of my IPC keys
# Modified by Robert Martin to work on Mac 10.4, due to IPCS requiring sudo to list any 
# shared memory usage, even if you own it; also modified using Jim Wyllie's "kill 
# all related processes" idea
# Simplified by Shawn Ostermann in October, 2023 to remove Enhanced Regular Expressions, "grep -E", and "sed -E"
# to make it more portable (to Solaris in particular).  Also quieted down the output a little.

OS_VERS=""

# Fix for SourceForge Bug #60, killm IPC cleanup fails for long account names
# Since ipcs truncates usernames to 10 characters, we need to match against a
# truncated username so we trim the username to 10 characters.
# NOTE: This may cause conflicts with long usernames with similar beginning
#       characters. We'll look for a more robust solution in the near future.
#USERNAME_CUT=$(echo "$USER" | cut -c 1-10)
USERNAME_CUT=$(echo "$(whoami)" | cut -c 1-10)

# DEBUG: check the value of USERNAME_CUT
# echo "Abbreviated username is "${USERNAME_CUT}

# Get IONPROCESSLIST
source ionprocesslist.sh

sw_vers 2> /dev/null > /dev/null

#if sw_vers ran, then we're on a mac system
if [ "$?" -eq 0 ]; then  
	OS_VERS=$(sw_vers | grep 10.4)
fi

OSNAME=`uname`
if [ "$OSNAME" = "SunOS" ]; then
    KILLCMD="pkill"
	PS="/usr/bin/ps"
	PS_ARGS="-fe"
	PROCESS_LIMIT=1
elif [[ "$OSNAME" == "MINGW"* ]]; then
  	KILLCMD="taskkill /f /im"
  	PS="tasklist"
  	PS_ARGS=""
  	PROCESS_LIMIT=64
  	MINGW="true"
else
    KILLCMD="killall"
	PS="ps"
	PS_ARGS="-fe"
	if [ "$(uname -m)" = "x86_64" ]; then
		PROCESS_LIMIT=64
	else
    	PROCESS_LIMIT=32
	fi
fi

if [ "$MINGW" != "true" ]; then
	#echo "Sending TERM to ${IONPROCESSLIST}..."   # (too noisy)
	echo "Sending TERM to the processes..."
	echo "${IONPROCESSLIST}" | xargs -n $PROCESS_LIMIT $KILLCMD 2> /dev/null
	
	# DEBUG: show killall command error
	#echo "${IONPROCESSLIST}" | xargs -n $PROCESS_LIMIT $KILLCMD

	sleep 2

	echo "Sending KILL to the processes..."
	echo "${IONPROCESSLIST}" | xargs -n $PROCESS_LIMIT $KILLCMD -KILL 2> /dev/null
	
	# DEBUG: show killall command error
	#echo "${IONPROCESSLIST}" | xargs -n $PROCESS_LIMIT $KILLCMD -KILL

	sleep 2
else
	# note that the TERM signal isn't supported in Windows, so processes are only killed. This also must be done via powershell
	echo "Killing processes using PowerShell..."
    powershell -Command "foreach (\$proc in '${IONPROCESSLIST}'.Split(' ')) { \$proc = \$proc.Trim(); taskkill /F /IM \"\$proc.exe\" }" 2> /dev/null
fi


echo "Checking if all ION processes ended..."

PSFILE="/tmp/ps.$$"
# grab all running processes
${PS} ${PS_ARGS} > ${PSFILE}

# DEBUG: show the PSFILE
#echo "Current running processes:"
#cat ${PSFILE}
#ps -eo pid,ppid,state,cmd

# see if any of those still-running processes belong to ION
for PROC in ${IONPROCESSLIST}; do
    grep "[^-a-zA-Z]${PROC}$" "${PSFILE}" | grep -v "defunct" | \
        awk '{printf("  *** Unknown error: process %s not killed...try rebooting\n", $NF);}'
done
if [ -z "$USERNAME_CUT" ]; then
    echo "Error: USERNAME_CUT is not set or empty."
    exit 1
fi
rm -f ${PSFILE}

echo "Deleting shared memory to remove SDR..."

if [ "$MINGW" == "true" ]; then 
	# for 2024 redesign of Windows MSYS
	powershell remove_win_shmem.ps1 
elif [[ -z "$OS_VERS" ]]; then 
	# For mac >=10.5 and Linux
	
	# DEBUG: show ipcs before ipcrm
	#echo "Before ipcrm, SRV4 IPC:"
	#ipcs
	
	for Q in `ipcs -q | grep $USERNAME_CUT | awk '{ print $2 }'`; do ipcrm -q $Q; done
	for M in `ipcs -m | grep $USERNAME_CUT | awk '{ print $2 }'`; do ipcrm -m $M; done
	for S in `ipcs -s | grep $USERNAME_CUT | awk '{ print $2 }'`; do ipcrm -s $S; done
	
	# DEBUG: show ipcs after ipcrm
	#echo "After ipcrm, SRV4 IPC:"
	#ipcs
else
	# For mac 10.4, since ipcs on it is weird.
	echo "Since ipcs on Apple OSX 10.4 is weird, this script (killm) needs to use sudo, and will ask for your password"
	for Q in `sudo ipcs -q | grep $USERNAME_CUT | awk '{ print $3 }'`; do ipcrm -Q $Q; done
	for M in `sudo ipcs -m | grep $USERNAME_CUT | awk '{ print $3 }'`; do ipcrm -M $M; done
	for S in `sudo ipcs -s | grep $USERNAME_CUT | awk '{ print $3 }'`; do ipcrm -S $S; done
fi

# remove posix named semaphores if this platform maps them into the file system
# Solaris puts them in /tmp/.SEM*, Linux in /dev/shm/sem.*, MacOS doesn't put them in file system
# FreeBSD puts them in /tmp/SEM*
echo "Deleting Posix Named Semaphores..."

# DEBUG: show POSIX Name Semaphore files before removal
#echo "Before deletion, Posix Name Semaphore Files:"
#ls /dev/shm/sem.ion:GLOBAL*
#ls /tmp/.SEM*ion:GLOBAL*
#ls /tmp/SEM*ion:GLOBAL*

# Function to safely remove semaphore files
remove_semaphores() {
    local path="$1"
    local pattern="$2"
    
    if [ -d "$path" ]; then
        local files=$(find "$path" -name "$pattern" 2>/dev/null)
        if [ -n "$files" ]; then
            #echo "Removing from $path:"
            #echo "$files"
            rm -f $files 2>/dev/null
        fi
    fi
}

# Function to find remaining semaphores
find_remaining() {
    local remaining=""
    
    # Check all possible paths
    for path in "/dev/shm" "/tmp" "/tmp/.LIBRT/SEMD" "/tmp/.LIBRT/SEML"; do
        if [ -d "$path" ]; then
            local found=$(find "$path" -maxdepth 1 -name "*ion:GLOBAL*" -o -name "sem.ion:GLOBAL*" -o -name ".SEM*ion:GLOBAL*" -o -name "SEM*ion:GLOBAL*" 2>/dev/null)
            if [ -n "$found" ]; then
                remaining="$remaining$found\n"
            fi
        fi
    done
    
    echo -e "$remaining"
}

echo -e "\n=== Starting cleanup ==="

# Linux paths (/dev/shm)
remove_semaphores "/dev/shm" "sem.ion:GLOBAL*"

# Generic /tmp paths FreeBSD
remove_semaphores "/tmp" ".SEM*ion:GLOBAL*"
remove_semaphores "/tmp" "SEM*ion:GLOBAL*"

# Solaris LIBRT paths
remove_semaphores "/tmp/.LIBRT/SEMD" "*ion:GLOBAL*"
remove_semaphores "/tmp/.LIBRT/SEML" "*ion:GLOBAL*"

# Check for any remaining semaphores
echo -e "\n=== Checking for remaining semaphores ==="
remaining=$(find_remaining)

if [ -n "$remaining" ] && [ "$remaining" != "" ]; then
    echo "*** WARNING: Some semaphores could not be removed ***"
    echo "*** Re-run script with sudo to remove remaining semaphores: ***"
    echo -e "$remaining"
    exit 1
else
    echo "All ion:GLOBAL semaphores removed successfully"
fi

echo -e "\nAfter deletion, remaining POSIX Named Semaphore files (should be blank)..."
find_remaining
# DEBUG: show POSIX Name Semaphore files after removal
#echo "After deletion, Posix Name Semaphore Files:"
#ls /dev/shm/sem.ion:GLOBAL*
#ls /tmp/.SEM*ion:GLOBAL*
#ls /tmp/SEM*ion:GLOBAL*

echo "Killm completed."	
exit 0
