James Wang's Blog

All about Microsoft Azure

初探Bash on Ubuntu on Windows及Linux子系統(WSL)介紹

Windows Subsystem for Linux

今年三月底在舊金山的 //Build 開發者大會展示了 Bash on Ubuntu on Windows,透過與 Canonical 合作開發的Windows Subsystem for Linux (WSL) 讓原生的 bash 及眾多 Linux 程式可以直接執行在 Windows 10 上,雖然目前還是beta 版但藉由廣大使用者測試以及意見回饋,相信這項功能可以變得更佳穩定且完整。在 Windows 10周年(Redstone) 更新之際,想藉由這篇文章和大家介紹 Bash on Ubuntu on Windows 同時分享使用上的一些心得。

Bash on Ubuntu on Windows是什麼?

Bash 是大部分 Linux distro 預設的 shell,也是一般 Unix/Linux 使用者所熟悉的介面,透過 bash 可以方便使用shell script 及 GNU tools。雖然 Windows 上有 Powershell 等強大 shell 環境,但如果開發遇到上需要用到 Linux 環境或工具的時候,只能開 Linux VM、連線遠端主機,或是打開 Cygwin terminal。而現在 Bash on Ubuntu on Windows 的出現,讓開發者可以在 Windows 環境下執行原生的 bash,在 Windows 10上開發時既可以使用 Windows 的工具,也可以使用 Linux 生態系的各種工具,減少開發時在不同工具不同平台間切換造成額外的負擔(“Remove a bit of friction from developers’ dialy workflow" by Pete Brown)。
不同於透過 VM 把程式跑在 Linux系統上,以及Cygwin把基本的 Unix 指令包在 cygwin1.dll 內跑在 Windows 系統上,Bash on Ubuntu on Windows 則是在 Windwos NT kernels 加入 Windows Subsystem for Linux(WSL)實作 linux system calls,所以不必透過虛擬機(VM)或是透過 Linux kernel 的重新包裝,user mode 的程式透過 WSL 可以如同跑在 Linux 上直接執行原生 ELF64 執行檔,比起 VM 相對輕量快速而且更方便共用檔案目錄,比起Cygwin則擁有更完整的套件管理,可以透過 apt/apt-get 管理套件及或是執行原有 Linux 套件。
若為初次安裝時在"執行(Run)"輸入"optionalfeatures",開啟"Turn Windows Features On or Off"視窗,勾選"Windows Subsytem for Linux(beta)"便可透過命令列執行bash.exe及lxrun.exe來設定及使用WSL。lxrun.exe用來設定Ubuntu環境,指令如下:

lxrun /install
lxrun /uninstall
lxrun /uninstall /full

完整移除 WSL (包含 /root 及 /home)

lxrun /setdefaultuser (username)

設定開啟 Bash 預設登入使用者(若使用者不存在,則創建新使用者及其家目錄)

lxrun /udate

更新 WSL 套件

bash.exe 本身是隻 win32 程式用來作為 Bash on Ubuntu on Windows 的入口,接著啟動 lxss manager service 來和 Kernel mode 的 lxss, lxcore 溝通,lxss 的主要作為 user mode linux 程式及 kernel mode NT kernel 溝通的橋樑,接著再啟動 init 及 /bin/bash 等等 Linux instance,便進入到熟悉的原生 Bash shell。

LXSS-diagram-1024x472

syscalls

WSL System call(系統呼叫)

User mode的程式若要和系統核心(kernel)溝通必須透過系統呼叫(syscalls)。Linux/WindowsNT 兩種系統在 user mode與kernel mode 之間介面 (Application Binary Interface, ABI) 的差異則是由 lxss.sys(Pico drivers)來解決,lxss.sys 本身本身不包含 Linux kernel code 而僅僅作為ABI的轉換介面,收到來自NT kernel請求時以及暫存器的狀態lxss.sys會處理完相對應的linux syscall會跳回NT kernel把回傳值放到正確的暫存器再跳回user mode。例如上圖在bash中ls會調用getdents來取的檔案目錄資訊,而 NT kernel 則有對應的 NtQueryDirectoryFile,因次lxss.sys 處理完暫存器位置後可以直接調用。我們可以把 Linux syscalls,依照與 NT syscall 的對應關係分為以下三大類﹔

  • 有 NT syscalls 可以直接對應,只需依照 ABI 做對應處理後直接調用。例如:getdents/NtQueryDirectoryFile,sched_yield / ZwYieldExecution。
  • 有功能類似的 NT syscalls,但因為性質差異太大而沒辦法直接做對應,WSL 仍需要自己實作 syscalls。例如:pipe。
  • 沒有直接對應的NT syscalls,WSL 自己實作 syscalls。例如:fork,Windows 沒有與 fork 對應的功能。這時WSL 需要透過 NT 內部 API 創建一個擁有相同暫存器內容的新的執行緒來來完成 fork syscalls。

Linux kernel 共有約300個 syscalls,而目前 WSL 約完成235個 linux syscalls,陸續的更新可以參考 WSL Release Notes

WSL File System(檔案系統)

fs

WSL 透過虛擬檔案系統(Virtual File System, VFS)整合NTFS以及其他linux使用的檔案系統,同時提供Linux檔案系統權限等功能支持。
VolFs

VolFs 主要使用在Linux系統檔案以及家目錄,並支援權限/symbolic link/FIFO等操作,Linux檔案系統會掛載在%LocalAppData%\lxss\rootfs之下(%LocalAppData%是隱藏資料夾,預設路徑在C:\Users\%UserName%\Appdata\Local),因為是在各自Windows使用資料夾之下,所以安裝套件等環境設定也不會影響到其他使用者。值得注意的是\root以及\home 則是分別另外掛載在%LocalAppData%\lxss\root及%LocalAppData%\lxss\home之下,這樣設計目的在於解除安裝WSL時,可以選擇保留root資料夾以及home資料夾(lxrun /uninstall,若要全部移除則執行lxrun /uninstall /full)。
目前還不完全支援Windows程式對VolFs的檔案存取修改,例如用檔案總管在%LocalAppData%\lxss\home\user下建立新資料夾,bash中ls會無法看到創建的資料夾;或是在沒有開啟bash的情況下用Windows程式編輯檔案,重新啟動時那個檔案會從會從VolFs消失等等。總之,VolFs是用於Linux系統檔案盡量不要從Window程式進去更改。

DriveFs(DrvFs)

另外要注意的是在 WSL 中的 root 權限,root 權限只會影響linux檔案系統下的權限,對於 Windows檔 案操作是受限於 bash.exe 的權限的,假設想改某些其他 Windows 使用者資料夾檔案或是 Windows系統檔案只有 root 權限是無法的,要透過 administrator 權限打開 bash.exe 才能做到。舉例來說,使用管理員權限權限開啟bash.exe 可以透過 ls /mnt/c/Users/Administrator 檢視 admin 資料夾,但一般權限開啟的 bash 即便透過sudo ls /mnt/c/Users/Administrator 也檢視權限,因此在管理員權限開啟 bash 操作 Windows 檔案系統時要特別注意(例如在rm -rf之前千萬要三思)。

sudoadmin

動手玩 Bash

      • 使用 Zsh 或是其他 shell
        如果還是習慣用 zsh 或是其他 shell,可以透過 .bash.rc的設定讓 Bash on Ubuntu onWindow 開啟 bash.exe 時直接開啟進入的shell,以zsh為例﹔

        sudo apt-get install zsh
        Vim ~/.bashrc
        輸入
        # Launch Zsh
        if [ -t 1 ]; then
        exec zsh
        fi
      • X11-apps
        雖然 WSL 最初目的在減少在工具間切換方便開發,並非為圖形化桌面(Gnome,KDE 等等)而設計,但我們還是可過 X11-Forwding 在 Linux 子系統執行圖形化程式。這邊我們安裝Xming作為Windows上的X server,在 bash 中 export DISPLAY=:0 重新導向後,便可以開啟 x11-apps 或是其他圖形化程式。

x11_apps

更多WSL的資訊請參考WSL MSDN Blog,使用遇到的問題可以在Github頁面回報,或是在Windows developer feedback 發表回饋與建議讓WSL可以帶來更好的使用與開發體驗。