Debian noroot 環境において link2symlink 機能を実装した proot を導入する

# はじめに

[Debian noroot][DBNR] とは、 [Android OS][ANDR] 上において root 権限を取ることなく [Debian 環境][DEBI]を構築するためのアプリケーションです。
CPU の性能とメモリ容量が潤沢にある Android 端末であれば、 [Debian noroot][DBNR] の導入によって Android 端末上で非常に軽快な [Debian 環境][DEBI]を実現することができます。

[Android OS 6.0][ANDR] 上において、 [Debian noroot 環境][DBNR]を起動すると、 ```apt-get``` 等の [Debian 環境][DEBI]のパッケージ管理コマンド及び git 等がコマンド内部で使用するファイルに対するハードリンクの実行の失敗により正常に起動せず、 [Debian noroot 環境への各種パッケージの導入に支障を来す問題][AN6L]が発生しています。

```apt-get``` 及び ```git``` 等の起動が失敗する原因は [Android OS 6.0][ANDR] における SELinux の権限に関する設定において、システムコール [```link(2)```][LINK] の実行が禁止されている為と考えられます。

以上に述べた問題を回避するには、 [Debian noroot 環境][DBNR]上で起動する全てのプロセスにおいて発生する全てのシステムコールをフックする機能を持つプロセスである [proot][PROT] に、システムコール [```link(2)```][LINK] の実行の代わりに [```symlink(2)```][SYML] の実行を行うことによりハードリンクをエミュレートする機能 (以下、 link2symlink 機能と呼びます) を追加する必要が有ります。そこで、 [termux の開発コミュニティ][TMUX]によって [link2symlink の機能が実装された proot が公開されています][TMPR]。

この [link2symlink 機能を実装した proot][TMPR] を [Ubuntu 14.04][UBUN] をインストールした PC 端末でクロスコンパイルし、 [Android OS 4.4.2][ANDR], [Android OS 6.0][ANDR] 及び [Android OS 7.0][ANDR] 上で動作する [Debian noroot 環境][DBNR]の [proot][PROT] と入れ換えたところ、 [Debian noroot 環境][DBNR]において [proot の link2symlink 機能][TMPR]が正常に動作することを確認し、また、これに伴って ```apt-get``` コマンドも正常に動作することも確認ました。

本稿では、 [Ubuntu 14.04][UBUN] を搭載した PC 端末を用いて [link2symlink の機能が実装された proot][TMPR] をクロスコンパイルして [Debian noroot 環境][DBNR]に導入し、動作を確認するまでの過程について述べます。

最初に、 "[link2symlink 機能を実装した proot のビルド][CHAP01]" の章で、 [termux の開発コミュニティ][TMUX]による [link2symlink 機能を実装した proot][TMPR] をクロスコンパイルする一連の過程について述べます。

次に、 "[proot の導入][CHAP02]" の章で、[前章][CHAP01]にてビルドした [proot][TMPR] を [Debian noroot 環境][DBNR]に導入する過程について述べ、 "[proot の動作確認][CHAP03]" の章で、 [link2symlink 機能を実装した proot][TMPR] を導入した [Debian noroot 環境][DBNR]において、ハードリンクの実行の正常な動作を確認する過程について述べます。

最後に、 "[結論][CHAP04]" の章で本稿の結論について述べます。

なお、以降においては特に断りの無い限り、クロスコンパイルを行う端末は [Ubuntu 14.04][UBUN] を導入した PC 端末であり、クロスコンパイルのターゲットとなるアーキテクチャは [ARM 32bit アーキテクチャ][ARMP]として本稿を記述します。

# link2symlink 機能を実装した proot のビルド

本章では、 [link2symlink 機能を実装した proot][TMPR] 及び [proot][PROT] の依存ライブラリである [talloc 2.1.14][TLOC] を PC 端末でクロスコンパイルする過程について述べます。

最初に、  "[クロスコンパイル環境の構築][SEC0101]" の節において、 [proot][PROT] のビルドに先立って、 PC 端末に [ARM 32bit アーキテクチャ][ARMP]用のクロスコンパイル環境を構築する手法について述べます。

次に、 "[talloc 2.1.14 のビルド][SEC0102]" の節において、 [proot][PROT] が依存するライブラリである [talloc 2.1.14][TLOC] をビルドする手法について述べ、 "[proot のビルド][SEC0103]" の節において、 [link2symlink 機能を実装した proot][TMPR] をビルドする手法について述べます。

最後に、 "[proot のビルドの自動化 Ruby スクリプト][SEC0104]" の節において、当方にて作成した [talloc 2.1.14][TLOC] 及び [proot][PROT] のビルドを一括で行う Makefile の使用法について述べます。

## クロスコンパイル環境の構築

本節では、 PC 端末に [ARM 32bit アーキテクチャ][ARMP]用のクロスコンパイル環境及び簡単な動作確認用の [```qemu```][QEMU] のユーザモード環境の構築について述べます。

ここで、　PC 端末にクロスコンパイル環境に導入するには、下記の２つの手法があります。

1. PC 端末に、 [ARM 32bit アーキテクチャ][ARMP]用のクロスコンパイル環境を導入するための Debian パッケージ ```g++-arm-linux-gnueabihf``` をインストールする手法。
2. PC 端末に、 [Android NDK][ANDK] を導入し、 [ARM 32bit アーキテクチャ][ARMP]用のクロスコンパイル環境として、 [Android NDK stand alone toolchain][ANDK] をインストールする手法。

本節では、 "[Debian パッケージによるクロスコンパイル環境をインストールする手法][SUBSEC010101]" の項において、前者による手法について述べ、 "[Android NDK によるクロスコンパイル環境をインストールする手法][SUBSEC010102]" の項において、後者による手法について述べます。

### Debian パッケージによるクロスコンパイル環境をインストールする手法

Debian パッケージによるクロスコンパイル環境をインストールするには、まず最初に PC 端末上で apt-get コマンドを用いて、セルフコンパイル環境と [github][GITH] 及び Web 上で必要なリポジトリ及びアーカイブの取得に必要な ```git``` と ```wget``` を下記のようにインストールします。

また、 [ARM 32bit アーキテクチャ][ARMP]用のクロスコンパイル環境の導入に必要な ```g++-arm-linux-gnueabihf``` と [```qemu```][QEMU] のユーザモード環境を下記のようにインストールします。

```shell-session
 $ sudo apt-get install build-essensial git wget
 $ sudo apt-get install g++-arm-linux-gnueabihf qemu-user qemu-user-static
```

ここで、もしディレクトリ ```/usr/include/asm``` が存在しない場合は下記のようにして、ディレクトリ ```/usr/include``` にカレントディレクトリを移動し、ディレクトリ ```asm-generic``` から ```asm``` にシンボリックリンクを張ります。

```
 $ cd /usr/include
 $ sudo ln -sf asm-generic asm
```

次に、クロスコンパイル環境に関連する ```CC, LD, CFLAGS``` 等の環境変数を以下のように設定します。

```shell-session
 $ export BUILD_PREFIX=${PWD}/opt
 $ export BUILD_HOST=arm-linux-gnueabihf
 $ export CROSS_COMPILE=/usr/bin/${BUILD_HOST}-
 $ export CC=${CROSS_COMPILE}gcc
 $ export CPP=${CROSS_COMPILE}cpp
 $ export AR=${CROSS_COMPILE}ar
 $ export RANLIB=${CROSS_COMPILE}ranlib
 $ export STRIP=${CROSS_COMPILE}strip
 $ export LD=${CROSS_COMPILE}ld
 $ export OBJCOPY=${CROSS_COMPILE}objcopy
 $ export OBJDUMP=${CROSS_COMPILE}objdump
 $ export CFLAGS="-mthumb -I${BUILD_PREFIX}/include -I/usr/${BUILD_HOST}/include"
 $ export CPPFLAGS="-mthumb -I${BUILD_PREFIX}/include -I/usr/${BUILD_HOST}/include"
 $ export LDFLAGS="-L${BUILD_PREFIX}/lib -L/usr/${BUILD_HOST}/lib"
```

以上で、 PC 端末において、 Debian パッケージ ```g++-arm-linux-gnueabihf``` による [ARM 32bit アーキテクチャ][ARMP]用のクロスコンパイル及び簡単な動作確認の環境が構築されました。

### Android NDK によるクロスコンパイル環境をインストールする手法

