Bash on Ubuntu on Windows: Windowsのドライブに名前付きパイプは作れるか

> # :no_entry:消費期限切れ
> この記事は古くなりすぎて程よく腐敗しています．
> 最新版ではこのページでできないと言っていることが出来るようになっています．
> 追従して記事をUpdateしたいところですが，そのような殊勝な心がけは全く持ち合わせていません．
> 最新版の情報を探しましょう

# まえがき
勝手に再起動しまくったりアップデートの催促がウザくて事あるごとに憤慨させてくれるSurfaceのWindows 10にAnniversary Updateが入って，噂のBashやらUbuntuがうごく機能が使えるようになった(なってた)．

昨今積極的にWindowsを使う理由はミジンコの糞ほどもないのだが，たま～にどうしてもWindowsじゃないと辛いという事象が発生する[^hoge]のもまた事実．
Cygwinだとスペシャルファイル周りなだ辛い部分があったので，そこらへんがどこまで動くのか興味が湧いたのでちょびっと弄ってみた．

[^hoge]: なんでUnicodeといいつつUTF-16なんだよ！SJISとか馬鹿か？とか愚痴りながらWindowsで魔改造されてぶっ壊れたファイルを治すとか，一部の危ない文字が似ているが非なる文字なって帰ってくるとか，BOMの有無でもって各所で爆発が起きたり，CRLFが邪魔だとかいろいろあって，Windowsマシン全部窓から投げ捨てろ！みたいな微笑ましい光景が幾度と無く繰り返されて僕は疲れましたパトラッシュ．

