
# be careful to keep the spacing in the defines - it counts

export

###################### make targets ########################
#
#   make config          prepares compilation
#   make all             makes driver, server and client
#   make test            minor test example
#   make clean           removes compile from BUILD dir
#   make distclean       removes config cache as well
#   make install         installs driver, utils, manpages
#
############################################################

#################### compile options #######################
#
# turn on to enable SSL channels
USING_SSL    = 0
# debug level
DEBUG        = 0
# root of build
BUILD        = /tmp
# will module be on an SMP machine
SMP          = 0
# where the kernel sources are
LINUXDIR     = /usr/src/linux
# which compiler to use (KCC is for the kernel modules)
CC           = gcc
KCC          = gcc
#
############################################################

#################### install options #######################
# placements
PREFIX       = $(DESTDIR)/usr/local
#
KERNELVERSION := $(shell grep UTS_RELEASE $(LINUXDIR)/include/linux/version.h|cut -f 2 -d'"')
KERNELMAJOR=$(shell echo $(KERNELVERSION) | sed -e 's/[.][^.]*$$//' | tr -d '\n')
#
MODDIR       = $(DESTDIR)/lib/modules/$(KERNELVERSION)/misc
#
ENBDVERSION := 2.4.31
#
INSTALL      = install
#
############################################################

###################### run options #########################
#
# server machine (runs enbd-server)
SERVER       = localhost
# client machine (runs enbd-client and enbd.o)
CLIENT       = localhost
# client whole device name
DEVICE       = /dev/ndb
# server builds these resources for export
EXPORT0      = /tmp/core0 /tmp/core1
EXPORT1      = /tmp/core2 /tmp/core3
# each of this many blocks
SRVSIZ       = 4096
# blocksize on client and server 1024, 2048, 4096
BLKSIZ       = 1024
# control port
PORT0        = 3033
PORT1        = 4044
# how many parallel channels (otherwise use server addr repeats)
OPTSOCK      = -n 4
#OPTSOCK     := $(SERVER) $(SERVER) $(SERVER) $(SERVER)
# session signature                        - default = random
OPTSIG       = -i "NBDabcdefNBD"
# blocksize                                - default = 1024B or highest offer
OPTBLK       = -b $(BLKSIZ)
# use raid linear or raid 0 or raid 1 on server - default = linear
OPTRAID      = -0
# timeout for first negotiate              - default = 60s
OPTTIME      = -t 120
# readonly on server side
OPTRO        = #-r
# server maintains write order until this many ms delay - default = 0ms
OPTORDER     = -w 500
# client uses checksumming protocol at startup
OPTMD5SUM    = #-m
# journalling
OPTJRNL      = #-j /tmp/nbd.log
# module readahead in blocks
RAHEAD       = 20
# module-based request aggregation (default 0)
MERGE_REQS   = 0
# module should check for partition table
CHK_PART     = 0
# module timeout seconds on daemon service
OPT_REQ_TIMEO= -p 5
# module force sync every n seconds
SYNC_INTVL   = 0
# make client asyncronous (default, no). client acks before net replies.
OPTASYNC     = #-a
# make server lock regions on accesses so multiple clients are OK.
OPTLOCK      = #-k
# make server async (default, no)
OPTSASYNC    = #-a
# server result caching
OPTRCACHE    = -h 0
# enbd module parameters
MODPARMS     = rahead=$(RAHEAD) merge_requests=$(MERGE_REQS) \
               sync_intvl=$(SYNC_INTVL) check_partitions=$(CHK_PART)
#
############################################################


ifeq ($(USING_SSL),1)
SSLSUBDIR    =
CAPATH       =$(SSLSUBDIR)/demoCA
CAFILE       =cacert.pem
SERVERCERT   =$(SSLSUBDIR)/$(SERVER)_server.pem
CLIENTCERT   =$(SSLSUBDIR)/$(CLIENT)_client.pem
OPTCAPATH    = -CApath $(BUILD)/$(CAPATH)
OPTCAFILE    = -CAfile $(BUILD)/$(CAFILE)
OPTSCERT     = -cert $(BUILD)/$(SERVERCERT)
OPTCCERT     = -cert $(BUILD)/$(CLIENTCERT)
OPTVERIFY    = -verify 1
OPTFASTCIPHER= -cipher EXP-RC4-MD5
OPTCLISSL    = $(OPTCAFILE) $(OPTCCERT) $(OPTVERIFY) #$(OPTFASTCIPHER)
OPTSRVSSL    = $(OPTCAFILE) $(OPTSCERT) $(OPTVERIFY)   
endif
OPTSIZ       = -s $(shell echo $$[ $(SRVSIZ) * ( $(BLKSIZ) / 1024 ) ])