前項で述べた  [ARM 32bit アーキテクチャ][ARMP]用のクロスコンパイル環境の Debian パッケージ ```g++-arm-linux-gnueabihf``` に代えて、 [Android NDK][ANDK] stand alone toolchain を用いたクロスコンパイル環境をインストールするには、まず Debian パッケージ ```wget, git``` とセルフコンパイル環境及び [```qemu```][QEMU] のユーザモード環境を下記のようにインストールします。

```shell-session
 $ sudo apt-get install build-essensial git wget qemu-user qemu-user-static
```

次に、 [proot][PROT] をビルドする端末に [Android NDK][ANDK] をインストールします。具体的なインストール手法については、 [tanjo 氏][TANJ]による "[Android の Linux 環境をターミナルから構築する][QTNJ]" の投稿の他、 [Android NDK][ANDK] に関する各種資料を参考にして下さい。

なお、 [Linuxbrew][BREW] が導入されている端末に [Android NDK][ANDK] のインストールする場合は、 2018 年 3 月現在で ```android-sdk, android-ndk``` の両 Formula が [Caskroom][CASK] に移行しているため、下記のようにしてインストールする必要があります。

```shell-session
 $ brew install -dv https://raw.githubusercontent.com/Linuxbrew/homebrew-core/a0f7020167cec6ee73c7d99ca89b1bd433ee6536/Formula/android-sdk.rb
 $ brew install -dv https://raw.githubusercontent.com/Linuxbrew/homebrew-core/b0eae852a26b09e17111caa75b6c8e9d636b9055/Formula/android-ndk.rb
```

そして、クロスコンパイル環境に関連する ```CC, LD, CFLAGS``` 等の環境変数を以下のように設定します。

```shell-session
 $ export BUILD_PREFIX=${PWD}/opt
 $ export BUILD_HOST=arm-linux-androideabi
 $ export CROSS_COMPILE=${BUILD_PREFIX}/toolchain-arm/bin/${BUILD_HOST}-
 $ export SYSROOT=${BUILD_PREFIX}/toolchain-arm/sysroot
 $ export CC="${CROSS_COMPILE}gcc --sysroot=${SYSROOT}"
 $ export CPP="${CROSS_COMPILE}cpp --sysroot=${SYSROOT}"
 $ export AR=${CROSS_COMPILE}ar
 $ export RANLIB=${CROSS_COMPILE}ranlib
 $ export STRIP=${CROSS_COMPILE}strip
 $ export LD=${CROSS_COMPILE}ld
 $ export OBJCOPY=${CROSS_COMPILE}objcopy
 $ export OBJDUMP=${CROSS_COMPILE}objdump
 $ export CFLAGS="-mthumb -I${BUILD_PREFIX}/include"
 $ export CPPFLAGS="-mthumb -I${BUILD_PREFIX}/include"
 $ export LDFLAGS="-L${BUILD_PREFIX}/lib"
```

最後に、下記のコマンドを起動して、 [proot][PROT] をビルドするための [ARM 32bit アーキテクチャ][ARMP]用のクロスコンパイル環境となる [Android NDK][ANDK] から [Android NDK stand alone toolchain][ANDK] を生成します。

ここで、 PC 端末への [Android NDK][ANDK] のインストール先のディレクトリは、環境変数 ```ANDROID_NDK_HOME``` に代入されているものとします。

```shell-session
 $ ${ANDROID_NDK_HOME}/build/tools/make_standalone_toolchain.py --arch arm --api 24 --force --verbose --install-dir ${BUILD_PREFIX}/toolchain-arm
```

以上で、 PC 端末において、 [Android NDK stand alone toolchain][ANDK] による [ARM 32bit アーキテクチャ][ARMP]用のクロスコンパイル及び簡単な動作確認の環境が構築されました。

## talloc 2.1.14 のビルド

本節では、 [proot][PROT] の依存ライブラリである talloc 2.1.14 を[前節][SEC0101]で構築したクロスコンパイル環境でビルドする手法について述べます。

先ず最初に、下記の通りに [talloc 2.1.14][TLOC] のソースコードの tarball をダウンロードして展開します。展開後は、カレントディレクトリを ```./talloc-2.1.14``` に移動します。

```shell-session
 $ wget https://download.samba.org/pub/talloc/talloc-2.1.14.tar.gz
 $ tar -zxvf talloc-2.1.14.tar.gz
 $ cd ./talloc-2.1.14
```

次に、 talloc 2.1.14 のクロスコンパイルの際に必要となる設定が書かれたテキストファイル ```talloc-cross-answer.txt``` を以下の内容で作成します。
テキストファイル ```talloc-cross-answer.txt``` は、ディレクトリ ```./talloc-2.1.14``` 上に置いておきます。

```talloc-cross-answer.txt
Checking uname sysname type: "Linux"
Checking uname machine type: "do not care"
Checking uname release type: "do not care"
Checking uname version type: "do not care"
Checking simple C program: OK
building library support: OK
Checking for large file support: OK
Checking for -D_FILE_OFFSET_BITS=64: OK
Checking for WORDS_BIGENDIAN: OK
Checking for C99 vsnprintf: OK
Checking for HAVE_SECURE_MKSTEMP: OK
rpath library support: OK
-Wl,--version-script support: FAIL
Checking correct behavior of strtoll: OK
Checking correct behavior of strptime: OK
Checking for HAVE_IFACE_GETIFADDRS: OK
Checking for HAVE_IFACE_IFCONF: OK
Checking for HAVE_IFACE_IFREQ: OK
Checking getconf LFS_CFLAGS: OK
Checking for large file support without additional flags: OK
Checking for working strptime: OK
Checking for HAVE_SHARED_MMAP: OK
Checking for HAVE_MREMAP: OK
Checking for HAVE_INCOHERENT_MMAP: OK
Checking getconf large file support flags work: OK
```

続いて、下記の通りに ```./configure``` スクリプト及び ```make``` コマンドを起動して、 [talloc 2.1.14][TLOC] の動的ライブラリ及びヘッダファイルをディレクトリ ```${BUILD_PREFIX}/{lib,include}``` 上にインストールします。

```shell-session
 $ ./configure --prefix=${BUILD_PREFIX} --cross-compile --cross-answers=./talloc-cross-answer.txt --disable-python --without-gettext --disable-rpath
 $ make install V=1
```

ここで、[次節][SEC0103]で述べる [proot][PROT] のビルドにおいて、ライブラリ [talloc][TLOC] を [proot][PROT] と静的にリンクさせるため、下記のようにして [talloc][TLOC] の静的ライブラリを生成し、動的ライブラリと同じくディレクトリ ```${BUILD_PREFIX}/lib``` 上にインストールします。

```shell-session
 $ (cd bin/default; ${AR} rsv ./libtalloc.a ./talloc_5.o ./lib/replace/replace_2.o ./lib/replace/cwrap_2.o ./lib/replace/closefrom_2.o)
 $ install -v -m 0644 bin/default/libtalloc.a ${BUILD_PREFIX}/lib
 $ cd ..
```

以上で、 [proot][PROT] の依存ライブラリである [talloc 2.1.14][TLOC] がインストールされました。

## proot のビルド

本節では、 [link2symlink 機能を実装した proot][TMPR] を[前々節][SEC0101]で構築したクロスコンパイル環境でビルドする手法について述べます。

まず最初に、下記のとおりにして [Termux の開発コミュニティ][TMUX]による [link2symlink 機能を実装した proot][TMPR] の [github][GITH] リポジトリを ```git``` コマンドを用いて取得します。

```shell-session
 $ git clone https://github.com/termux/proot.git ./proot-termux-git
```

なお、 [Termux の開発コミュニティ][TMUX]による [link2symlink 機能を実装した proot][TMPR] において、現行の [github][GITH] リポジトリのソースコードをコンパイルする際には、下記に述べる問題を修正する必要があります。

- Debian パッケージ ```g++-arm-linux-gnueabihf``` による [ARM 32bit アーキテクチャ][ARMP]及び [ARM 64bit アーキテクチャ][ARMP]用のクロスコンパイル環境を用いてコンパイルを行った場合に、コンパイルエラーが発生する問題を修正。
- VFAT 領域等、シンボリックリンクに対応していないファイルシステムの領域において、システムコール [link(2)][LINK] を実行した時に、リンク元のファイルが別名に変更されたままとなる問題を修正。
- [proot][PROT] コマンドにおいて、オプション ```--link2symlink``` が指定され、かつ、環境変数 ```PROOT_L2S_DIR``` が設定されない場合に、自動的にオプション ```-H``` が指定されて [proot][PROT] コマンドが起動されるように修正。
    - また、オプション ```-H``` が設定された場合に、 [proot][PROT] によって不可視化されるファイル及びシンボリックリンクのプレフィックスを ".l2s." とするように修正。
    - [link(2)][LINK] を [symlink(2)][SYML] によってエミュレートする機能を使用時に [proot][PROT] の内部で作成される ".l2s." をプレフィックスとするファイル及びシンボリックリンクが外部から直接読み書きが出来るためにこれらのファイルを削除すると、ハードリンクが機能しなくなるために行われる修正です。