## インストール
[ググレカス](https://www.google.co.jp/search?q=how+to+install+bash+on+ubuntu+on+windows)

## 本当にUbuntuなんだろうか？

```bash
$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.04
DISTRIB_CODENAME=trusty
DISTRIB_DESCRIPTION="Ubuntu 14.04.4 LTS"
```
まごうことなきUbuntuであった．

# Windonw領域のFile I/O
## Windowsの領域から読み込む
```text
hello!
ァゼソゾタダチボポマミ
АЪЫЬЭЮЯклмн
```

というテキストファイルをC:\直下に保存．Bash on Ubuntu on Windowsで見てみると．．．

```text
$ file /mnt/c/test.txt
/mnt/c/test.txt: Non-ISO extended-ASCII text, with CRLF line terminators
$ cat /mnt/c/test.txt
hello!
�@�[�\�]�^�_�`�{�|�}�~
�@�[�\�]�^�_�`�{�|�}�~
```

予想通りな感じで，特に感動はありませんね．

Windowsのファイルシステムをマウントしてのファイルの読み込みに関しては，/mnt配下に自動でマウントされている以外は，従来のVMやコンテナとほとんど変わらないようです．

## パーミッション
WindowsとLinuxはファイルパーミッション方式に関して互換性というものを微塵も感じさせない．相容れないファイルシステムを他方に直接マウントした場合，大抵パーミッションが火を噴く．というわけで早速見てみた．

```text
$ ll /mnt/c
ls: cannot access hiberfil.sys: Permission denied
ls: cannot access pagefile.sys: Permission denied
ls: cannot access swapfile.sys: Permission denied
total 140
drwxrwxrwx 2 root root  0 Aug  8 07:08 ./
drwxr-xr-x 2 root root  0 Jan  1  1970 ../
-r-xr-xr-x 1 root root  1 Oct 30  2015 BOOTNXT*
-????????? ? ?    ?     ?            ? hiberfil.sys
drwxrwxrwx 2 root root  0 Nov 27  2015 Intel/
drwxrwxrwx 2 root root  0 May  4 02:02 OneDriveTemp/
-????????? ? ?    ?     ?            ? pagefile.sys
d--------- 2 root root  0 Jul 16 20:47 PerfLogs/
drwxrwxrwx 2 root root  0 Aug  6 20:21 ProgramData/
dr-xr-xr-x 2 root root  0 Aug  6 19:53 Program Files/
dr-xr-xr-x 2 root root  0 Aug  8 07:04 Program Files (x86)/
...
```

- ディレクトリ: 777
- アクセスできるファイル: 777
- 権限が無いファイル: 555
- クリティカルなシステムファイル: ?????????

という豪快(simple?)なパーミッション．
?????????はBashから弄らせる気は全く無いようです．

## Windowsの領域へ書き込む
777ならザルじゃん，やったーって書き込んでみると，そう甘くなかった．

```bash
$ echo hoge > /mnt/c/hoge.txt
bash: /mnt/c/hoge.txt: Permission denied
```

777とはなにか \:anger:

じゃあrootなら行けるだろってことで

```bash
$ sudo echo hoge > /mnt/c/hoge.txt
bash: /mnt/c/hoge.txt: Permission denied
```

あっるえええ．．．

じゃあ，BashをAdminで起動してみよう．

```bash
$ echo hoge > /mnt/c/hoge.txt
$ cat /mnt/c/hoge.txt
hoge
```

あ，いけた．

察するに，Bash on Ubuntu on Windowsは一見するとLinuxだけど，実際はWindows上で動いている1プロセスなので，まずWindowsのファイルシステムとパーミッションがあって，その上でLinuxのパーミッションがあるという2層構造になっている．
だから，Bash on Ubuntu on Windowsでの/mnt/\<dirve\>以下のパーミッション表示は必ずしも正確ではなくて，Write権が付いていても場所によってはWindowsにハネられてしまうことがある．

## 名前付きパイプ
Cygwinでイマイチなスペシャルファイルはどうか．

```bash
$ mkfifo /mnt/c/bash_test/hoge_pipe
mkfifo: cannot create fifo ‘/mnt/c/bash_test/hoge_pipe’: Operation not permitted
```

おお，パイプも作れないとは情けない．

注： Ubuntuのファイルシステム領域だと名前付きパイプを作ることができて動くようだ．

## ソフトリンク
```
$ cd /mnt/c/bash_test/
$ ln -s /mnt hoge
$ ll
total 8
drwxrwxrwx 2 root root 0 Aug  8 09:14 ./
drwxrwxrwx 2 root root 0 Aug  8 08:56 ../
lrwxrwxrwx 1 root root 4 Aug  8 09:14 hoge -> /mnt/
```

リンクは貼れるらしい．

リンクファイルを含むリポジトリをチェックアウトしてここで修正したりしたらどうなるんだろうとか，```cp -rf```とかしたらどうなるんだろうかとか，興味は尽きません．


# デバイスファイル関連
## mount
だめだろうな．

```
$ mkisofs -r -J -V test_image -o image.iso /home/
I: -input-charset not specified, using utf-8 (detected in locale settings)
Total translation table size: 0
Total rockridge attributes bytes: 1614
Total directory bytes: 8192
Path table size(bytes): 70
Max brk space used 23000
198 extents written (0 MB)
$ ll
total 404
drwxrwxrwx 2 root root      0 Aug  8 09:42 ./
drwxrwxrwx 2 root root      0 Aug  8 08:56 ../
-rwxrwxrwx 1 root root 405504 Aug  8 09:42 image.iso*
drwxrwxrwx 2 root root      0 Aug  8 09:23 test_mount/
$ sudo mount image.iso test_mount/
mount: Could not find any loop device. Maybe this kernel does not know
       about the loop device? (If so, recompile or `modprobe loop'.)
```

だめっつうか，それ以前にKernelはloopデバイスなんて知らないとか悲しいこと言ってる．/dev はどうなっとるのかね．

```
$ ll /dev/
ls: cannot access /dev/lxss: Operation not permitted
ls: /dev/random: Invalid argument
total 8
drwxr-xr-x 2 root     root    0 Aug  8 05:18 ./
drwxr-xr-x 2 root     root    0 Jan  1  1970 ../
drwxr-xr-x 2 root     root    0 Aug  8 04:57 block/
lrwxrwxrwx 1 root     root   13 Aug  8 04:57 fd -> /proc/self/fd/
crw------- 1 root     root 0, 0 Aug  8 09:55 kmsg
c????????? ? ?        ?       ?            ? lxss
crw-rw-rw- 1 root     root 1, 3 Jan  1  1970 null
crw-rw-rw- 0 root     tty  5, 2 Aug  8 09:40 ptmx
drwxr-xr-x 0 root     root    0 Aug  8 04:57 pts/
crw-rw-rw- 1 root     root 1, 8 Aug  8 09:55 random
lrwxrwxrwx 1 root     root    8 Aug  8 04:57 shm -> /run/shm/
lrwxrwxrwx 1 root     root   15 Aug  8 04:57 stderr -> /proc/self/fd/2
lrwxrwxrwx 1 root     root   15 Aug  8 04:57 stdin -> /proc/self/fd/0
lrwxrwxrwx 1 root     root   15 Aug  8 04:57 stdout -> /proc/self/fd/1
crw------- 1 integral tty  4, 1 Aug  8  2016 tty
crw-rw-rw- 1 root     tty  4, 0 Aug  8 09:55 tty0
crw------- 1 integral tty  4, 1 Aug  8  2016 tty1
crw------- 1 integral tty  4, 2 Aug  8 09:55 tty2
crw-rw-rw- 1 root     root 1, 9 Aug  8 09:55 urandom
crw-rw-rw- 1 root     root 0, 0 Aug  8 09:55 zero
```

すっきりしてますな．これといってめぼしいデバイスがありません．lxssが魔法の何か．

## LXSS
Linux Subsystemで，これがBash on Ubuntu on Windowsのコアテクノロジーらしい．lxssについては自分の手に余るどころの話ではないので，詳しいことはググったり↓のサイトとか参照いただきたい．

- http://blog.ryukiy.net/2016/04/01/bash-on-windows/
- http://rcmdnk.github.io/blog/2016/06/05/computer-windows-ubuntu-bash/


で，Ubuntu上のファイルは(Windowsの)ホームディレクトリ以下の /AppData/Local/lxss/ にあるらしい．

```
$ ll /mnt/c/Users/ひみつ/AppData/Local/lxss/
total 912
drwxrwxrwx 2 root root      0 Aug  8 04:57 ./
drwxrwxrwx 2 root root      0 Aug  8 07:03 ../
-rwxrwxrwx 1 root root 911975 Aug  6 20:34 bash.ico*
d--------- 2 root root      0 Aug  6 20:34 cache/
d--------- 2 root root      0 Aug  6 20:34 data/
d--------- 2 root root      0 Aug  6 20:45 home/
d--------- 2 root root      0 Aug  6 20:34 mnt/
d--------- 2 root root      0 Aug  8 09:36 root/
d--------- 2 root root      0 Aug  6 20:34 rootfs/
-rwxrwxrwx 1 root root     64 Aug  6 20:32 sha256*
d--------- 2 root root      0 Aug  8 04:57 temp/
```

おお！パーミッションが000．ここは不可侵領域らしい．
ちなみに，lxssディレクトリはWindowsから見て500MBくらいでしたよ．

## ネットワークは？
### ネットワークスタック
LXSSの仕組みと /dev の様子から推測するに，ネットワークスタックは持っていなそうである．そんな気がする．

```
$ ip a
SO_SNDBUF: Invalid argument
$ ifconfig
Command 'ifconfig' is available in '/sbin/ifconfig'
The command could not be located because '/sbin' is not included in the PATH environment variable.
This is most likely caused by the lack of administrative privileges associated with your user account.
ifconfig: command not found
$ route
Command 'route' is available in '/sbin/route'
The command could not be located because '/sbin' is not included in the PATH environment variable.
This is most likely caused by the lack of administrative privileges associated with your user account.
route: command not found
```

ビンゴ！やはりネットワークはWindowsのものを利用するようだ．
ネットワークの使えないLinuxってツマンナクないですかね？:shit:

pingは面白い挙動をする．Run as Adminでないと動いてくれない．

```
# ユーザー権限でbashを起動した場合
$ sudo ping google.com
ping: icmp open socket: Permission denied
```

```
# Admin権限でbashを起動した場合
$ ping google.com
PING google.com (172.217.25.78) 56(84) bytes of data.
64 bytes from nrt13s50-in-f14.1e100.net (172.217.25.78): icmp_seq=1 ttl=53 time=12.7 ms
```

oh...:shit:



### Resolver
名前解決はUbuntu on Windows内で独自に持っているらしい．

```
$ cat /etc/hosts
127.0.0.1 localhost

# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
...
$ dig google.com

; <<>> DiG 9.9.5-3ubuntu0.8-Ubuntu <<>> google.com
;; global options: +cmd
;; Got answer:
...

```

### ネットワークソケット使うとどうなるのか？
```
$ python -m SimpleHTTPServer
Serving HTTP on 0.0.0.0 port 8000 ...
```

PowerShellから見ると，Windows上にポートが作成されていることがわかる．

```
PS C:\> netstat -na

Active Connections

  Proto  Local Address          Foreign Address        State
  TCP    0.0.0.0:22             0.0.0.0:0              LISTENING
  TCP    0.0.0.0:135            0.0.0.0:0              LISTENING
  TCP    0.0.0.0:445            0.0.0.0:0              LISTENING
  TCP    0.0.0.0:8000           0.0.0.0:0              LISTENING
  ...
```

# まとめ
## わかったこと
- Bash on Ubuntu on WindowsはLinux SubSystemという技術で実現されている
    - VMやコンテナではなく，LinuxバイナリをWindows Subsystemで動かす仕組み．やり方としてはCygwinに近い．
    - VMのように完全隔離されていない
    - Cygwinより総じて爆速である
- スペシャルファイルは動くものもあるが，対応していないものもあるので，低レイヤー全開で遊びたい人は期待しないほうがよいかも
- UbuntuにマウントされたWindows領域ではファイル操作に若干の制限がある
    - パーミッションは777，555，000，?????????
    - Ubuntu on Windowsという2層構造で微妙にWindowsが染み出している．
- Bash on Ubuntu on Windowsの本体は```C:\Windows\System32\bash.exe```
- Ubuntuのファイルは```/mnt/c/Users/<username>/AppData/Local/lxss/```にあるが，Windowsから弄れるが弄れない[^lxss]
- ネットワークはWindowsのものを使うので，Linuxの誇る**至高**のネットワーク機能はだいたい使えない:shit:
    - Resolverとかpingは微妙に使える

[^lxss]: こちらのサイトさんでいろいろ実験されてます．ケースセンシティブなファイル名はWindows上でどう解釈されるか他多数．http://rcmdnk.github.io/blog/2016/06/05/computer-windows-ubuntu-bash/

## 既知の未知
今回触ってみた過程で，疑問に思ったけど華麗に放置したトピック

- カーネルビルドとかできるのか？
- modprobeって動くのか？
- Ubuntu上からWindowsファイルシステムのパーミッションを変えたらどうなるのか？
- daemonはどこまでそれっぽく動けるか？
- Windowsバイナリ on Wine on Bash on Ubuntu on Windowsは動くのか
- lxssディレクトリのファイルはどのように管理されているのか？

## 感想
最初は名前付きパイプ動くんかな？というどーでもいい疑問だけだったんだけど，気がついたら朝だチュチュン:sleepy:

Bash on Ubuntu on Windowsは爆速キビキビでかなり本物のLinuxに近いというメリットはあるんだけど，BashからWindowsのコンソールを弄れない，WindowsからUbuntu上のファイルを直接弄れない(LXSSを経由する必要がある)という弱点もある．
WindowsとLinuxの相互乗り入れとしてはCygwinのほうが便利かなと思う．

Microsoft視点で見れば，爆発的な成長を見せたOSS界隈のリソースを取り込みたい，WindowsでもOSSを問題なく使えるというセールストークにしたい，という意図はすごくよく分かる[^だがしかし]．

しかしながら，VMやコンテナ，Cygwinと比べても抜きん出るところのない微妙な実装で，いまいちビビッと来る使い方が思いつかないというのが正直なところ．もう一捻りあれば化けそうな気もしなくもないので，今後に期待というあたりが落とし所でしょうかね．

[^だがしかし]: この意味ではMacのほうがはるかにOSSと親和性が高くて便利．

蛇足ですが，デフォルトでは例によってターミナルが糞すぎるので，ナイスなターミナルソフトから bash.exe を実行したほうがよい．

---