OPTCLI       = $(SERVER):$(PORT0) $(OPTSOCK) $(OPTBLK) $(OPTSIG) $(OPTTIME) $(OPTMD5SUM) $(OPTCLISSL) $(OPT_REQ_TIMEO) $(OPTJRNL) $(OPTASYNC) -d 1 $(DEVICE)
#OPTCLI       = $(SERVER):$(PORT0) $(OPTSOCK) +$(SERVER):$(PORT0) $(OPTSOCK) $(OPTBLK) $(OPTSIG) $(OPTTIME) $(OPTMD5SUM) $(OPTCLISSL) $(OPT_REQ_TIMEO) $(OPTJRNL) $(OPTASYNC) -d 1 $(DEVICE)
#OPTCLI       = $(SERVER):$(PORT0) $(OPTSOCK) +file\$$/tmp/core:$(PORT0) $(OPTSOCK) $(OPTBLK) $(OPTSIG) $(OPTTIME) $(OPTMD5SUM) $(OPTCLISSL) $(OPT_REQ_TIMEO) $(OPTJRNL) $(OPTASYNC) -d 1 $(DEVICE)
OPTSRV       = $(PORT0) $(EXPORT0) $(OPTSIG) $(OPTTIME) $(OPTBLK) $(OPTRAID) $(OPTSRVSSL) $(OPTRO) $(OPTORDER) $(OPTLOCK) $(OPTSASYNC) $(OPTRCACHE)


VPATH       := $(shell pwd)

CFLAGS       = -D_LARGEFILE64_SOURCE=1 -D_LARGEFILE_SOURCE=1 \
               -D_GNU_SOURCE=1 -D_XOPEN_SOURCE=1 -D_FILE_OFFSET_BITS=64 \
               -Wall

ifeq ($(DEBUG),0)
  CFLAGS    += -O2
else
  CFLAGS    += -O -g
endif
ifneq ($(SMP),0)
EXTRA_CFLAGS+= -D__SMP__ -DCONFIG_X86_LOCAL_APIC
endif

DATE        := $(shell date)
LIBS         =
LDFLAGS      =
MODULES      = enbd.o enbd_bufferwr.o enbd_ioctl.o enbd_raw.o
ifeq ($(USING_SSL),1)
EXTRA_CFLAGS+= -DUSING_SSL=1
EXTRA_LIBS  += -lssl -lcrypto # -lsocket -lnsl
EXTRA_LDFLAGS=
endif

ifeq ($(ARCH),um)
SUBARCH := $(shell uname -m | sed -e 's/i.86/i386/' -e 's/sun4u/sparc64/' -e 's/arm.*/arm/' -e 's/sa110/arm/')
EXTRA_CFLAGS+=  -DUM_FASTCALL  \
		-D__arch_$(ARCH)__ \
		-DSUBARCH=\"$(SUBARCH)\" \
		-D_LARGEFILE64_SOURCE \
		-I$(LINUXDIR)/arch/$(ARCH)/include \
		-Derrno=kernel_errno \
		-I$(LINUXDIR)/arch/$(ARCH)/kernel/tt/include \
		-I$(LINUXDIR)/arch/$(ARCH)/kernel/skas/include
endif

SYSTEM      := $(shell uname -s)

.PHONY: config

all: utils module 

config: $(BUILD)/configure
	export CONFIG_SITE=$(VPATH)/conf/config.$(SYSTEM); \
	cd $(BUILD);  ./configure --srcdir=$(VPATH)/nbd \
                                  --with-kernel-srcdir=$(LINUXDIR); \
	$(MAKE) VPATH=$(VPATH)/nbd \
                CFLAGS="$(CFLAGS) \
                      -I$(BUILD) \
                      -I$(VPATH)/kernel/linux/include \
                      $(EXTRA_CFLAGS) -DDEBUG=$(DEBUG)" \
                EXTRA_LIBS="$(EXTRA_LDFLAGS) $(LIBS) $(EXTRA_LIBS)" \
                $@

