Interoperability Windows Subsystem for Linux Lead image: Lead Image Craig Whitehead on Unsplash
Lead Image Craig Whitehead on Unsplash
 

Hands-on test of Windows Subsystem for Linux

Undercover

If you don't want to do without the main advantages of Linux on the Windows platform, the Windows Subsystem for Linux offers another option. We delve the depths of the Linux underworld and explain how you can optimize the subsystem. By Andreas Möller

The new Linux subsystem [1] has been around since the Windows 10 Creators Update; according to Microsoft, it can get by without a resource-consuming virtual machine (VM) and configuration. It is also said to offer a more native Linux feeling than the previous Cygwin [2] Linux environment. Linux users have used Cygwin on Windows for years, for example, to automate processes with shell scripts (e.g., mass Git checkouts), but it does mean recompiling Linux programs for Windows.

A look at the subsystem is worthwhile because of the surprisingly lightweight, process-based virtualization concept that just might catch on. In this article, I explain the limitations of the subsystem compared with native Linux and Cygwin, and I offer a number of customization tips that help make the subsystem fit for everyday use.

Installation

Users of Windows 10 Professional, at least, will be able to pick up the Linux subsystem easily. The subsystem runs natively on Windows and does not require an additional VM. If you do not want to create a Microsoft account during the install, you can install Ubuntu 16.04 LTS directly by using Windows PowerShell. As an administrator, the command

Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux

prepares Windows for installing the subsystem (Figure 1, top). Next, select Settings | Update & Security | For developers to enable Developer mode (Figure 2). Once the installation is complete, type bash to display the prompt (Figure 1, bottom). Like all applications under Windows, the bash shell shown in Figure 3 is launched from the Start menu by calling bash.exe.

Easy to confuse: PowerShell is at the top, the prompt at the bottom.
Figure 1: Easy to confuse: PowerShell is at the top, the prompt at the bottom.
Windows users have to enable developer mode.
Figure 2: Windows users have to enable developer mode.
The Linux shell on Windows at least feels native.
Figure 3: The Linux shell on Windows at least feels native.

Home Is Home

After double clicking on bash.exe, you will find yourself in a Linux shell with an Ubuntu environment. Even the Apt package manager is there waiting for you. Windows saves the subsystem files under C:\Users\<pa>\AppData\Local\lxss. Conversely, Ubuntu mounts Windows under /mnt/c.

To save typing and avoid redundant data structures, it is best to merge the Linux and Windows home directories first. For this purpose, change the path to your Linux home directory in the /etc/passwd file so that it points to your Windows home /mnt/c/users/<pa>. The Vi editor, which you call by typing sudo vi /etc/passwd, helps you do this on Windows. After restarting Bash.exe, you land directly in the Windows home directory.

Startup Problems

Differences from a native Linux system are already apparent with the use of a user-specific C:\Users\<pa>\AppData\Local\lxss path: In contrast to the normal procedure, the services that Ubuntu usually links in the /etc/init.d directory do not start up automatically at boot time. They also terminate along with the shell. Although the Apache web server can be configured in the usual way, you have to boot it manually every time. After closing Bash.exe, it cannot be reached at all.

A command to register a Linux service under Windows (e.g., cygrunsrv under Cygwin) does not yet exist for the new subsystem. However, you can live with this restriction, because you will always open a shell to start work.

Peculiar Permissions

Other peculiarities await. All files below /mnt/c belong to root. Changes to user rights with chmod and chown are ineffective. This handicap does not seriously disrupt usability, however, because you can freely create and delete files and directories in your subsystem.

However, if you want to transfer user rights for files during a data transfer, it has to be set up during or after the transfer. Rsync offers a solution for this:

rsync --perms --chmod=+wrx,go-w index.html server:/var/www

The perms parameter makes sure that the synchronization tool also transfers the directory rights. In the first step, chmod sets all rights for the user, the owner group, and everyone else using +wrx. In the second step, the go-w expression deprives the group and others of write permissions. In this way, the transferred file (here, index.html) receives the rwxr-xr-x permissions. Incidentally, Rsync uses filters to distinguish between directories (D) and files (F). An additional F-x expression as the third element in the comma-separated list would eliminate the ability of all files to be executed.

If you would prefer to use your own SSH key, the script in Listing 1 backs up the SSH key and config files from your home directory into the /etc/ssh folder. If you do without the script, calling the ssh myserver command throws up the Bad owner or permissions on /mnt/c/users/<pa>/.ssh/config error message.

Listing 1: Adapting SSH

01 #!/bin/bash
02 cd ~
03 if [ -d .ssh ]; then
04   tar cf ssh.tar .ssh
05   for keyfile in `grep -le 'BEGIN .* PRIVATE KEY' -e '^ssh-' .ssh/*`; do
06     filename=`filename $keyfile`
07     mv $keyfile /etc/ssh
08     chmod 644 /etc/ssh/$filename
09   done
10   if [ -f .ssh/config ]; then
11     cat .ssh/config >> /etc/ssh/ssh_config
12     sed -i 's|~/.ssh|/etc/ssh|g' /etc/ssh/ssh_config
13     rm -f .ssh/config
14   fi
15 fi

