#
#  Makefile
#
#  Written by Jari Ruusu, February 1 2004
#
#  Copyright 2001,2002,2003,2004 by Jari Ruusu.
#  Redistribution of this file is permitted under the GNU Public License.
#
#  To compile and install, use commands:  make clean; make
#  This Makefile tries to locate running kernel source directory and
#  steal definitions from kernel Makefile. Note: kernel must be properly
#  configured and compiled in order for this to work.
#  You can override the kernel source directory by defining LINUX_SOURCE
#  like this:  make LINUX_SOURCE=/usr/src/linux-2.2.20aa1
#
#  Both LINUX_SOURCE and KBUILD_OUTPUT must be defined when
#  compiling for 2.6.x kernel with separate object directory.
#

KR:=$(shell uname -r)
ifdef LINUX_SOURCE
	LS:=$(LINUX_SOURCE)
else
	LS:=$(shell  if [ -f /lib/modules/$(KR)/build/include/linux/version.h ]; then echo /lib/modules/$(KR)/build; \
		else if [ -f /usr/src/linux/include/linux/version.h ]; then echo /usr/src/linux; \
		else if [ -f /usr/src/linux-$(KR)/include/linux/version.h ]; then echo /usr/src/linux-$(KR); \
		else if [ -f /usr/src/kernel-source-$(KR)/include/linux/version.h ]; then echo /usr/src/kernel-source-$(KR); \
		else echo unable-to-guess-source-dir; fi; fi; fi; fi)
endif
TD:=$(shell pwd)

all:
ifeq ($(LS),unable-to-guess-source-dir)
	@echo "Unable to guess linux kernel source directory. Please specify"
	@echo "directory like this:  make LINUX_SOURCE=/usr/src/linux-2.2.20aa1"
	@exit 1
endif
	cd $(LS) && make SUBDIRS=$(TD) modules Q='@cd $(TD) && if [ "$$@" = "$(TD)" ]; then make modules; fi; # '

PATCHNAME:=loop.c-$(VERSION).$(PATCHLEVEL).diff
ORIGNAME:=loop.c-$(VERSION).$(PATCHLEVEL).original
PREPATCHED:=loop.c-$(VERSION).$(PATCHLEVEL).patched

EF:=
LF:=-r
CP1:=
OD1:=$(LS)
PP1:=
VM1:=
ifeq ($(VERSION).$(PATCHLEVEL),2.0)
	# Use optimized assembler implementation if target is Pentium or better x86 processor
	PENTIUM_ASM:=$(shell if grep -q -s "define CONFIG_M[56]86" $(LS)/include/linux/autoconf.h; then echo y; fi)
	# kernel v2.0 doesn't have u_int32_t and u_int64_t
	EF += -Du_int32_t=__u32 -Du_int64_t=__u64
ifndef KERNELRELEASE
	# some older 2.0 kernels don't define KERNELRELEASE
	KERNELRELEASE:=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)
endif
endif
ifeq ($(VERSION).$(PATCHLEVEL),2.2)
	# Use optimized assembler implementation if target is Pentium or better x86 processor
	PENTIUM_ASM:=$(shell if grep -q -s "define CONFIG_M[56]86" $(LS)/include/linux/autoconf.h; then echo y; fi)
endif
ifeq ($(VERSION).$(PATCHLEVEL),2.4)
	EF += $(kbuild_2_4_nostdinc)
	# Use optimized assembler implementation if target is Pentium or better x86 processor
	PENTIUM_ASM:=$(shell if grep -q -s "define CONFIG_X86 1" $(LS)/include/linux/autoconf.h; then if ! grep -q -s "define CONFIG_X86_64" $(LS)/include/linux/autoconf.h; then if ! grep -q -s "define CONFIG_M[34]86" $(LS)/include/linux/autoconf.h; then echo y; fi; fi; fi)
	# some older 2.4 kernels don't have struct block_device_operations.owner
	EF += $(shell if ! grep -q -s "owner.*THIS_MODULE" $(LS)/drivers/block/loop.c; then echo "-DNO_BLOCK_DEVICE_OPERATIONS_OWNER"; fi)
	# some older 2.4 kernels don't have reparent_to_init()
	EF += $(shell if ! grep -q -s "extern void reparent_to_init" $(LS)/include/linux/sched.h; then echo "-DNO_REPARENT_TO_INIT"; fi)
	# some 2.4 kernels don't have struct task_struct.sigmask_lock
	EF += $(shell if ! grep -q -s "spinlock_t sigmask_lock" $(LS)/include/linux/sched.h; then if grep -q -s 'struct sighand_struct \*sighand;' $(LS)/include/linux/sched.h; then echo '-DNO_TASK_STRUCT_SIGMASK_LOCK=1'; else echo '-DNO_TASK_STRUCT_SIGMASK_LOCK=2'; fi; fi)