nbd/configure: nbd/configure.in
	autoconf $< > $@; chmod +x $@

$(BUILD)/configure: nbd/configure.in
	mkdir -p $(BUILD)
	autoconf $< > $@; chmod +x $@

$(BUILD)/Makefile: $(BUILD)/configure
	$(MAKE) config

utils: $(BUILD)/Makefile
	$(MAKE) -C $(BUILD) VPATH=$(VPATH)/nbd \
                            CFLAGS="$(CFLAGS) \
                                  -I$(BUILD) \
                                  -I$(VPATH)/kernel/linux/include \
                                  -I$(LINUXDIR)/include \
                                    $(EXTRA_CFLAGS) \
                                  -DDEBUG=$(DEBUG)" \
                            EXTRA_LIBS="$(EXTRA_LDFLAGS) \
                                        $(LIBS) $(EXTRA_LIBS)" 


module:
	test $(KERNELMAJOR) = 2.6 && { echo please apply kernel patch instead; exit 0; }; \
	for file in $(MODULES); do \
	$(MAKE) -C $(BUILD) \
                -f $(VPATH)/kernel/linux/drivers/block/Makefile \
                   VPATH=$(VPATH)/kernel/linux/drivers/block \
                   CONFIG_BLK_DEV_NBD=m \
                   CC="$(KCC)" \
                   EXTRA_CFLAGS="$(EXTRA_CFLAGS) \
                               -D__KERNEL__ \
                               -DMODULE \
                               -DDEBUG=$(DEBUG) \
                               -DCONFIG_ENBD=m \
                               -DENBD_VERSION='\"$(ENBDVERSION) Date: $(DATE)\"' \
                               -I$(VPATH)/kernel/linux/include \
                               -I$(LINUXDIR)/include" \
                   TOPDIR=$(LINUXDIR) \
                   $$file ; \
        done

distclean: clean
	$(MAKE) -C $(BUILD) VPATH=$(VPATH)/nbd $@

clean: utils-clean module-clean

utils-clean:
	$(MAKE) -C $(BUILD) VPATH=$(VPATH)/nbd clean

module-clean:
	cd $(BUILD) && rm -f enbd.o .enbd.o.flags enbd_*.o .enbd_*.o.flags 

install: utils-install module-install

utils-install:
	$(MAKE) -C $(BUILD) VPATH=$(VPATH)/nbd PREFIX="$(PREFIX)" install

module-install:
	mkdir -p $(MODDIR)
	for m in $(MODULES); do \
	        $(INSTALL) $(BUILD)/$$m $(MODDIR)/$$m; \
        done

devices:
	cd /dev; $(VPATH)/nbd/scripts/MAKEDEV $(DEVICE)

FILES := $(shell cat $(VPATH)/FILES)


IS_SRV:=$(shell [ localhost = $(SERVER) -o `hostname | sed -e 's/.*[.]//'` = $(SERVER) ] && echo yes || echo no)
IS_CLI:=$(shell [ localhost = $(CLIENT) -o `hostname | sed -e 's/.*[.]//'` = $(CLIENT) ] && echo yes || echo no)

RSYNC := rsync

ifeq ($(IS_SRV),yes)
  # CMI is interactive, CMD is not
  SRVCMD:= sh -c 
  SRVCMI:= sh -c
  SRVCPY:= cp -a
  SRVYPC:= cp -a
else
  SRVCMD:= ssh -n $(SERVER)
  SRVCMI:= ssh $(SERVER)
  define SRVCPY
    copy(){ \
      $(RSYNC) -uav --rsh=ssh "$$1" "$(SERVER):$$2" ; \
    } ; \
    copy 
  endef
  define SRVYPC
    copy(){ \
      $(RSYNC) -uav --rsh=ssh "$(SERVER):$$1" "$$2" ; \
    } ; \
    copy 
  endef
endif
ifeq ($(IS_CLI),yes)
  # CMI is interactive, CMD is not
  CLICMD:= sh -c 
  CLICMI:= sh -c
  CLICPY:= $(RSYNC) -uav --rsh=ssh 
  CLIYPC:= $(RSYNC) -uav --rsh=ssh
