#!/bin/sh

# Hard links to link.
# https://www.reddit.com/r/linuxquestions/comments/pbxlbm/is_there_any_disadvantage_of_using_a_hardlink/haipc4r/
# For argument that has multiple links,
# as identically as feasible, convert it to file having link count of one.
# Other links to the original remain the same except their link count
# decrementing by one, newly created target will be new file with
# inode number different from the original.

set -e # should suffice for handling most of the more common errors
# our program name - just base portion for more concise self-reference:
progname="$(basename -- "$0")"

# vi(1) :se tabstop=4

# usage information for, e.g. diagnostics:
my_usage(){
	echo "usage: $progname file"
}

# need exactly one argument
case "$#" in
	1):;; # okay
	*)
		my_usage 2>&1
		exit 1
	;;
esac

# our target file
file="$1"

# target needs to exist and not be directory and have more than one hard link

set -e # should suffice for catching errors
ls_info="$(ls -ond -- "$1")"

case "$ls_info" in
	d*)
		echo "$progname: not allowed, is directory: $file" 2>&1
		my_usage 2>&1
		exit 1
	;;
	-*):;;# type ordinary file
	?*)
		# TO DO?  :-)
		echo "$progname: not yet implemented, is neither file nor directory:" \
			"$file" 2>&1
		my_usage 2>&1
		exit 1
	;;
	'') # this probably shouldn't be possible, but just in case
		echo "$progname: failed to get lstat(2) info for: $file" 2>&1
		my_usage 2>&1
		exit 1
	;;
esac

# Need to have multiple hard links
link_count="$(set -- $ls_info; echo "$2")"
case "$link_count" in
	[01])
		echo "$progname: link count ($link_count) too low on: $file" 2>&1
		exit 1
	;;
	[2-9]|[1-9][0-9]*)
		: # link count okay
	;;
	*)	# this probably shouldn't be possible, but just in case
		echo "$progname: bad/missing link count ($link_count) for: $file" 2>&1
		exit 1
	;;
esac

# so far so good, need new temporary in same directory
# still have set -e
dirname="$(dirname -- "$file")"
basename="$(basename -- "$file")"
tmpf="$(mktemp "$dirname/tmpXXXXXXXXXX.$progname")"
# handle common catchable signals
for sig in 1 2 3 15
do
	# still have set -e for exceptions,
	# remove file, avoid multiple trappings
	# whack ourselves with same signal without catching it
	trap 'rm -f -- "$tmpf"
		trap - 0 '"$sig"'
		kill -'"$sig $$"'
	' "$sig"
done

rc=0 # exit return code/value, change when appropriate

# handle cleanup in other cases
# still have set -e for exceptions,
# remove file, avoid multiple trappings
trap '
		rm -f -- "$tmpf"
		trap - 0
		exit "$rc"
	' 0

cp -p -- "$file" "$tmpf" ||
	rc=1 # cp should also give sufficient stderr

if mv -f -- "$tmpf" "$file"; then
	# nothing left to clean up or do, cancel our trap and exit
	trap - 0
	exit
else
	rc=1 # mv should also give sufficient stderr
fi