- ソースコード ```src/syscall/socket.c``` において、 obsolete である glibc の標準ライブラリ関数 ```mktemp(3)``` に代えて独自の実装による ```mktemp(3)``` 関数である ```proot_mktemp``` 関数を使用するように修正。
- ソースコードのうち、幾つかのファイル等において、 [proot][PROT] のコンパイル時に警告を出力する問題を修正。
- proot の一時ファイルを置くためのディレクトリのパス名の設定について、環境変数 ```PROOT_TMP_DIR``` の他に、環境変数 ```PROOT_TMPDIR``` を参照するように修正。

上記で述べた問題を修正するためには、ソースコードをコンパイルする前に、以下に示す差分ファイルをソースコードに適用する必要があります。

```proot-termux-fix.diff
diff --git a/src/arch.h b/src/arch.h
index f554338..272bcbe 100644
--- a/src/arch.h
+++ b/src/arch.h
@@ -111,6 +111,22 @@ typedef unsigned char byte_t;
     #undef SYSCALL_AVOIDER
     #define SYSCALL_AVOIDER ((word_t) 222)
 
+    #if !defined(__ANDROID__) && defined(__thumb__)
+    /* Fix a compile error of proot when edc869d -> 58d2161. */
+    /* These defines come from /usr/arm-linux-gnueabihf/include/asm/ptrace.h */
+    #ifndef ARM_cpsr
+    #define ARM_cpsr        uregs[16]
+    #endif /* ARM_cpsr */
+
+    #ifndef V4_PSR_T_BIT
+    #define V4_PSR_T_BIT    0x00000020      /* >= V4T, but not V7M */
+    #endif /* V4_PSR_T_BIT */
+
+    #ifndef PSR_T_BIT
+    #define PSR_T_BIT       V4_PSR_T_BIT
+    #endif /* PSR_T_BIT */
+    #endif /* !__ANDROID__ && __thumb__ */
+
 #elif defined(ARCH_ARM64)
 
     #define SYSNUMS_HEADER1 "syscall/sysnums-arm64.h"
@@ -139,6 +155,35 @@ typedef unsigned char byte_t;
     #undef SYSCALL_AVOIDER
     #define SYSCALL_AVOIDER ((word_t) -1)
 
+    #ifndef __ANDROID__
+    /* Fix a compile error of proot when using aarch64-linux-gnu-gcc. */
+    /* These define come from glibc/sysdeps/unix/sysv/linux/aarch64/sys/user.h */
+    /* See https://code.woboq.org/userspace/glibc//sysdeps/unix/sysv/linux/aarch64/sys/user.h.html */
+    #include <stdint.h>
+
+    struct user_regs_struct {
+	    uint64_t regs[31];
+	    uint64_t sp;
+	    uint64_t pc;
+	    uint64_t pstate;
+    };
+
+    struct user_fpsimd_struct {
+	    __uint128_t vregs[32];
+	    uint32_t fpsr;
+	    uint32_t fpcr;
+    };
+    #endif /* __ANDROID__ */
+
+    /* This define come from /usr/src/include/uapi/linux/ptrace.h */
+    /* See https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/ptrace.h */
+    #ifndef PTRACE_GETSIGMASK
+    #define PTRACE_GETSIGMASK	0x420a
+    #endif
+    #ifndef PTRACE_SETSIGMASK
+    #define PTRACE_SETSIGMASK	0x420b
+    #endif
+
 #elif defined(ARCH_X86)
 
     #define SYSNUMS_HEADER1 "syscall/sysnums-i386.h"
diff --git a/src/cli/cli.c b/src/cli/cli.c
index c523f2e..e3949ee 100644
--- a/src/cli/cli.c
+++ b/src/cli/cli.c
@@ -557,10 +557,17 @@ const char *expand_front_variable(TALLOC_CTX *context, const char *string)
 
 static int indent_level = 0;
 
+#ifdef __ANDROID__
+void __cyg_profile_func_enter(void *this_function UNUSED, void *call_site UNUSED) DONT_INSTRUMENT;
+void __cyg_profile_func_enter(void *this_function UNUSED, void *call_site UNUSED)
+#else
 void __cyg_profile_func_enter(void *this_function, void *call_site) DONT_INSTRUMENT;
 void __cyg_profile_func_enter(void *this_function, void *call_site)
+#endif
 {
+#ifndef __ANDROID__
 	void *const pointers[] = { this_function, call_site };
+#endif
 	char **symbols = NULL;
 
 #ifndef __ANDROID__
diff --git a/src/cli/proot.c b/src/cli/proot.c
index 6a37c79..1f29a44 100644
--- a/src/cli/proot.c
+++ b/src/cli/proot.c
@@ -221,8 +221,10 @@ static int handle_option_V(Tracee *tracee UNUSED, const Cli *cli, const char *va
 	fflush(stdout);
 
 	size = &_binary_licenses_end - &_binary_licenses_start;
-	if (size > 0)
-		write(1, &_binary_licenses_start, size);
+	if (size > 0) {
+		if (write(1, &_binary_licenses_start, size) < 0) { /* noop */
+		}
+	}
 
 	exit_failure = false;
 	return -1;
@@ -283,12 +285,20 @@ static int handle_option_S(Tracee *tracee, const Cli *cli, const char *value)
 static int handle_option_link2symlink(Tracee *tracee, const Cli *cli UNUSED, const char *value UNUSED)
 {
 	int status;
+	char *l2s_directory;
 
 	/* Initialize the link2symlink extension.  */
 	status = initialize_extension(tracee, link2symlink_callback, NULL);
 	if (status < 0)
 		note(tracee, WARNING, INTERNAL, "link2symlink not initialized");
 
+	/* If environment variable PROOT_L2S_DIR is not set, the option "-H" is forced to be set. */
+	l2s_directory = getenv("PROOT_L2S_DIR");
+	if (l2s_directory == NULL || l2s_directory[0] == '\0') {
+		if(handle_option_H(tracee, cli, value) < 0) { /* noop */
+		}
+	}
+
 	return 0;
 }
 
diff --git a/src/cli/proot.h b/src/cli/proot.h
index 31ce9ac..bccaafb 100644
--- a/src/cli/proot.h
+++ b/src/cli/proot.h
@@ -245,7 +245,12 @@ Copyright (C) 2015 STMicroelectronics, licensed under GPL v2 or later.",
                 { .name = "-H", .separator = '\0', .value = NULL },
                 { .name = NULL, .separator = '\0', .value = NULL } },
           .handler = handle_option_H,
+#ifdef USERLAND
           .description = "Hide files and directories starting with '.proot.' .",
+#endif
+#ifndef USERLAND
+          .description = "Hide files and directories starting with '.l2s.' . (If environment variable 'PROOT_L2S_DIR' is not set, this option is forced to be set.)",
+#endif
           .detail = "",
         },
         { .class = "Extension options",
diff --git a/src/extension/fake_id0/chroot.c b/src/extension/fake_id0/chroot.c
index 757a602..1876d13 100644
--- a/src/extension/fake_id0/chroot.c
+++ b/src/extension/fake_id0/chroot.c
@@ -32,12 +32,14 @@ int handle_chroot_exit_end(Tracee *tracee, Config *config) {
 	status = translate_path(tracee, path_translated, AT_FDCWD, path, false);
 	if (status < 0)
 		return status;
-	realpath(path_translated, path_translated_absolute);
+	if (realpath(path_translated, path_translated_absolute) == (char *)NULL) { /* noop */
+	}
 
 	status = translate_path(tracee, root_translated, AT_FDCWD, get_root(tracee), false);
 	if (status < 0)
 		return status;
-	realpath(root_translated, root_translated_absolute);
+	if (realpath(root_translated, root_translated_absolute) == (char *)NULL) { /* noop */
+	}
 
 	/* Only "new rootfs == current rootfs" is supported yet.  */
 	status = compare_paths(root_translated_absolute, path_translated_absolute);
diff --git a/src/extension/fake_id0/fake_id0.c b/src/extension/fake_id0/fake_id0.c
index 0e248e3..886c483 100644
--- a/src/extension/fake_id0/fake_id0.c
+++ b/src/extension/fake_id0/fake_id0.c
@@ -1082,6 +1082,7 @@ int fake_id0_callback(Extension *extension, ExtensionEvent event, intptr_t data1
 			uid = getuid();
 
 		gid_string = strchr(uid_string, ':');
+		gid = 0;
 		if (gid_string == NULL) {
 			errno = EINVAL;
 		}
diff --git a/src/extension/fake_id0/helper_functions.c b/src/extension/fake_id0/helper_functions.c
index 3a16ce5..48c4e97 100644
--- a/src/extension/fake_id0/helper_functions.c
+++ b/src/extension/fake_id0/helper_functions.c
@@ -319,7 +319,8 @@ int read_meta_file(char path[PATH_MAX], mode_t *mode, uid_t *owner, gid_t *group
 		return 0;
 
 	}
-	fscanf(fp, "%d %d %d ", &lcl_mode, owner, group);
+	if (fscanf(fp, "%d %d %d ", &lcl_mode, owner, group) == EOF) { /* noop */
+	}
 	lcl_mode = otod(lcl_mode);
 	*mode = (mode_t)lcl_mode;
 	fclose(fp);
diff --git a/src/extension/fake_id0/sendmsg.c b/src/extension/fake_id0/sendmsg.c
index 228fcdc..ea3cb8d 100644
--- a/src/extension/fake_id0/sendmsg.c
+++ b/src/extension/fake_id0/sendmsg.c
@@ -13,7 +13,7 @@ int handle_sendmsg_enter_end(Tracee *tracee, word_t sysnum)
 	/* Read sendmsg header.  */
 	int status;
 	unsigned long socketcall_args[3];
-	struct msghdr msg = {};
+	struct msghdr msg = { .msg_name = (void *)NULL };
 	bool is_socketcall = sysnum == PR_socketcall;
 
 	if (!is_socketcall)
diff --git a/src/extension/hidden_files/hidden_files.c b/src/extension/hidden_files/hidden_files.c
index 54e4abc..a27a42b 100644
--- a/src/extension/hidden_files/hidden_files.c
+++ b/src/extension/hidden_files/hidden_files.c
@@ -13,7 +13,12 @@
 #include "path/path.h"
 
 /* Change the HIDDEN_PREFIX to change which files are hidden */
+#ifdef USERLAND
 #define HIDDEN_PREFIX ".proot"
+#endif 
+#ifndef USERLAND
+#define HIDDEN_PREFIX ".l2s."
+#endif 
 
 struct linux_dirent {
     unsigned long d_ino;
diff --git a/src/extension/link2symlink/link2symlink.c b/src/extension/link2symlink/link2symlink.c
index 3b63382..511cc22 100644
--- a/src/extension/link2symlink/link2symlink.c
+++ b/src/extension/link2symlink/link2symlink.c
@@ -56,6 +56,8 @@ static int move_and_symlink_path(Tracee *tracee, Reg sysarg)
 	char new_intermediate[PATH_MAX];
 	char final[PATH_MAX];
 	char new_final[PATH_MAX];
+	char final_bak[PATH_MAX];
+	char intermediate_bak[PATH_MAX];
 	char * name;
 	const char * l2s_directory;
 	struct stat statl;
@@ -141,13 +143,24 @@ static int move_and_symlink_path(Tracee *tracee, Reg sysarg)
 
 		/* Symlink the intermediate to the final file.  */
 		status = symlink(final, intermediate);
-		if (status < 0)
+		if (status < 0) {
+			/* ensure rename final -> original */
+			rename(final, original);
+
 			return status;
+		}
 
 		/* Symlink the original path to the intermediate one.  */
 		status = symlink(intermediate, original);
-		if (status < 0)
+		if (status < 0) {
+			/* ensure rename final -> original */
+			rename(final, original);
+
+			/* ensure unlink intermediate */
+			unlink(intermediate);
+
 			return status;
+		}
 	} else {
 		/*Move the original content to new location, by incrementing count at end of path. */
 		size = my_readlink(intermediate, final);
@@ -166,12 +179,32 @@ static int move_and_symlink_path(Tracee *tracee, Reg sysarg)
 		status = notify_extensions(tracee, LINK2SYMLINK_RENAME, (intptr_t) final, (intptr_t) new_final);
 		if (status < 0)
 			return status;
+
+		strcpy(final_bak, final);
 		strcpy(final, new_final);
+		snprintf(intermediate_bak, (size_t)PATH_MAX, "%s.bak", intermediate);
+
 		/* Symlink the intermediate to the final file.  */
-		status = unlink(intermediate);
-		if (status < 0)
+		status = rename(intermediate, intermediate_bak);
+		if (status < 0) {
+			/* ensure rename final_bak (original final) -> final */
+			rename(final, final_bak);
+
 			return status;
+		}
+
 		status = symlink(final, intermediate);
+		if (status < 0) {
+			/* ensure rename intermediate_bak (original intermediate) -> intermediate */
+			rename(intermediate_bak, intermediate);
+
+			/* ensure rename final_bak (original final) -> final */
+			rename(final, final_bak);
+
+			return status;
+		}
+
+		status = unlink(intermediate_bak);
 		if (status < 0)
 			return status;
 	}
@@ -195,6 +228,8 @@ static int decrement_link_count(Tracee *tracee, Reg sysarg)
 	char intermediate[PATH_MAX];
 	char final[PATH_MAX];
 	char new_final[PATH_MAX];
+	char final_bak[PATH_MAX];
+	char intermediate_bak[PATH_MAX];
 	char * name;
 	struct stat statl;
 	ssize_t size;
@@ -254,15 +289,32 @@ static int decrement_link_count(Tracee *tracee, Reg sysarg)
 		if (status < 0)
 			return status;
 
+		strcpy(final_bak, final);
 		strcpy(final, new_final);
+		snprintf(intermediate_bak, (size_t)PATH_MAX, "%s.bak", intermediate);
 
 		/* Symlink the intermediate to the final file.  */
-		status = unlink(intermediate);
-		if (status < 0)
+		status = rename(intermediate, intermediate_bak);
+		if (status < 0) {
+			/* ensure final_bak (original final) -> final */
+			rename(final_bak, final);
+
 			return status;
+		}
 
 		status = symlink(final, intermediate);
-		if (status < 0)
+		if (status < 0) {
+			/* ensure final_bak (original final) -> final */
+			rename(final_bak, final);
+
+			/* ensure intermediate_bak (original intermediate) -> intermediate */
+			rename(intermediate_bak, intermediate);
+
+			return status;
+		}
+
+		status = unlink(intermediate_bak);
+		if(status < 0)
 			return status;
 	} else {
 		/* If it is the last, delete the intermediate and final */
diff --git a/src/path/temp.c b/src/path/temp.c
index 8d8aa63..829168a 100644
--- a/src/path/temp.c
+++ b/src/path/temp.c
@@ -24,7 +24,11 @@ const char *get_temp_directory()
 
 	temp_directory = getenv("PROOT_TMP_DIR");
 	if (temp_directory == NULL) {
-		temp_directory = P_tmpdir;
+		temp_directory = getenv("PROOT_TMPDIR");
+		if (temp_directory == NULL) {
+			temp_directory = P_tmpdir;
+			return temp_directory;
+		}
 	}
 
 	tmp = realpath(temp_directory, NULL);
diff --git a/src/syscall/rlimit.c b/src/syscall/rlimit.c
index d167843..27efd2a 100644
--- a/src/syscall/rlimit.c
+++ b/src/syscall/rlimit.c
@@ -88,7 +88,7 @@ int translate_setrlimit_exit(const Tracee *tracee, bool is_prlimit)
 		/* Convert this special value from 32-bit to 64-bit,
 		 * if needed.  */
 		if (is_32on64_mode(tracee) && tracee_stack_limit == (uint32_t) -1)
-			tracee_stack_limit = RLIM_INFINITY;
+			tracee_stack_limit = (uint32_t)RLIM_INFINITY;
 	}
 	if (errno != 0)
 		return -errno;
@@ -112,6 +112,6 @@ int translate_setrlimit_exit(const Tracee *tracee, bool is_prlimit)
 		VERBOSE(tracee, 1, "can't set stack limit.");
 	return 0; /* Not fatal.  */
 
-	VERBOSE(tracee, 1, "stack soft limit increased to %llu bytes", proot_stack.rlim_cur);
+	VERBOSE(tracee, 1, "stack soft limit increased to %llu bytes", (long long unsigned int)proot_stack.rlim_cur);
 	return 0;
 }
diff --git a/src/syscall/socket.c b/src/syscall/socket.c
index ec74950..6780318 100644
--- a/src/syscall/socket.c
+++ b/src/syscall/socket.c
@@ -28,6 +28,10 @@
 #include <sys/socket.h>  /* struct sockaddr_un, AF_UNIX, */
 #include <sys/un.h>      /* struct sockaddr_un, */
 #include <sys/param.h>   /* MIN(), MAX(), */
+#include <stdlib.h>      /* For proot_mktemp() */
+#include <time.h>        /* For proot_mktemp() */
+#include <sys/types.h>   /* For proot_mktemp() */
+#include <sys/stat.h>    /* For proot_mktemp() */
 
 #include "syscall/socket.h"
 #include "tracee/tracee.h"
@@ -39,12 +43,47 @@
 
 #include "compat.h"
 
+/* For proot_mktemp() */
+#define ALPHABET "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#define XXXXXX "XXXXXX"
+
 /* The sockaddr_un structure has exactly the same layout on all
  * architectures.  */
 static const off_t offsetof_path = offsetof(struct sockaddr_un, sun_path);
 extern struct sockaddr_un sockaddr_un__;
 static const size_t sizeof_path  = sizeof(sockaddr_un__.sun_path);
 
+/**
+ * This function generates a unique temporary filename from @path.
+ * The last six characters of @path must be XXXXXX and these 
+ * are replaced with a string that makes the filename unique. 
+ * The function proot_mktemp() is made instead of mktemp(3) in glibc.
+ */
+static char *proot_mktemp(char *path) {
+	char *xptr, *p; struct stat st;
+
+	xptr = strstr((const char *)path, XXXXXX);
+
+	if ((xptr == (char *)NULL) || (*(xptr + strlen(XXXXXX)) != '\0')) {
+		(void)strncpy(path, "", strlen((const char *)path));
+		return (char *)NULL;
+	}
+
+	srand((unsigned int)time(NULL));
+
+	for ( ; ; ) {
+		for (p = xptr ; *p == 'X'; p++) {
+			*p = ALPHABET[rand() % strlen(ALPHABET)];
+		}
+
+		if (stat(path, &st) == -1) {
+			return path;
+		} else {
+			(void)strncpy(xptr, XXXXXX, strlen(XXXXXX));
+		}
+	}
+}
+
 /**
  * Copy in @sockaddr the struct sockaddr_un stored in the @tracee
  * memory at the given @address.  Also, its pathname is copied to the
@@ -120,7 +159,7 @@ int translate_socketcall_enter(Tracee *tracee, word_t *address, int size)
 		if (shorter_host_path == NULL || strlen(shorter_host_path) > sizeof_path)
 			return -EINVAL;
 
-		(void) mktemp(shorter_host_path);
+		(void) proot_mktemp(shorter_host_path);
 
 		if (strlen(shorter_host_path) > sizeof_path)
 			return -EINVAL;
diff --git a/src/tracee/event.c b/src/tracee/event.c
index 7310605..501baee 100644
--- a/src/tracee/event.c
+++ b/src/tracee/event.c
@@ -637,7 +637,7 @@ int handle_tracee_event(Tracee *tracee, int tracee_status)
 			break;
 
 		case SIGSYS: {
-			siginfo_t siginfo = {};
+			siginfo_t siginfo = { .si_signo = 0 };
 			ptrace(PTRACE_GETSIGINFO, tracee->pid, NULL, &siginfo);
 			if (siginfo.si_code == SYS_SECCOMP) {
 				if (tracee->skip_next_seccomp_signal) {
diff --git a/src/tracee/mem.c b/src/tracee/mem.c
index 5e0d1d9..0aadd68 100644
--- a/src/tracee/mem.c
+++ b/src/tracee/mem.c
@@ -192,14 +192,14 @@ static int ptrace_pokedata_or_via_stub(Tracee *tracee, word_t addr, word_t word)
 	return status;
 }
 
-void mem_prepare_after_execve(Tracee *tracee)
+void mem_prepare_after_execve(Tracee *tracee UNUSED)
 {
 #if HAS_POKEDATA_WORKAROUND
 	tracee->pokedata_workaround_stub_addr = peek_reg(tracee, CURRENT, INSTR_POINTER) + offset_to_pokedata_workaround;
 #endif
 }
 
-void mem_prepare_before_first_execve(Tracee *tracee)
+void mem_prepare_before_first_execve(Tracee *tracee UNUSED)
 {
 #if HAS_POKEDATA_WORKAROUND
 	tracee->pokedata_workaround_stub_addr = (word_t)&launcher_pokedata_workaround;
diff --git a/src/tracee/reg.c b/src/tracee/reg.c
index 4c8d254..986e6e6 100644
--- a/src/tracee/reg.c
+++ b/src/tracee/reg.c
@@ -262,7 +262,11 @@ int fetch_regs(Tracee *tracee)
 	return 0;
 }
 
+#ifdef ARCH_ARM_EABI
 int push_specific_regs(Tracee *tracee, bool including_sysnum)
+#else
+int push_specific_regs(Tracee *tracee, bool including_sysnum UNUSED)
+#endif
 {
 	int status;
 
diff --git a/src/tracee/seccomp.c b/src/tracee/seccomp.c
index 7a3893e..1fa186a 100644
--- a/src/tracee/seccomp.c
+++ b/src/tracee/seccomp.c
@@ -230,7 +230,6 @@ static int handle_seccomp_event_common(Tracee *tracee)
 	case PR_statfs:
 	{
 		int size;
-		int status;
 		char path[PATH_MAX];
 		char original[PATH_MAX];
 		struct statfs64 my_statfs64;
```