endif
ifeq ($(shell if [ "$(VERSION)$(PATCHLEVEL)0" -ge 260 ]; then echo y; fi),y)
	EF += $(CFLAGS_MODULE) $(NOSTDINC_FLAGS)
	LF:=$(LDFLAGS) $(EXTRA_LDFLAGS) $(LDFLAGS_MODULE)
ifdef KBUILD_OUTPUT
	CP1:=cd $(KBUILD_OUTPUT) &&
	OD1:=$(KBUILD_OUTPUT)
else
	CP1:=cd $(LS) &&
endif
	PP1:=$(TD)/
	VM1:=k
	# Use optimized assembler implementation if target is Pentium or better x86 processor
	PENTIUM_ASM:=$(shell if grep -q -s "define CONFIG_X86 1" $(OD1)/include/linux/autoconf.h; then if ! grep -q -s "define CONFIG_X86_64" $(OD1)/include/linux/autoconf.h; then if ! grep -q -s "define CONFIG_M[34]86" $(OD1)/include/linux/autoconf.h; then if ! grep -q -s "define CONFIG_CPU_[34]86" $(OD1)/include/linux/autoconf.h; then echo y; fi; fi; fi; fi)
	# some 2.6 kernels have different block driver interface
	EF += $(shell if grep -q -s "^static int lo_ioctl.struct block_device " $(LS)/drivers/block/loop.c; then echo "-DNEW_BLOCK_DRIVER_INTERFACE"; fi)
	# some older 2.6 kernels have different request_module interface
	EF += $(shell if ! grep -q -s "request_module.*block-major-.*MAJOR.*MINOR" $(LS)/drivers/block/genhd.c; then echo "-DOLD_REQUEST_MODULE_INTERFACE"; fi)
endif

AES_OBJ_CODE:=aes.o
MD5_OBJ_CODE:=md5.o
ifeq ($(PENTIUM_ASM),y)
	AES_OBJ_CODE:=aes-i586.o
	MD5_OBJ_CODE:=md5-i586.o
	EF += -DPENTIUM_ASM
endif

# check if depmod supports -F and -b options
ifeq ($(shell if [ "$(VERSION)$(PATCHLEVEL)0" -ge 260 ]; then echo y; fi),y)
	DMOK:=y
else
	DMOK:=$(shell if [ `/sbin/insmod -V 2>&1 | head -1 | awk '/^insmod version /{split($$3, a, /\./); printf "%d%03d%03d\n", a[1], a[2], a[3];}'`0 -ge 20020020 ]; then echo y; fi)
endif
ifndef DEPMOD
	DEPMOD:=/sbin/depmod
endif

# check if kernel source has System.map
SYSM:=$(shell if [ -r $(OD1)/System.map ]; then echo y; fi)

RUNDM:=
DMOPTS:=
ifeq ($(DMOK),y)
ifneq "$(strip $(INSTALL_MOD_PATH))" ""
	DMOPTS += -b $(INSTALL_MOD_PATH)
endif
ifeq ($(SYSM),y)
	RUNDM:=y
	DMOPTS += -F $(OD1)/System.map $(KERNELRELEASE)
endif
endif
ifeq ($(KERNELRELEASE),$(KR))
ifeq "$(strip $(INSTALL_MOD_PATH))" ""
	RUNDM:=y
endif
endif

modules: clean loop.$(VM1)o
	mkdir -p $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)/block
	cp -p loop.$(VM1)o $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)/block
ifeq ($(shell if [ "$(VERSION)$(PATCHLEVEL)0" -ge 240 ]; then echo y; fi),y)
	rm -f $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)/kernel/drivers/block/loop.{,k}o
endif
ifeq ($(RUNDM),y)
	$(DEPMOD) -a $(DMOPTS)
endif
	sync
	@echo "Currently running kernel is" $(KR)
	@echo "Module was built for kernel" $(KERNELRELEASE)
ifneq ($(KERNELRELEASE),$(KR))
	@echo "WARNING - THIS MODULE WILL NOT WORK WITH CURRENTLY RUNNING KERNEL"