else
  CLICMD:= ssh -n $(CLIENT)
  CLICMI:= ssh $(CLIENT)
  define CLICPY
    copy(){ \
      $(RSYNC) -uav --rsh=ssh "$$1" "$(CLIENT):$$2" ; \
    } ; \
    copy 
  endef
  define CLIYPC
    copy(){ \
      $(RSYNC) -uav --rsh=ssh "$(CLIENT):$$1" "$$2" ; \
    } ; \
    copy 
  endef
endif


notest: test-notice test-server test-delay test-client
test: test-notice test-server test-delay test-client test-device
	echo done

test-notice:
	-@echo "server:$(SERVER) <- $(PORT0) -> client:$(CLIENT)"
	-@echo "server:$(SERVER) <- $(PORT1) -> client:$(CLIENT)"

ifeq ($(USING_SSL),1)
install-server-certs:
	$(MAKE) -C $(BUILD) -f $(VPATH)/ssl/Makefile VPATH=$(VPATH)/ssl $@
install-client-certs:
	$(MAKE) -C $(BUILD) -f $(VPATH)/ssl/Makefile VPATH=$(VPATH)/ssl $@
install-master-certs:
	$(MAKE) -C $(BUILD) -f $(VPATH)/ssl/Makefile VPATH=$(VPATH)/ssl $@
install-all-certs:
	$(MAKE) -C $(BUILD) -f $(VPATH)/ssl/Makefile VPATH=$(VPATH)/ssl $@
install-clean:
	$(MAKE) -C $(BUILD) -f $(VPATH)/ssl/Makefile VPATH=$(VPATH)/ssl $@
else
install-server-certs:
install-client-certs:
install-master-certs:
install-all-certs:
install-clean:
endif 

IS_ROOT := $(shell [ `id -u` = 0 ] && echo yes || echo no)
ifeq ($(IS_ROOT),yes)
SUDO := 
else
SUDO := sudo
endif


kill-server:
	-echo; echo; \
	 stty -echo </dev/tty ; \
	 $(SRVCMI) "$(SUDO) echo kill enbd-server" ; \
	 stty echo </dev/tty ;  \
	 $(SRVCMD) "$(SUDO) killall enbd-server; sleep 1; $(SUDO) killall -9 enbd-server" 

test-server: install-server-certs kill-server
	-echo; echo; \
	 stty -echo </dev/tty ; \
	 $(SRVCMI) "$(SUDO) echo enbd-server" ; \
	 stty echo </dev/tty ;  \
	 $(SRVCPY) $(BUILD)/enbd-server $(BUILD)/  ; \
	 for i in $(EXPORT0) $(EXPORT1); do $(SRVCMD) "test -s $$i || dd if=/dev/zero  bs=$(BLKSIZ) count=$(SRVSIZ) >$$i" ; done ; \
	 $(SRVCMD) "$(SUDO) nice -19 $(BUILD)/enbd-server $(OPTSRV) ; pstree -p | grep enbd-server; sleep 300" & 

test-delay:
	-@echo -n delay 5s ..; sleep 5 ; echo .

test-device:
	$(CLICMD) "$(SUDO) $(BUILD)/enbd-test $(DEVICE) -s 1M -i 1:2:3:4:5"

kill-client:
	-echo; echo; \
	 stty -echo </dev/tty ; \
	 $(CLICMI) "$(SUDO) echo kill enbd-client"  ; \
	 stty echo </dev/tty ; \
	 $(CLICMD) "$(SUDO) killall -USR1 enbd-client ; sleep 1; $(SUDO) killall -9 enbd-client; sleep 4; #$(SUDO) /sbin/rmmod enbd" 