即ち、 [proot][PROT] のソースコードの [github][GITH] リポジトリが置かれているディレクトリ ```./proot-termux-git``` 上において、下記のように差分ファイル ```proot-termux-fix.diff``` を適用します。

```shell-session
 $ patch -p1 < ../proot-termux-fix.diff
``` 

最後に、カレントディレクトリを ```./proot-termux-git/src``` に移動した後、 ```./GNUmakefile``` に対して ```make``` コマンドを下記のように起動して、 [link2symlink 機能を実装した proot][TMPR] をビルドします。
この時、一時的に環境変数 ```LC_ALL``` を ```C``` に設定し、また、[前節][SEC0102]においてビルドした talloc 2.1.14 を静的にリンクするために、環境変数 ```LDFLAGS``` に ```"-static -ltalloc"``` を追加して ```make``` コマンドを起動するのを忘れないようにします。

```shell-session
 $ cd ./proot-termux-git/src
 $ /usr/bin/env LC_ALL=C make -f ./GNUmakefile CC=${CC} LD=${CC} STRIP=${STRIP} OBJCOPY=${OBJCOPY} OBJDUMP=${OBJDUMP} \
     CPPFLAGS="-D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I. -I${BUILD_PREFIX}/include ${CPPFLAGS}" \
     CFLAGS="${CFLAGS} -Wall -Wextra -O2" LDFLAGS="${LDFLAGS} -static -ltalloc -Wl,-z,noexecstack" V=1
```