endif
loop.$(VM1)o: patched-loop.o glue.o $(AES_OBJ_CODE) $(MD5_OBJ_CODE)
	$(LD) $(LF) patched-loop.o glue.o $(AES_OBJ_CODE) $(MD5_OBJ_CODE) -o loop.o
ifneq "$(VM1)" ""
	$(CP1) ./scripts/modpost vmlinux $(PP1)loop.o >/dev/null 2>&1
	$(CP1) $(CC) $(CFLAGS) $(EF) -c $(PP1)loop.mod.c -o $(PP1)loop.mod.o
	$(LD) $(LF) loop.o loop.mod.o -o loop.$(VM1)o
	rm -f loop.o loop.mod.[co]
endif
patched-loop.o:
	rm -f patched-loop.[ch]
ifeq ($(shell if [ "$(VERSION)$(PATCHLEVEL)0" -ge 240 ]; then echo y; fi),y)
	cp $(PREPATCHED) patched-loop.c
else
	cp $(LS)/drivers/block/loop.c patched-loop.c
	@echo "*** BEGINNING OF SECTION TO IGNORE PATCH ERRORS ***"
	patch -p0 -l -f --dry-run < $(PATCHNAME) || cp $(ORIGNAME) patched-loop.c
	@echo "*** END OF SECTION TO IGNORE PATCH ERRORS ***"
	patch -p0 -l -f < $(PATCHNAME)
endif
	$(CP1) $(CC) $(CFLAGS) $(EF) -DKBUILD_BASENAME=patched_loop -DKBUILD_MODNAME=loop -DEXPORT_SYMTAB -c $(PP1)patched-loop.c -o $(PP1)patched-loop.o
glue.o: glue.c aes.h md5.h
	$(CP1) $(CC) $(CFLAGS) $(EF) -DKBUILD_BASENAME=glue -DKBUILD_MODNAME=loop -c $(PP1)glue.c -o $(PP1)glue.o
aes.o: aes.c aes.h
	$(CP1) $(CC) $(CFLAGS) $(EF) -DKBUILD_BASENAME=aes -DKBUILD_MODNAME=loop -c $(PP1)aes.c -o $(PP1)aes.o
aes-i586.o: aes-i586.S
	$(CP1) $(CC) $(AFLAGS) -c $(PP1)aes-i586.S -o $(PP1)aes-i586.o
md5.o: md5.c md5.h
	$(CP1) $(CC) $(CFLAGS) $(EF) -DKBUILD_BASENAME=md5 -DKBUILD_MODNAME=loop -c $(PP1)md5.c -o $(PP1)md5.o
md5-i586.o: md5-i586.S
	$(CP1) $(CC) $(AFLAGS) -c $(PP1)md5-i586.S -o $(PP1)md5-i586.o

clean:
	rm -f *.o *.ko *.orig *.rej *.mod.c patched-loop.[ch] test-file[1234]
	rm -f -r test-dir1

# tests can be run after loop.o and losetup are compiled and installed
TLD:=/dev/loop7
TEST_GPG_TYPES:=yes
TEST_UNHASHED_AES_TYPES:=yes
TEST_PARTITION_TO_TRASH:=none
tests:
	dd if=/dev/zero of=test-file1 bs=1024 count=33
	cp test-file1 test-file3
	echo 09876543210987654321 | /sbin/losetup -p 0 -e AES128 $(TLD) test-file3
	dd if=/dev/zero of=$(TLD) bs=1024 count=33 conv=notrunc
	/sbin/losetup -d $(TLD)
	make test-part2 CT=XOR    ITER=0  HF=sha256 GK= MD=d28220a1737763260f6e0109f141814a TF=test-file1 PSW=12345678901234567890
	make test-part2 CT=NONE   ITER=0  HF=sha256 GK= MD=0b08ceeb8b609b0885471ba25a23f5a5 TF=test-file1 PSW=12345678901234567890
	make test-part2 CT=AES128 ITER=0  HF=sha256 GK= MD=7c1cfd4fdd0d7cc847dd0942a2d48e48 TF=test-file1 PSW=12345678901234567890
	make test-part2 CT=AES192 ITER=0  HF=sha384 GK= MD=51c91bcc04ee2a4ca00310b519b3228c TF=test-file1 PSW=12345678901234567890
	make test-part2 CT=AES256 ITER=0  HF=sha512 GK= MD=1bf92ee337b653cdb32838047dec00fc TF=test-file1 PSW=12345678901234567890
	make test-part2 CT=AES256 ITER=0  HF=rmd160 GK= MD=c85eb59da18876ae71ebd838675c6ef4 TF=test-file1 PSW=12345678901234567890
	make test-part2 CT=AES256 ITER=10 HF=sha512 GK= MD=dadad48a6d3d9b9914199626ed7b710c TF=test-file1 PSW=12345678901234567890