test-client: install-client-certs kill-client
	-echo; echo; \
	 stty -echo </dev/tty ; \
	 $(CLICMI) "$(SUDO) echo enbd-client"  ; \
	 stty echo </dev/tty ; \
	 $(CLICPY) $(BUILD)/enbd.o  $(BUILD)/ ; \
	 $(CLICPY) $(BUILD)/enbd-client $(BUILD)/ ; \
	 $(CLICPY) $(VPATH)/nbd/scripts/MAKEDEV $(BUILD)/ ; \
	 $(CLICMD) "cd /dev; $(SUDO) $(BUILD)/MAKEDEV $(DEVICE)" ; \
	 $(CLICMD) "$(SUDO) /sbin/insmod $(BUILD)/enbd.o $(MODPARMS) ; $(SUDO) /sbin/insmod $(BUILD)/enbd_ioctl.o; $(SUDO) /sbin/insmod $(BUILD)/enbd_bufferwr.o; /sbin/insmod $(BUILD)/enbd_raw.o" || true  ; \
	 $(CLICMD) "$(SUDO) nice -19 $(BUILD)/enbd-client $(OPTCLI) ; pstree -p | grep enbd-client; sleep 10" 

test-reconnect:
	 $(CLICMD) "time dd if=/dev/zero of=$(DEVICE) bs=$(BLKSIZ) count=5"
	 $(SRVCMD) "$(SUDO) kill `pstree -p | grep enbd-server | head -1 | tr -d 'a-zA-Z-|()'`"
	 $(CLICMD) "time dd if=/dev/zero of=$(DEVICE) bs=$(BLKSIZ) count=5"
	 $(SRVCMD) "$(SUDO) nice -19 $(BUILD)/enbd-server $(OPTSRV) ; pstree -p | grep enbd-server; sleep 300" & 

test-regress:
	-@$(CLICMD) "time dd if=/dev/zero of=$(DEVICE) bs=1024 " </dev/null & 
	 $(SRVCMD) "sleep 5 ; $(SUDO) kill `ps aux | grep enbd-server | grep -v grep | awk '{ print $$2 }' | tail -1`" &


rescue: rescue-server rescue-client

rescue-server:
	-@echo ; echo ; \
	 stty -echo </dev/tty ; \
	 $(SRVCMI) "$(SUDO) echo enbd-server-rescue" ; \
	 stty echo </dev/tty ; \
	 $(SRVCMD) "$(SUDO) killall enbd-server; sleep 1; $(SUDO) killall -9 enbd-server" 

rescue-client:
	-@echo ; echo ; \
	 stty -echo </dev/tty ; \
	 $(CLICMI) "$(SUDO) echo enbd-client-rescue"  ; \
	 stty echo </dev/tty ; \
	 $(CLICMD) "$(SUDO) killall -USR1 enbd-client"  ; \
	 $(CLICMD) "$(SUDO) killall enbd-client"  ; \
	 $(CLICMD) "sleep 15; $(SUDO) killall -9 enbd-client"  ; \
	 #$(CLICMD) "$(SUDO) killall -STOP watchdog && $(SUDO) kill -STOP `cat /var/run/watchdog.pid` || $(SUDO) killall -STOP watchdog"  ; \
	 $(CLICMD) "sync >/dev/null"  & 
	 #$(CLICMD) "test -s /var/run/watchdog.pid && $(SUDO) kill -CONT `cat /var/run/watchdog.pid` || $(SUDO) killall -CONT watchdog"  ; \
	 #$(CLICMD) "sleep 2; /sbin/lsmod | grep -q nbd && ( $(SUDO) /sbin/rmmod nbd || $(SUDO) /sbin/shutdown -r now ) ; sleep 2"  &

KERNEL_PATCH := kernel/patches/enbd-$(shell echo $(KERNELVERSION) | sed -e 's/-.*//').pat

kernel_patches:
	$(MAKE) $(KERNEL_PATCH) > /tmp/`basename $(KERNEL_PATCH)` 

.PHONY: $(KERNEL_PATCH)

$(KERNEL_PATCH): 
	kernel_patch=$(KERNEL_PATCH); \
        if [ ! -e $$kernel_patch ]; then exit 1; fi ; \
        pwd=`pwd`; \
	cd $(LINUXDIR)/.. ; \
	diffstat $$pwd/$$kernel_patch | awk '{ if ( $$2 == "|")  print $$1 }' | while read file; do \
	    if [ -e `basename $(LINUXDIR)`/$$file.pre-enbd ]; then \
	      diff -u `basename $(LINUXDIR)`/$$file{.pre-enbd,}; \
	    else \
	      diff -u --label=$(LINUXDIR)/$$file.pre-enbd - $(LINUXDIR)/$$file </dev/null; \
	    fi; \
	  done ; true