以上で、 [link2symlink 機能が実装された proot][TMPR] の [ARM 32bit アーキテクチャ][ARMP]用実行ファイルがビルドされました。

## proot のビルドの自動化 Ruby スクリプト

ここで、[前々節][SEC0102]において述べた [talloc 2.1.14 のビルド][TLOC]と、[前節][SEC0103]において述べた [link2symlink 機能を実装した proot][TMPR] をビルドを一括して行う為の Ruby スクリプトを当方にて作成し、[github にて公開しました][PRBU]。

本節では、 [link2symlink 機能を実装した proot][TMPR] の実行ファイルのビルドを自動化する Ruby スクリプトの使用法について述べます。

まず最初に、下記のようにして、 "[クロスコンパイル環境の構築][SEC0101]" の節において述べた [ARM 32bit アーキテクチャ][ARMP]用クロスコンパイル環境を PC 端末に構築した後、 ```git``` コマンドを用いて [link2symlink 機能を実装した proot のビルドを自動化する Ruby スクリプト][PRBU]のリポジトリを取得します。

```shell-session
 $ sudo apt-get install build-essensial git wget
 $ sudo apt-get install g++-arm-linux-gnueabihf qemu-user qemu-user-static
 $ git clone https://github.com/z80oolong/proot-termux-build.git
```

次に、カレントディレクトリを ```./proot-termux-build``` に移動して下記のように ```./build-proot.rb``` コマンドを起動します。

これにより、 [talloc 2.1.14][TLOC] 及び [link2symlink 機能を実装した proot][TMPR] のソースコードの取得と [ARM 32bit アーキテクチャ][ARMP]用のクロスコンパイルによるビルドを自動的に行い、実行形式のファイル  ```proot``` をディレクトリ ```./cross-compile``` にインストールします。