ifeq ($(TEST_GPG_TYPES),yes)
	mkdir test-dir1
	make test-part2 CT=AES128 ITER=0 HF=sha256 GK="-K gpgkey1.asc -G test-dir1" MD=fa5c9a84bc8f6257830c3cbe60294c69 TF=test-file1 PSW=12345678901234567890
	make test-part2 CT=AES192 ITER=0 HF=sha384 GK="-K gpgkey1.asc -G test-dir1" MD=ddec9544a36100156aef353ec2bf9740 TF=test-file1 PSW=12345678901234567890
	make test-part2 CT=AES256 ITER=0 HF=sha512 GK="-K gpgkey1.asc -G test-dir1" MD=cb38b603f96f0deac1891d423983d69c TF=test-file1 PSW=12345678901234567890
	make test-part2 CT=AES128 ITER=0 HF=sha256 GK="-K gpgkey2.asc -G test-dir1" MD=f9825b79873f5c439ae9371c1a929a6c TF=test-file1 PSW=12345678901234567890
	make test-part2 CT=AES192 ITER=0 HF=sha384 GK="-K gpgkey2.asc -G test-dir1" MD=489991b779213f60219f09c575c08247 TF=test-file1 PSW=12345678901234567890
	make test-part2 CT=AES256 ITER=0 HF=sha512 GK="-K gpgkey2.asc -G test-dir1" MD=2a1d0d3fce83fbe5f3edcca95fbab3b7 TF=test-file1 PSW=12345678901234567890
endif
ifeq ($(TEST_UNHASHED_AES_TYPES),yes)
	make test-part2 CT=AES ITER=0 HF=unhashed1 GK= MD=293b09053055af7ca5235dc6a5bc0b74 TF=test-file1 PSW=1234567890123456789012345678901
	make test-part2 CT=AES ITER=0 HF=unhashed1 GK= MD=6b157917570250ef4370bf9acae49279 TF=test-file1 PSW=12345678901234567890123456789012
	make test-part2 CT=AES ITER=0 HF=unhashed1 GK= MD=6b157917570250ef4370bf9acae49279 TF=test-file1 PSW=123456789012345678901234567890123456789012
	make test-part2 CT=AES ITER=0 HF=unhashed1 GK= MD=e12fd55fbae9fc0e03517593e253e239 TF=test-file1 PSW=1234567890123456789012345678901234567890123
endif
ifneq ($(TEST_PARTITION_TO_TRASH),none)
	make test-part2 CT=AES128 ITER=0 HF=sha256 GK= MD=7c1cfd4fdd0d7cc847dd0942a2d48e48 TF=$(TEST_PARTITION_TO_TRASH) PSW=12345678901234567890
	make test-part2 CT=NONE   ITER=0 HF=sha256 GK= MD=0b08ceeb8b609b0885471ba25a23f5a5 TF=$(TEST_PARTITION_TO_TRASH) PSW=12345678901234567890
endif
	rm -f -r test-file[1234] test-dir1
	@echo "*** Test results ok ***"

test-part2:
	echo $(PSW) | /sbin/losetup -p 0 -e $(CT) -H $(HF) -C $(ITER) $(GK) $(TLD) $(TF)
	dd if=test-file3 of=$(TLD) bs=1024 count=33 conv=notrunc
	/sbin/losetup -d $(TLD)
	echo $(PSW) | /sbin/losetup -p 0 -e $(CT) -H $(HF) -C $(ITER) $(GK) $(TLD) $(TF)
	dd if=$(TLD) of=test-file4 bs=33792 count=1
	/sbin/losetup -d $(TLD)
ifneq ($(TF),test-file1)
	dd if=$(TF) of=test-file1 bs=33792 count=1
endif
	md5sum test-file1 >test-file2
	echo "$(MD)  test-file1" | cmp test-file2 -
	cmp test-file3 test-file4

.PHONY: all clean tests test-part2
