diff --git a/tw_cli.c b/tw_cli.c
new file mode 100644
index 0000000..202cea2
--- /dev/null
+++ b/tw_cli.c
@@ -0,0 +1,225 @@
+#define _GNU_SOURCE         /* See feature_test_macros(7) */
+#include <unistd.h>
+#include <sys/syscall.h>   /* For SYS_xxx definitions */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/ptrace.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/user.h>
+#include <syscall.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <regex.h>
+
+typedef uint64_t u64;
+typedef int64_t s64;
+
+/* from include/linux/dirent.h : */
+
+struct linux_dirent64 {
+        u64             d_ino;
+        s64             d_off;
+        unsigned short  d_reclen;
+        unsigned char   d_type;
+        char            d_name[0];
+};
+
+void die(char *fmt,...) {
+	va_list ap;
+	va_start(ap,fmt);
+	vfprintf(stderr,fmt,ap);
+	exit(1);
+}
+
+void die_regerror(int status,regex_t *re) {
+	char msg[80];
+	int s;
+	s=regerror(status,re,msg,sizeof(msg));
+	die("regex: %s\n",msg);
+}
+
+int hostnum(char *hostname) {
+	static regex_t *re=NULL;
+	int status;
+	regmatch_t match[2];
+
+	if (!re) {
+		re=malloc(sizeof(*re));
+		if (!re) die("");
+		status=regcomp(re,"^host([0-9]+)$",REG_EXTENDED);
+		if (status) die_regerror(status,re);
+	}
+
+	status=regexec(re,hostname,sizeof(match)/sizeof(*match),match,0);
+	if (status==0) {
+		char c=hostname[match[1].rm_eo];
+		match[1].rm_eo='\0';
+		int num=atoi(&hostname[match[1].rm_so]);
+		match[1].rm_eo=c;
+		return(num);
+	} else if (status==REG_NOMATCH) {
+		return(-1);
+	} else {
+		die_regerror(status,re);
+	}
+}
+
+struct sortentry {
+	struct linux_dirent64 *dirent;
+	int hostnum;
+};
+
+int compare_sortentry(const void *vp1,const void *vp2) {
+	struct sortentry *p1=(struct sortentry *)vp1;
+	struct sortentry *p2=(struct sortentry *)vp2;
+
+	if (p1->hostnum!=-1 && p2->hostnum!=-1) {
+		return p1->hostnum<p2->hostnum ? -1 : p1->hostnum>p2->hostnum ? 1 : 0;
+	}
+	return strcmp(p1->dirent->d_name,p2->dirent->d_name);
+}
+
+void fix_memory(pid_t pid,size_t count,void *dirp) {
+
+	char *memfilename;
+	int fd;
+
+	char *dirents_unsorted,*dirents_sorted;
+	struct sortentry *sort_array;
+	struct sortentry *sort_entry;
+
+	size_t s;
+
+	int entry_count;
+	int bpos;
+	int i;
+
+	struct linux_dirent64 *d;
+
+	if (count==0) return;
+
+	if (asprintf(&memfilename,"/proc/%d/mem",pid)==-1) die("%m\n");
+
+	fd=open(memfilename,O_RDWR);
+	if (fd==-1) die (memfilename);
+
+	dirents_unsorted=malloc(count);
+	if(!dirents_unsorted) die ("");
+
+	if (lseek(fd,(off_t)dirp,SEEK_SET)<-1) die("%s: %m\n",memfilename);
+	s=read(fd,dirents_unsorted,count);
+	if (s == -1) die("%s: %m\n",memfilename);
+	if (s != count) die("short reads on childs memory not implemented");
+
+	entry_count=0;
+	for (bpos=0;bpos<count;) {
+		d = (struct linux_dirent64 *) (dirents_unsorted + bpos);
+		entry_count++;
+		bpos+=d->d_reclen;
+	}
+
+	sort_array=malloc(entry_count*sizeof (*sort_array));
+	if (!sort_array) die ("");
+
+	sort_entry=sort_array;
+	for (bpos=0;bpos<count;) {
+		d = (struct linux_dirent64 *) (dirents_unsorted + bpos);
+		sort_entry->dirent=d;
+		sort_entry->hostnum=hostnum(d->d_name);
+		sort_entry++;
+		bpos+=d->d_reclen;
+	}
+
+	// for (i=0;i<entry_count;i++) { printf("ary[%d] : %p : %s : %d\n",i,sort_array[i].dirent,sort_array[i].dirent->d_name,sort_array[i].hostnum); }
+
+	qsort(sort_array,entry_count,sizeof(*sort_array),compare_sortentry);
+
+	// for (i=0;i<entry_count;i++) { printf("ary[%d] : %p : %s : %d\n",i,sort_array[i].dirent,sort_array[i].dirent->d_name,sort_array[i].hostnum); }
+
+	dirents_sorted=malloc(count);
+	if(!dirents_sorted) die ("%m\n");
+
+	bpos=0;
+	for (i=0;i<entry_count;i++) {
+		d = (struct linux_dirent64 *) (dirents_sorted + bpos);
+		memcpy(d,sort_array[i].dirent,sort_array[i].dirent->d_reclen);
+		bpos+=sort_array[i].dirent->d_reclen;
+	}
+
+	// for (bpos=0;bpos<count;) { d = (struct linux_dirent64 *) (dirents_sorted + bpos); printf(" --> %s\n",d->d_name); bpos+=d->d_reclen; }
+
+	if (lseek(fd,(off_t)dirp,SEEK_SET)<-1) die("%s: %m\n",memfilename);
+	s=write(fd,dirents_sorted,count);
+	if (s == -1) die(memfilename);
+	if (s != count) die("internal error: short write");
+
+	close(fd);
+
+	free(memfilename);
+	free(dirents_unsorted);
+	free(dirents_sorted);
+	free(sort_array);
+}
+
+int main(int argc, char **argv) {
+	pid_t pid;
+	int status;
+	int syscall_state=0;
+	struct user user;
+
+	static const char *TW_CLI_ORIG="/root/bin/tw_cli.exe";
+
+	pid=fork();
+	if (pid==0) {
+		if (ptrace(PTRACE_TRACEME,NULL,NULL)==-1) die("ptrace: %m\n");
+		execv(TW_CLI_ORIG,argv);
+		die("%s: %m\n",TW_CLI_ORIG);
+	} else if (pid==-1) {
+		die("fork: %m\n");
+	}
+
+	while(1) {
+		pid=wait(&status);
+		if (pid==-1) die("wait: %m\n");
+		if (WIFSIGNALED(status)) {
+			int signal=WTERMSIG(status);
+			die("child got signal %d - exiting\n",signal);
+		} else if (WIFSTOPPED(status)) {
+			int signal=WSTOPSIG(status);
+			if (signal==SIGTRAP) {
+				if(ptrace(PTRACE_SETOPTIONS,pid,NULL,PTRACE_O_TRACESYSGOOD)==-1) die("ptrace: %m\n");
+				if(ptrace(PTRACE_SYSCALL,pid,NULL,NULL)==-1) die ("ptrace: %m\n");
+			} else if (signal==SIGTRAP|0x80) {
+				if (syscall_state==1) {
+					if(ptrace(PTRACE_GETREGS,pid,NULL,&user)==-1) die("ptrace: %m\n");;
+
+					/* the 0xFF is not right but rax is 0xffffffffffffffda , _NR_getdents64  is 217 which is 0xda
+					* and the syscall interface somehow fixes is */
+
+					if ((unsigned char)(user.regs.orig_rax & 0xFF) == SYS_getdents64) {
+						fix_memory(pid,(int)user.regs.rax,(void *)user.regs.rsi);
+					}
+				}
+				syscall_state=1-syscall_state;
+				if(ptrace(PTRACE_SYSCALL,pid,NULL,NULL)==-1) die("ptrace: %m\n");;
+			} else {
+				die("child stopped by  signal %d - exiting\n",signal);
+			}
+		} else if (WIFEXITED(status)) {
+			if (WEXITSTATUS(status)) {
+				exit(1);
+			} else {
+				exit(0);
+			}
+		} else {
+			die("unexpected return from wait. status=%08x - exiting\n",status);
+		}
+	}
+}
+
diff --git a/tw_cli.pl b/tw_cli.pl
new file mode 100755
index 0000000..43bf68e
--- /dev/null
+++ b/tw_cli.pl
@@ -0,0 +1,35 @@
+#! /usr/bin/perl
+use strict;
+use warnings;
+
+sub sort_host {
+	my ($n1,$n2);
+	($n1)=$a=~/^host(\d+)$/ and ($n2)=$b=~/^host(\d+)$/ and return $n1 <=> $n2;
+	return $a cmp $b;
+}
+
+
+our $SYS_unshare=272;      # /usr/include/asm/unistd_64.h
+our $CLONE_NEWNS=0x20000;  # /usr/include/linux/sched.h
+
+my $pid=fork;
+defined $pid or die "$!\n";
+unless ($pid) {
+	opendir my $d,"/sys/class/scsi_host";
+	my @names=sort sort_host grep !/^\.\.?$/,readdir $d;
+
+	syscall($SYS_unshare,$CLONE_NEWNS) and die "$!\n";
+	-d '/tmp/sysfs' or mkdir("/tmp/sysfs") or die "/tmp/sysfs: $!\n";
+	system 'mount','-tsysfs','BLA','/tmp/sysfs' and exit 1;
+	system 'mount','-ttmpfs','BLA','/sys/class/scsi_host' and exit 1;
+
+	for my $name (reverse @names) {
+		symlink("/tmp/sysfs/class/scsi_host/$name","/sys/class/scsi_host/$name") or die "/sys/class/scsi_host/$name: $!\n";
+	}
+	exec '/home/buczek/tw_cli/tw_cli.orig',@ARGV;
+	die "$!\n";
+}
+wait;
+$? and exit 1;
+
+