#!/bin/sh

# Copyright: 2026 Lorenzo Puliti <plorenzo@disroot.org>
# License: BSD-3-clause
# or GPL-2+ if shipped with cruft-ng

set -e

pkg_is_purged () {
	#takes pkgname as arg; return 0 if pkgname is purged // 1 if installed or removed
	pkgname=$1
	if dpkg -s $pkgname 2>/dev/null >/dev/null ; then
		return 1
	else
		return 0
	fi
#TODO
# cruft-ng pkg --> /usr/libexec/cruft/TMPFILES
# look at explain/TMPFILES: there is now a "@" protocol
# to delegate the "dpkg -S" step for later evaluation
# to the main C/C++ cruft-ng engine.
}

print_extra_dirs () {
	#takes service as arg; print log dirs and other files if any
	#service enabled (link) or disabled (.link) symlinks
	[ -h /etc/service/$service ] && echo "/etc/service/$service"
	[ -h /etc/service/.$service ] && echo "/etc/service/.$service"
	# sysv override files: 'foo.pkgsysv', 'foo.pkgrunit' or  'foo.pkgblock'
	[ -f /etc/runit/override-sysv.d/$service.pkgblock ] && echo "/etc/runit/override-sysv.d/$service.pkgblock"
	[ -f /etc/runit/override-sysv.d/$service.pkgrunit ] && echo "/etc/runit/override-sysv.d/$service.pkgrunit"
	[ -f /etc/runit/override-sysv.d/$service.pkgsysv ] && echo "/etc/runit/override-sysv.d/$service.pkgsysv"
	[ -f /etc/runit/override-sysv.d/$service.block ] && echo "/etc/runit/override-sysv.d/$service.block"
	[ -f /etc/runit/override-sysv.d/$service.runit ] && echo "/etc/runit/override-sysv.d/$service.runit"
	[ -f /etc/runit/override-sysv.d/$service.sysv ] && echo "/etc/runit/override-sysv.d/$service.sysv"
	 #log dir: inside there are @*.u, @*.s, current, lock and maybe .pkg
	[ -d /var/log/runit/$service ] && echo "/var/log/runit/$service"
	return 0
}

for overrides in /etc/runit/override-sysv.d/* ; do
	overridefile=${overrides##*/}
	[ $overridefile = 'README' ] && continue
	[ $overridefile = 'runit-default' ] && continue
	service=${overridefile%.*}
	#override files are cruft if their service is not found in the system
	if [ -d /etc/sv/$service ]; then
		continue
	elif [ -d /usr/share/runit/sv.now/$service ]; then
		continue
	elif [ $overridefile = "$service.pkgblock" ] && [ -f /etc/init.d/$service ]; then
		#unconditionally blocks a sysv script, no need for runit service
		continue
	else
		echo "$overrides"
	fi
done

for svname in /etc/sv/* /usr/share/runit/sv.now/* ; do
	#/etc/sv/svlogd is from runit pkg
	if [ $svname = '/etc/sv/svlogd' ]; then
		if pkg_is_purged runit ; then
			echo "$svname"
		else
			continue
		fi
	fi
	#template for user service supervision
	if [ $svname = '/usr/share/runit/sv.now/runsvdir@user' ]; then
		if pkg_is_purged runit ; then
			echo "$svname"
		else
			continue
		fi
	fi
	service=${svname##*/}
	pkgname=
	if [ 'runsvdir' = "${service%@*}"  ]; then
		#user service nested instance; not cruft if user exists
		user="${service##*@}"
		if ! getent passwd $user >/dev/null ; then
			echo "$svname"
		else
			continue
		fi
	fi
	if [ ! -d $svname ]; then  #only dirs are valid runit services
		echo "$svname"
		continue
	fi
	if [ -e $svname/.meta/installed ]; then
		# this is the legacy interface: dh_runit + runit-helper + service installed in /etc/sv/
		# it may be removed in future but it's here for now
		if [ ! -e /usr/share/runit/meta/$service/installed ]; then
			#removed: try to guess if it's purged too
			#NOTE this may generate a false report as servicename=pkgname is not reliable...
			if pkg_is_purged $service ; then
				echo "$svname"
				print_extra_dirs "$service"
				continue
			fi
		else
			continue #not cruft, service belongs to an installed pkg
		fi
		continue
	elif [ -r $svname/.meta/bin ]; then
		# this is dh_runit + runit-trigger (trigger_sv) interface
		binpath=$(cat $svname/.meta/bin)
		if [ ! -e $binpath ]; then
			#binary no longer installed, pkg is premoved: use pkg metafile
			if [ -r $svname/.meta/pkg ]; then
				pkgname=$(cat $svname/.meta/pkg)
			else #should not happen, still..
				pkgname=$service
			fi
			if pkg_is_purged $pkgname ; then
				echo "$svname"
				print_extra_dirs "$service"
				continue
			fi
		else
			continue #pkg is still installed, not cruft
		fi
		continue
	else
		#not installed with dh-runit; try to wildguess servicename=pkgname otherwise is cruft
		#NOTE this may generate a false report as servicename=pkgname is not reliable...
		if pkg_is_purged $service ; then
			echo "$svname"
			print_extra_dirs "$service"
		fi
	fi
done

#check for log directories with no service found
for logdir in   /var/log/runit/* ; do
	service=${logdir##*/}
	if [ -d /etc/sv/$service ]; then
		continue
	elif [ -d /usr/share/runit/sv.now/$service ]; then
		continue
	else # no service found, logdir is cruft
		echo "$logdir"
	fi
done



#NOTE the following requires root
[ "$(id -u)" != 0 ] && exit 0
#supervie dirs: /var/ is old and discarded design
# the current design for foo service is /run/runit/supervise/foo and /run/runit/supervise/foo.log
# note that /run is a tmpfs in runit, not sure there is value on running checks there

for supervise in /var/lib/supervise/* /var/lib/runit/supervise/* /run/runit/supervise/* ; do
	#should not list as removable if there is a service active on this supervise dir
	if which chpst > /dev/null ; then
		if chpst -L "$supervise"/lock true 2>/dev/null ; then
			echo "$supervise"
		else
			continue #supervise is used by a runsv process, can't be removed
		fi
	elif which flock >/dev/null ; then # fallback on flock
		if flock -F -n "$supervise"/lock true ; then
			echo "$supervise"
		else
			continue
		fi
	else #wtf, Hurd port?  without runit installed
		echo "unreliable: $supervise"
	fi
done




