#!/bin/bash
# vim: cindent:shiftwidth=4:tabstop=4:smarttab:textwidth=100

#$title$ shared library runtime version freshness
#$check$ use of new system libraries deployed via APT updates instead of old versions
#$ref$ man lsof
#$author$ Rafal Rzeczkowski
#$version$ 0.57

level_check long

#CHANGELOG
#0.50	initial
#0.51	count open files in lsof output properly
#0.52	metadata headers, help messages
#0.53	restyle according to https://kb.clearcable.ca/KB/ProgrammingStyleStandards
#0.54	filter Java temporary files
#0.55	downgrade failure report level to caution
#0.56	filter MythTV temporary files
#0.57	integrate with the the FIX API

declare -r -a PROBLEMS=(OLD_LIBRARY_IN_USE)

TMP_LSOF=$(mktemp)
TMP_AWK=$(mktemp)

if ! lsof -Fcftn / > "$TMP_LSOF"; then
	fail warning 'failed to run lsof'
	helpmsg 'contact the plugin maintainer'
	rm "$TMP_LSOF"
	exit
fi

OPEN_FILE_COUNT=$(grep --extended-regexp --count '^n' < "$TMP_LSOF")
echodebug "library freshness scan of $OPEN_FILE_COUNT open files on the root filesystem"

if ! awk --assign DEBUG="$DEBUG" '
function errprint(msg) {
	if (DEBUG) {print msg > "/dev/stderr"}
}
{
	field=substr($0,1,1)
	data=substr($0,2)
	if (field=="f") {
		file_descriptor=data
	} else if (field=="p") {
		pid=data
	} else if (field=="t") {
		file_type=data
	} else if (field=="c") {
		command_name=data
	} else if (field=="n") {
		name=data
		#errprint(file_descriptor "\t" file_type "\t" pid "\t" command_name "\t" name)
		if (command_name=="java" && name~"/tmp/")
			errprint("filtered Java temporary file: " name)
		else if (command_name=="mythfrontend" && name~"/#")
			errprint("filtered MythTV temporary file: " name)
		else if (file_descriptor=="DEL" && file_type=="REG")
			file[command_name]++
	}
}
END {
	for (name in file) {
		errprint(file[name] "\t" name)
		error++
		if (error_name)
			error_name=error_name " "
		error_name=error_name name
	}
	if (error_name) {
		print error_name
		exit error
	} else {
		exit
	}
}' "$TMP_LSOF" > "$TMP_AWK"; then
	PROC=($(<"$TMP_AWK"))
	printf -v MSG 'old library used by %d %s: %s' \
		${#PROC[@]} $(plural_text ${#PROC[@]} 'process') "${PROC[*]}"
	fail caution "$MSG"
	problem OLD_LIBRARY_IN_USE $(printf '%s;' ${PROC[@]})
	helpmsg 'restart the affected process using their init.d script'
else
	ok
fi
rm "$TMP_LSOF" "$TMP_AWK"