At the end, back up Listing 1 as the file ssh-extend.sh and call it – also in the shell – with the sudo bash ssh-extend.sh command. In line 2, the script initially switches to the home of the user. If any content exists in the ~/.ssh folder, line 4 saves it using the tar archive command. The for loop iterates over all the files that the grep expression identifies as key files.

The character strings after the -e switch work as regular search patterns. Line 7 moves a key file to /etc/ssh each loop run; line 8 sets appropriate access rights.

Assuming ~/.ssh/config is available, the script transfers the settings of this configuration file into the global SSH configuration file. In line 11, the script attaches the found entries to the end of the /etc/ssh/ssh_config file using the >> operator. The sed command then uses search and replace to replace the ~/.ssh path prefix with /etc/ssh. Because the Linux subsystem is in the Windows users directory, there is no threat of a breach of security from the transfer of key files in the subsystem. SSH can then be used in the shell as usual.

Nuclear Fission

The limitations of the subsystem should be a lot greater for programs that have access to kernel features, because the Linux subsystem has to make do without the Linux kernel. However, Linux processes run in a new process type called Pico [3] in the Windows user space (Figure 4). Windows translates kernel calls from the Pico process through Pico providers Lxss and LxCore into calls to the Windows kernel and forwards them transparently.

Pico processes take a route for kernel calls different from native Windows processes.
Figure 4: Pico processes take a route for kernel calls different from native Windows processes.

You can check how well this works with the Docker container solution. Similar to Cygwin, the Creators Update makes it possible to call .exe files from the Shell. If you install Docker under Windows and .bashrc in the home directory and then add the Bash code from Listing 2, the Docker commands can be used after restarting the shell, as in Linux. The for loop frees all .exe files from their file extensions and connects them to the Linux world with an alias.

Listing 2: Configuring Docker

DOCKER_BIN='/mnt/c/Program Files/Docker/Docker/resources/bin'
for f in "$DOCKER_BIN"/*; do
  alias "$(basename "$f" | sed 's/.exe$//')" '="'"$f"'"'
done

Only the interactive terminal mode (option -t, as in the docker run -it debian bash command) fails, because Bash cannot interpret the Windows terminal protocol. Creating an appropriate pseudo-terminal with

sudo /sbin/MAKEDV -v pty

also failed in the test. Under Cygwin, the winpty command helps achieve the desired result [4].

What a Shame: Paths

Windows and Linux use different path schemes to address resources within their directory tree. With Subversion, for example, you can check a working copy of the repository document with the file:///C/Users/<pa>/svn/documents Windows path.

However, a subsequent attempt to update the working copy with the svn update Bash command fails, because Linux cannot cope with the source path.

This class of issues is sometimes fixed with a diversion into the network world, because Linux and Windows analyze URLs in the same way. Under Subversion, the command

sc create svnserve binpath= "\"C:\Program Files\TortoiseSVN\bin\svnserve.exe\" --service -r C:\User\<pa>\svn" displayname= "Subversion Server" depend= Tcpip start= auto

entered with administrative privileges initially registers the internal svnserve server as a Windows service. The sc start svnserve command starts the service; then, check out a working copy by URL:

svn checkout svn://localhost/documents

This time, Subversion is working in both worlds.

Be aware that to write data, you need to add the anon-access = write line to the conf/svnserve.conf file in the root directory of the C:\User\<pa>\svn repository.

Domain Sockets

Implementing Domain sockets only seems to working partially according to a blog post [5]. The attempt to create such a socket with

sudo nc -U /var/tmp/sockted

fails with nc: unix connect failed: No such file or directory.

Similar to the path problem, the solution here is to run interprocess communication via TCP/IP, as in the case of the D-Bus system. If you are not afraid of a bit of extra work, you will find another blog post on this topic online [6]. To sum up, you need to install an X server such as vcxrc or Xming, add the export DISPLAY=:0.0 entry to .bashrc, and use the command

sudo sed -i 's$.*$tcp:host=localhost,port=0$' /etc/dbus-1/session.conf

to tell D-Bus to communicate via TCP/IP. Then, Firefox launches and – so people claim – the Ubuntu desktop too.

Conclusions

The Windows Subsystem for Linux shows a lightweight, container-based virtualization approach that relies on its own process class. In practice, there is a still scope for improvement, if you want to work with Linux in the usual way or require at least the level of maturity that Cygwin already has. However, a few simple steps help to create a system fit to work and harmonize with the Windows superstructure. It remains to be seen whether Microsoft is willing to complete its subsystem.