#!/bin/bash

test -z "$1" && echo "Usage: $0 kernel-directory" && exit 1

function check_header()
{
	while read FILE; do
		if egrep -q "$1" $FILE; then
			test -n "$2" && echo "$FILE has $1"
		else
			test -z "$2" && echo "$FILE is missing $1"
		fi
	done
}
function includers_to_re()
{
	grep -Hcr "$2" "$1/include/linux" | awk -F: '$2 > 0 { gsub("'"$1"'/include/", ""); gsub("/", "\\/"); printf "%s|", $1 }'
}

VARS=
if test -e "$1/include/linux/vs_pid.h"; then
	VARS="$VARS pid=2;"
else
	VARS="$VARS pid=1;"
fi

grep -q linux/mount.h "$1/include/linux/fs.h" && VARS="$VARS fs_has_mount=1;"
grep -q linux/mount.h "$1/include/linux/namespace.h" && VARS="$VARS namespace_has_mount=1;"
grep -q linux/vs_cvirt.h "$1/include/linux/ptrace.h" && VARS="$VARS ptrace_has_cvirt=1;"
grep -q REALPID "$1/include/linux/pid.h" && VARS="$VARS pidtype=1;"
grep -q linux/vs_base.h "$1/include/linux/sched.h" && VARS="$VARS sched_has_base=1;"
BASE_HEADERS=$(includers_to_re "$1" vserver/base.h)
CONTEXT_HEADERS=$(includers_to_re "$1" vserver/context.h)
test -e "$1/include/linux/vs_utsname.h" && VARS="$VARS vs_utsname=1;"