```shell-session
 $ cd ./proot-termux-build
 $ ./build-proot --arch arm   
```

また、 [link2symlink 機能を実装した proot][TMPR] のビルドに [Android NDK][ANDK] を使用する場合は、以下のように ```./build-proot.rb``` コマンドに、オプション ```--android-ndk-prefix``` と共に [Android NDK][ANDK] のインストール先のディレクトリを渡します。これにより、 [Android NDK stand alone toolchain][ANDK] の生成と一連の [link2symlink 機能を実装した proot][TMPR] のビルドが自動的に行われます。

```shell-session
 $ cd ./proot-termux-build
 $ ./build-proot --arch arm --android-ndk-prefix ${ANDROID_NDK_HOME}	# (ここに、 ANDROID_NDK_HOME は Android NDK のインストール先のディレクトリを示す環境変数)
```

Ruby スクリプト ```./build-proot.rb``` の詳細については、[link2symlink 機能を実装した proot のビルドを自動化する Ruby スクリプト][PRBU]のリポジトリに同梱されている [```README.md```][READ] を御覧下さい。

なお、 [ARM][ARMP] 用及び x86 用のセルフコンパイル環境及びクロスコンパイル環境の構築が煩わしい若しくは困難な場合は、次に示す URL から [Debian noroot 環境][DBNR]上に実行ファイルを下記のようにダウンロードして使用しても構いません。