find ${2:-$1} -name '*.c' | while read LINE; do
FVARS="$VARS FILE="'"'"$LINE"'";'
awk '	BEGIN {
		'"$FVARS"'
	}
	/->(total_vm|_rss|_anon_rss|_file_rss|locked_vm)[ 	]*([\+\-]?=|\+\+|--)/ { printf "%s has mm stuff: %s\n", FILE, $0; }
	/find_task_by_pid\(/ && !pidtype { needs_pid=1; }
	/vx_(info_)?r?map_(p|tg)id/ { needs_pid=1; }
	/vx_new_uts|vx_(de)?activate_task|vx_uninterruptible_(inc|dec)/ && !vs_utsname { needs_cvirt=1; }
	/vx_vsi_uptime|vx_update_load|vx_uts_virt_handler|vx_do_syslog/ { needs_cvirt2=1; }
	/MNT_IS_RDONLY\(/ { needs_mount=1; }
	/vx_(vmpages|vmlocked|file_rsspages|anon_rsspages|rsspages|anonpages)_(add|sub|inc|dec|avail)/ { needs_memory=1; }
	/(set|add|sub|inc|dec)_mm_counter/ { needs_memory=1; }
	/([vn]x_task_xid|[vn]x_current_xid|current_[vn]x_info|[vn]x_check|__vs_check|[vn]x_weak_check|vs_check_flags|vs_mask_flags|vs_mask_mask|vs_check_bit|__[vn]x_flags|[vn]x_current_flags|[vn]x_info_flags|task_[vn]x_flags|[vn]x_flags|__vx_ccaps|vx_current_ccaps|vx_info_ccaps|vx_ccaps|__nx_ncaps|nx_current_ncaps|nx_info_ncaps|nx_ncaps|__vx_mcaps|vx_info_mcaps|vx_mcaps|__vx_bcaps|vx_current_bcaps|vx_info_bcaps|vx_bcaps|vx_info_cap_bset|vx_current_cap_bset|__vx_info_mbcap|vx_info_mbcap|task_vx_mbcap|vx_mbcap|vx_cap_raised|vx_capable|vx_current_initpid|__[vn]x_state|[vn]x_info_state)\(/ { needs_base=1; }
	/(VX[FMCS]_[A-Z_]+|struct vx_info(_save)?|((claim|release|lookup|lookup_or_create)_vx_info|get_xid_list|xid_is_hashed|vx_migrate_task|vs_state_change)\(|vxi->)/ { needs_context=1; }
	/#include ["<]linux\/vs_pid.h[">]/ { has_vs_pid=1; }
	/#include ["<]linux\/vs_cvirt.h[">]/ { has_vs_cvirt=1; }
	/#include ["<]linux\/vserver\/cvirt.h[">]/ { has_vs_cvirt2=1; }
	/#include ["<]linux\/mount.h[">]/ { has_mount=1; }
	/#include ["<]linux\/fs.h[">]/ { has_fs=1; }
	/#include ["<]linux\/namespace.h[">]/ { has_namespace=1; }
	/#include ["<]linux\/vs_memory.h[">]/ { has_memory=1; }
	/#include ["<]linux\/ptrace.h[">]/ { has_ptrace=1; }
	/#include ["<]asm\/tlb.h[">]/ { has_memory=1; }
	/#include ["<]linux\/vs_base.h[">]/ { has_base=1; }
	/#include ["<]linux\/vserver\/base.h[">]/ { has_base=1; }
	/#include ["<]linux\/sched.h[">]/ && sched_has_base { has_base=1; }
	/#include ["<]('"$BASE_HEADERS"')[">]/ { has_base_indirect=1; }
	/#include ["<]('"$CONTEXT_HEADERS"')[">]/ { has_context=1; }
	END {
		if (pid == 2 && !has_vs_pid && needs_pid) {
			printf "%s is missing linux/vs_pid.h\n", FILE;
		}
		else if (pid == 2 && has_vs_pid && !needs_pid) {
			printf "%s doesn'"'"'t need linux/vs_pid.h\n", FILE;
		}
		if (!has_vs_cvirt && !(ptrace_has_cvirt && has_ptrace) && ((pid == 1 && needs_pid) || (needs_cvirt && !vs_utsname))) {
			printf "%s is missing linux/vs_cvirt.h\n", FILE;
		}
		else if (has_vs_cvirt && (!(pid == 1 && needs_pid) && !needs_cvirt && !needs_cvirt2)) {
			printf "%s doesn'"'"'t need linux/vs_cvirt.h\n", FILE;
		}
		if (needs_cvirt2 && !has_vs_cvirt2 && !has_vs_cvirt) {
			printf "%s is missing linux/vserver/cvirt.h\n", FILE;
		}
		else if (has_vs_cvirt2 && !needs_cvirt2) {
			printf "%s doesn'"'"'t need linux/vserver/cvirt.h\n", FILE;
		}
		if (needs_mount && !((fs_has_mount && has_fs) || (namespace_has_mount && has_namespace) || has_mount)) {
			printf "%s is missing linux/mount.h\n", FILE;
		}
		if (needs_memory && !has_memory) {
			printf "%s is missing linux/vs_memory.h\n", FILE;
		}
		if (needs_base && !has_base && !has_base_indirect) {
			printf "%s is missing linux/vs_base.h\n", FILE;
		}
		else if (!needs_base && has_base) {
			printf "%s doesn'"'"'t need linux/vs_base.h\n", FILE;
		}
		if (needs_context && !has_context) {
			printf "%s is missing linux/vs_context.h\n", FILE;
		}
	}
' $LINE
done
cat > /dev/null <<EOF
test "$SC" -le 0 && egrep -Hr -- '->(total_vm|_rss|_anon_rss|_file_rss|locked_vm)\s*([\+\-]?=|\+\+|--)' "$1"
grep -q linux/vs_cvirt.h "$1/include/linux/ptrace.h" && pid=$pid'|linux/ptrace.h'
test "$SC" -le 1 && grep -cHr 'find_task_by_pid(' "$1" | awk -F: '$2 > 0 { print $1; }' | check_header $pid
test "$SC" -le 2 -a "$pid" != "linux/vs_cvirt.h" && grep -cHr $pid "$1" | awk -F: '$2 > 0 { print $1; }' | check_header 'find_task_by_pid\(|vx_r?map'
test "$SC" -le 3 && grep -cHr 'vx_new_uts' "$1" | awk -F: '$2 > 0 { print $1; }' | check_header linux/vs_cvirt.h
mount='linux/mount\.h'
grep -q linux/mount.h "$1/include/linux/fs.h" && mount=$mount'|linux/fs\.h'
grep -q linux/mount.h "$1/include/linux/namespace.h" && mount=$mount'|linux/namespace\.h'
test "$SC" -le 4 && grep -cHr 'MNT_IS_RDONLY(' "$1" | awk -F: '$2 > 0 { print $1; }' | check_header $mount
test "$SC" -le 5 && awk '/^diff/ { diffl=$5; } /^\+#include <linux\/mount/ { print diffl; }' "$2" | while read LINE; do egrep -cH $mount "$1"/${LINE#*/} | awk -F: '$2 > 1 { printf "%s includes mount.h %d times\n", $1, $2; }'; done
EOF