- 安定版 (v5.1.0.112)
    - [proot の実行形式ファイル (ARM 対応) → **https://git.io/proot-5.1.0.112.arm**][PARM]
    - [proot の実行形式ファイル (32 ビット x86 対応) → **https://git.io/proot-5.1.0.112.x32**][PX32]

```shell-session
 $ wget -O ./proot.arm https://git.io/proot-5.1.0.109.arm		# (ARM 用の実行ファイルのダウンロードの場合)
 $ wget -O ./proot.x86-32 https://git.io/proot-5.1.0.109.x32	# (32 ビット x86 用の実行ファイルのダウンロードの場合)
```

ここで、上記の URL から取得できる [proot][PROT] の実行形式のファイルは、何れも [Android NDK stand alone toolchain][ANDK] によるクロスコンパイル環境を用いてビルドされたものです。

また、上記の URL から取得した [proot][PROT] の実行形式のファイルにおいて、動作に問題が発生する場合は、 [Debian パッケージ][DEBI]によるクロスコンパイル環境を用いてビルドされた [proot][PROT] の実行形式のファイルを下記の URL から取得して実行を試みて下さい。

- 安定版 (v5.1.0.112)
    - [proot の実行形式ファイル (ARM 対応) → **https://git.io/proot-5.1.0.112-cross.arm**][XARM]
    - [proot の実行形式ファイル (32 ビット x86 対応) → **https://git.io/proot-5.1.0.112-cross.x32**][XX32]

# proot の導入

本章では、[前章][CHAP01]でビルドした [link2symlink 機能を実装した proot][TMPR] を [Debian noroot 環境][DBNR]に導入する手法について述べます。

先ず最初に、下記のようにして [proot][PROT] の実行ファイルをルートディレクトリにインストールします。この時、 [proot][PROT] の実行ファイルの名前は ```/proot``` と異なる名前にする必要が有ります。

```shell-session
 $ install -v -m 0700 ./proot /proot.link2symlink
 $ install -v -m 0700 ./proot.arm /proot.link2symlink   # (proot の実行ファイルを proot のビルド自動化 Makefile によってビルドしたか、若しくは https://git.io/proot* からダウンロードした場合)
```

ここで、ルートディレクトリ上の実行ファイル ```/proot.link2symlink``` の実行権限がユーザ権限に対して与えられていることと、 ```/proot.link2symlink --help``` コマンドが正常に動作することを確認します。

```shell-session
  $ ls -l /proot.link2symlink
  -rwx------. 1 u0_a185 u0_a185 525464 Dec  7 15:02 /proot.link2symlink
  $ /proot.link2symlink --help
  proot v0.1-5-gd06009d1-dirty: chroot, mount --bind, and binfmt_misc without privilege/setup.

  Usage:
    proot [option] ... [command]
  ...
    --link2symlink
        Replace hard links with symlinks, pretending they are really hardlinks

        Emulates hard links with symbolic links when SELinux policies
        do not allow hard links.
  ...
  Visit http://proot.me for help, bug reports, suggestions, patchs, ...
  Copyright (C) 2015 STMicroelectronics, licensed under GPL v2 or later.
  $

```

次に、[Debian noroot 環境][DBNR]の為の chroot 環境の構築を行うシェルスクリプトである ```/proot.sh``` を修正します。ここで、修正を行う前に、 ```/proot.sh``` のバックアップを下記のように取っておきます。

もし [link2symlink 機能を実装した proot][TMPR] の導入に問題が生じた場合は、バックアップファイルを用いて [Debian noroot 環境][DBNR]を起動する必要が有ります。障害復旧用の環境に関しての詳細は "[Debian noroot 環境に障害復旧用の環境を導入する][DNBK]" の投稿を参照して下さい。

```shell-session
 $ cd /
 $ cp -p ./proot.sh ./proot-safe.sh
 $ chmod u+x ./proot-safe.sh
```

そして、シェルスクリプト ```/proot.sh``` を下記のように修正します。即ち、 ```/proot.sh``` の最後の行の ```./proot``` を起動している箇所を [link2symlink 機能を実装した proot][TMPR] である ```./proot.link2symlink``` に修正し、オプション ```--link2symlink``` を追加します。

```sh:/proot.sh
#!/system/bin/sh
...
export HOME=/home/$USER
export SHELL=/bin/bash
export LD_LIBRARY_PATH=
...
export TZ="`getprop persist.sys.timezone`"
# ./proot -r `pwd` -w / -b /dev -b /proc -b /sys -b /system $STORAGE "$@" # proot を実行している行を以下のように修正する。
./proot.link2symlink --link2symlink -r `pwd` -w / -b /dev -b /proc -b /sys -b /system $STORAGE "$@"
```

シェルスクリプト ```/proot.sh``` を修正した後は、 [Debian noroot 環境][DBNR]を再起動します。

以上で、 [Debian noroot 環境][DBNR]への [link2symlink 機能を実装した proot][TMPR] の導入が完了しました。

# proot の動作確認

本章では、 [Debian noroot 環境][DBNR]へ導入した [link2symlink 機能を実装した proot][TMPR] について、正常にシステムコール [```link(2)```][LINK] が [```symlink(2)```][SYML] によって代替され、 [```link(2)```][LINK] の機能をエミュレートされていることを確認する一連の過程について述べます。

まず最初に、 [link2symlink 機能を実装した proot][TMPR] に基づく [Debian noroot 環境][DBNR]において、下記のようにテスト用の簡潔なテキストファイル ```foo``` を作成します。

```shell-session
 $ mkdir ./test
 $ cd ./test
 $ echo aaaa > foo
 $ ls -l
 合計 4
 -rw-------. 1 u0_a135 u0_a135 5  6月 12 14:35 foo
```

次に、テキストファイル ```foo``` に向けてシンボリックリンク ```foo1``` を作成します。

```shell-session
 $ ln -sf foo foo1
 $ ls -l
 合計 4
 -rw-------. 1 u0_a135 u0_a135 5  6月 12 14:35 foo
 lrwxrwxrwx. 1 u0_a135 u0_a135 3  6月 12 14:37 foo1 -> foo
```

続いて、テキストファイル ```foo``` に向けてハードリンク ```foo2``` を作成します。 ```ls -li``` コマンドによって各ファイル及びリンクを見ると、ハードリンク ```foo2``` はシンボリックリンク ```foo1``` と異なり、ファイル ```foo``` と inode 番号を共有し、権限やタイムスタンプ等も同じ物を共有していることが判ります。

```shell-session
 $ ln foo baz
 $ ls -l
 合計 8
 -rw-------. 2 u0_a135 u0_a135 5  6月 12 14:35 foo
 lrwxrwxrwx. 1 u0_a135 u0_a135 3  6月 12 14:37 foo1 -> foo
 -rw-------. 2 u0_a135 u0_a135 5  6月 12 14:35 foo2
 $ ls -li
 合計 8
 1745266 -rw-------. 2 u0_a135 u0_a135 5  6月 12 14:35 foo
 1745267 lrwxrwxrwx. 1 u0_a135 u0_a135 3  6月 12 14:37 foo1 -> foo
 1745266 -rw-------. 2 u0_a135 u0_a135 5  6月 12 14:35 foo2
 $ cat foo foo1 foo2
 aaaa
 aaaa
 aaaa
```
そして、もう一度、テキストファイル ```foo``` に向けてハードリンク ```foo2``` を作成すると、下記のようになります。

```shell-session
 $ ln foo foo3
 $ ls -li
 合計 12
 1745266 -rw-------. 3 u0_a135 u0_a135 5  6月 12 14:35 foo
 1745267 lrwxrwxrwx. 1 u0_a135 u0_a135 3  6月 12 14:37 foo1 -> foo
 1745266 -rw-------. 3 u0_a135 u0_a135 5  6月 12 14:35 foo2
 1745266 -rw-------. 3 u0_a135 u0_a135 5  6月 12 14:35 foo3
```

ここで、 [Debian noroot 環境][DBNR]上のスクリプトファイル ```/proot.sh``` を元の状態に戻し、 link2symlink 機能を無効にして再起動した後、再度ファイル及びリンク ```foo, foo1, foo2, foo3``` をコマンド ```ls -li``` 等によって表示させると下記の通りになることが判ります。

```shell-session
 $ ls -ali
 合計 28
 drwx------.  2 u0_a135 u0_a135 4096  6月 12 14:52 .
 drwx------. 54 u0_a135 u0_a135 4096  6月 12 14:02 ..
 lrwxrwxrwx.  1 u0_a135 u0_a135  116  6月 12 14:46 .l2s.foo0001 -> /home/u0_a135/test/.l2s.foo0001.0003
 -rw-------.  1 u0_a135 u0_a135    5  6月 12 14:35 .l2s.foo0001.0003
 lrwxrwxrwx.  1 u0_a135 u0_a135  111  6月 12 14:40 foo -> /home/u0_a135/test/.l2s.foo0001
 lrwxrwxrwx.  1 u0_a135 u0_a135    3  6月 12 14:37 foo1 -> foo
 lrwxrwxrwx.  1 u0_a135 u0_a135  111  6月 12 14:40 foo2 -> /home/u0_a135/test/.l2s.foo0001
 lrwxrwxrwx.  1 u0_a135 u0_a135  111  6月 12 14:46 foo3 -> /home/u0_a135/test/.l2s.foo0001
```

これより、 [link2symlink 機能を実装した proot][TMPR] のプロセスの子プロセスよりシステムコール [```link(2)```][LINK] が実行されると、 [proot][PROT] によってこれがフックされ、以下の処理が行われることが判ります。

1. １回目に、ハードリンク元となるファイルからハードリンク先となるファイルにハードリンクを張る時、以下の処理が行われる。
    - ハードリンク元となるファイルの実体のファイル名が .l2s.\*.0002 で始まるファイル名に変更される。ここに、ファイル名の末尾の .0002 は、ファイルの i-node を共有するリンクの個数を示す。
    - ハードリンク元となるファイルの実体のファイル .l2s.\*.0002 に向けて、中間的なシンボリックリンク .l2s.\* を張る。
    - 中間的なシンボリックリンク .l2s.\* に向けて、ハードリンク元及びハードリンク先となるファイル名にシンボリックリンクを張る。
2. ２回目以降に、ハードリンク元となるファイルからハードリンク先となるファイルにハードリンクを張る時、以下の処理が行われる。
    - ハードリンク元となるファイルの実体のファイル名である .l2s.\*.0002 の末尾の .0002 の数字を .0003 にインクリメントする。 (ハードリンク元となるファイルの実体のファイル名が、 l2s.\*.0003 以降も同様。)
    - ハードリンク元となるファイルの実体のファイル .l2s.\*.0003 に向けて、中間的なシンボリックリンク .l2s.\* を張り直す。
    - 中間的なシンボリックリンク .l2s.\* に向けて、ハードリンク先となるファイル名にシンボリックリンクを張る。
3. [proot][PROT] による chroot 環境下においては、 1. 及び 2. で示された過程で作成されたシンボリックリンクが擬似的にハードリンクとして扱われる。
4. 但し、 [link2symlink 機能を実装した proot][TMPR] の起動時に環境変数 ```PROOT_L2S_DIR``` が設定されている場合には、 .l2s. で始まるファイル及びシンボリックリンクは、全て ```PROOT_L2S_DIR``` で示されるディレクトリの下に置かれる。

即ち、 [link2symlink 機能を実装した proot][TMPR] を用いた [Debian noroot 環境][DBNR]において、システムコール [```link(2)```][LINK] の実行は問題無く完全に [```symlink(2)```][SYML] によって代替されることが判りました。

最後に、```/proot.sh``` を再度修正し、 proot の link2symlink 機能を再度有効にして [Debian noroot 環境][DBNR]を再起動した後、 ```apt-get install hello``` コマンドを実行して、 ```hello``` パッケージのインストールが問題なく実行されるか確認します。

```shell-session
  $ sudo apt-get install hello
  Reading package lists... Done
  Building dependency tree       
  Reading state information... Done
  ...
  Preparing to unpack .../hello_2.9-2+deb8u1_armhf.deb ...
  Unpacking hello (2.9-2+deb8u1) ...
  Processing triggers for man-db (2.7.0.2-5) ...
  Setting up hello (2.9-2+deb8u1) ...
  $
```

以上の動作確認が問題なく実行されることが確認されれば、 [link2symlink 機能を実装した proot][TMPR] が正常に動作することが判ります。

# 結論

本稿では、"[link2symlink 機能を実装した proot のビルド][CHAP01]" の章及び "[proot の導入][CHAP02]" の章において、 [Debian noroot 環境][DBNR]において、 [Termux の開発コミュニティ][TMUX]による [link2symlink 機能を実装した proot][TMPR] のビルド及び導入に関する一連の過程について述べました。

そして、"[proot の動作確認][CHAP03]" の章では、 [link2symlink 機能を実装した proot][TMPR] を用いた [Debian noroot 環境][DBNR]において、システムコール [```link(2)```][LINK] が正常に [```symlink(2)```][SYML] によってエミュレートされることを示し、コマンド ```apt-get install hello``` の実行によって、 ```apt-get``` によるパッケージのインストールが正常に行われることが確認されました。

本稿にて行った [link2symlink 機能を実装した proot][TMPR] の導入により、 [Android OS 6.0][ANDR] 以降の [Android OS][ANDR] 上において、 [Debian noroot 環境][DBNR]を起動すると、 ```apt-get``` 等の [Debian 環境][DEBI]のパッケージ管理コマンド及び ```git``` コマンドが正常に動作し、 [Debian noroot 環境への各種パッケージの導入に支障を来す問題][AN6L]等が回避されることが示されました。

# 謝辞

最初に、本稿の記述に当たって、 [Android OS][ANDR] 端末上で非常に軽快な [Debian 環境][DEBI]を実現することを可能にした [Debian noroot 環境][DBNR]の開発者である [pelya 氏][PELY]に心より感謝致します。

次に、 "[クロスコンパイル環境の構築][SEC0101]" の節で述べた [ARM アーキテクチャ][ARMP]のクロスコンパイル環境の構築の詳細に関しては、下記の記事を参考にしました。下記の記事の筆者の皆様に心より感謝致します。

- [lnznt 氏][LNZN]による [Ubuntu 12.04 で hello.c をARMバイナリとしてコンパイルして実行してみる][LBLG]
- [京都マイクロコンピュータ株式会社スタッフ各氏][KMCK]による [Ubuntu 12.04LTS Beta2でMultiarchを試す][KBLG]

また、 "[talloc 2.1.14 のビルド][SEC0102]" の節で述べた [talloc 2.1.14][TLOC] のクロスコンパイルに関する設定に関しては、 [Termux のプロジェクトにおける libtalloc のインストール用スクリプト][LIBT]を参考にしました。

ここで、 Debian noroot 環境の実現の中心を担う [proot][PROT] を開発した STMicroelectronics 社及び proot に link2symlink の機能を実装した [Termux の開発コミュニティの皆様][TMUX]に心より感謝致します。

次に、 [link2symlink の機能を実装した proot][TMPR] の各種不具合の修正については、 [GNURoot の開発コミュニティによる proot][GRPR] のソースコード及び、その中の [Dieter Mueller 氏による特定のプレフィックスを持つファイルを不可視化するコードである ```hidden_files.c```][SRC1] を参考にしました。 Dieter Mueller 氏及び [GNURoot Debian の開発コミュニティ][GNUR]の各氏に心より感謝致します。

そして、 [Android OS 6.0][ANDR] が動作する実機による [link2symlink 機能を実装した proot][TMPR] の動作確認に関しては、 [Uhucream 氏][UHUC]による多くの協力を得ました。 [Uhucream 氏][UHUC]に心より感謝致します。

最後に、 [Debian noroot 環境][DBNR]と [Android OS][ANDR] 及び [Debian 環境][DEBI]の全ての事に関わる全ての皆様に心より感謝致します。

# 追記及びお断り

## 2018/01/15 現在の追記

[link2symlink 機能を実装した proot][TMPR] に関して、 [Android OS 6.0][ANDR] 及び [Android OS 7.0][ANDR] が動作する実機による正常な動作が確認されたことに伴い、本稿の大幅な改稿を行いました。

"[結論][CHAP04]" の章において述べた通り、実機における動作確認について多大なる協力を頂いた [Uhucream 氏][UHUC]に心より感謝致します。

## 2018/03/16 現在の追記

[link2symlink 機能を実装した proot][TMPR] にビルドに関して、 [Android NDK][ANDK] によるクロスコンパイル環境の構築について、本稿に追記しました。

また、 [link2symlink 機能を実装した proot のビルドを自動化する Makefile のリポジトリ][PRBU]において、 Makefile を完全に Ruby スクリプトに書き換えると共に、 [talloc][TLOC] 及び [proot][PROT] を最新のバージョンに更新したことに伴い、本稿を改稿致しました。どうか御了承下さい。

## 2018/04/02 現在の追記

複数の誤字等の訂正を行いました。どうか御了承下さい。

## 2018/06/05 現在の追記

[link2symlink 機能を実装した proot][TMPR] の安定版を最新版に更新した事と、 [link2symlink 機能を実装した proot][TMPR] において、 [Debian noroot][DBNR] 環境における外部ストレージ領域及び VFAT 領域等の、シンボリックリンクに対応していないファイルシステムの領域において、システムコール [link(2)][LINK] を実行した場合に問題が発生する不具合を修正した事に伴い、本稿を改稿致しました。

どうか御了承下さい。

## 2018/06/12 現在の追記

[link2symlink 機能を実装した proot][TMPR] の安定版を最新版に更新した事と、 [proot][PROT] の [link2symlink 機能][TMPR]の動作原理に変更が生じた事に伴い、本稿の改稿を行いました。どうか御了承下さい。

## 2018/06/30 現在の追記

[link2symlink 機能を実装した proot][TMPR] の最新の安定版のリンクに誤りが有りましたので、ここに御詫びして訂正致します。この度は、誠に恐れ入ります。

また、 [link2symlink 機能を実装した proot][TMPR] の安定版において、一部端末での動作の不具合が発見されたことに伴い、 [Debian パッケージ][DEBI]によるクロスコンパイルを用いてビルドした [proot][PROT] の実行形式ファイルを併せて公開致しました。

上記の件に関しまして問題の御報告を頂きました、[おやすみ様][OYAS]には、誠にお手数をお掛けしますと共に、心より感謝致します。

## 2018/07/05 現在の追記

[link2symlink 機能を実装した proot][TMPR] の各種不具合を修正し、安定版を最新版に更新した事に伴い、本稿の改稿を行いました。

"[謝辞][CHAP05]" の章において前述した通り、 [link2symlink 機能を実装した proot][TMPR] の各種不具合に修正にあたっては、 [GNURoot Debian の開発コミュニティによる proot][GRPR] のソースコードを参考にしました。参考にしたコードの作者である Dieter Mueller 氏を始め、 [GNURoot Debian の開発コミュニティ][GNUR]の各氏には心より感謝致します。

また、 "[proot のビルド][SEC0103]" の節でも前述した通り、 **[link2symlink 機能を実装した proot][TMPR] の最新の安定版では、 link2symlink 機能に関する各種問題を修正していますので、 [link2symlink 機能を実装した proot][TMPR] の実行形式ファイルは、最新の安定版を使用することを強く御勧めします。**

## 2018/07/26 現在の追記

[proot][PROT] 及び [talloc][TLOC] のソースコードを最新版に更新したことにより、 [link2symlink 機能を実装した proot][TMPR] の安定版を最新版に更新した事に伴い、本稿の改稿を行いました。

## 2018/08/19 現在の追記

[proot][PROT] のソースコードを最新版に更新したことと、 [proot][PROT] のソースコードのコンパイル時に発生する問題の修正を行ったことにより、 [link2symlink 機能を実装した proot][TMPR] の安定版を最新版に更新した事に伴い、本稿の改稿を行いました。

## 2018/09/25 現在の追記

[proot][PROT] のソースコードの最新版への更新と、 [proot][PROT] のソースコードへの各種修正を行ったことにより、 [link2symlink 機能を実装した proot][TMPR] の安定版を最新版 v5.1.0.109 に更新した事に伴い、本稿の改稿を行いました。

## 2019/06/04 現在の追記

[proot][PROT] のソースコードの最新版への更新と、 [proot][PROT] のソースコードへの各種修正を行ったことにより、 [link2symlink 機能を実装した proot][TMPR] の安定版を最新版 v5.1.0.112 に更新した事に伴い、本稿の改稿を行いました。

<!-- 各章及び各節へのリンク一覧 -->

[CHAP00]:#はじめに
[CHAP01]:#link2symlink-機能を実装した-proot-のビルド
[CHAP02]:#proot-の導入
[CHAP03]:#proot-の動作確認
[CHAP04]:#結論
[CHAP05]:#謝辞
[SEC0101]:#クロスコンパイル環境の構築
[SEC0102]:#talloc-2110-のビルド
[SEC0103]:#proot-のビルド
[SEC0104]:#proot-のビルドの自動化-Ruby-スクリプト
[SUBSEC010101]:#debian-パッケージによるクロスコンパイル環境をインストールする手法
[SUBSEC010102]:#android-ndk-によるクロスコンパイル環境をインストールする手法

<!-- 外部リンク一覧 -->

[DBNR]:https://play.google.com/store/apps/details?id=com.cuntubuntu&hl=ja
[ANDR]:https://www.android.com/intl/ja_jp/
[DEBI]:https://www.debian.org/index.ja.html
[AN6L]:https://github.com/pelya/debian-noroot/issues/8
[LINK]:http://man7.org/linux/man-pages/man2/link.2.html
[SYML]:http://man7.org/linux/man-pages/man2/symlink.2.html
[TMUX]:https://termux.com/
[PROT]:https://proot-me.github.io/
[TMPR]:https://github.com/termux/proot
[UBUN]:https://www.ubuntu.com/
[ARMP]:https://www.arm.com/
[TLOC]:https://talloc.samba.org/talloc/doc/html/index.html
[QEMU]:https://www.qemu.org/
[GITH]:https://github.com/
[ANDK]:https://developer.android.com/ndk/index.html?hl=ja
[TANJ]:https://qiita.com/tanjo
[QTNJ]:https://qiita.com/tanjo/items/0c6549c6700160d5595b
[BREW]:https://linuxbrew.sh/
[CASK]:https://caskroom.github.io/
[DIF1]:https://github.com/z80oolong/proot-termux-build/blob/master/proot-termux-fix.diff
[GNUR]:http://corbinlc.github.io/GNURootDebian/
[GRPR]:https://github.com/corbinlc/GNURootDebian/blob/master/GNURootDebianSource/src/main/build_rootfs/PRoot
[SRC1]:https://github.com/corbinlc/GNURootDebian/blob/master/GNURootDebianSource/src/main/build_rootfs/PRoot/src/extension/hidden_files/hidden_files.c
[PRBU]:https://github.com/z80oolong/proot-termux-build/
[READ]:https://github.com/z80oolong/proot-termux-build/blob/master/README.md
[PARM]:https://git.io/proot-5.1.0.112.arm
[PX32]:https://git.io/proot-5.1.0.112.x32
[XARM]:https://git.io/proot-5.1.0.112-cross.arm
[XX32]:https://git.io/proot-5.1.0.112-cross.x32
[DNBK]:http://qiita.com/z80oolong/items/0049269559270ccc68bd
[PELY]:https://github.com/pelya
[LNZN]:http://linux2.g.hatena.ne.jp/lnznt/
[LBLG]:http://linux2.g.hatena.ne.jp/lnznt/20120527/1338097961
[KMCK]:http://blog.kmckk.com/
[KBLG]:http://blog.kmckk.com/archives/4165115.html
[LIBT]:https://github.com/termux/termux-packages/blob/master/packages/libtalloc/build.sh
[UHUC]:https://qiita.com/Uhucream
[OYAS]:https://twitter.com/oyasumi_asap