假设我们有一个静态链接的Linux可执行文件。
我应该如何在导入的tar.gz中命名它,以便WSL1在创建和启动时默认运行它,如:
# import an archive as a WSL distro
wsl --import static tmp-root-dir static.tar.gz
# boot distro to a default app??
wsl -d static
PSWSL使用自己的专有引导过程,似乎不使用传统的Unix/sbin/init
。
简短回答:
最小的可引导(没有错误或警告)WSL rootfs将由三个文件组成:
/main
:静态链接的应用程序。只要名称与passwd
中的名称相匹配,就可以随心所欲地命名它/etc/passwd
:定义要为默认用户加载的应用程序(即shell)/etc/wsl.conf
:抑制正常的WSL功能并(可选)定义非根用户
更多详细信息:
这可能不是你想要的,但它有望满足你的需求。
首先,WSL(第一次在实例中启动Linux ELF二进制文件)的入口点似乎是它的/init
二进制文件,除了一些";正常的";Linux初始化进程任务,设置一些Windows互操作功能。据我所知,目前无法改变。据我所知,对于WSL1,它是由LXSS管理器在启动WSL实例时注入到实例中的。
注意:WSL2在这方面可能略有不同,因为它似乎确实使用了内核处理的initrd来加载/init
。可以覆盖内核命令行,但这会影响所有WSL2实例,因此这可能不是一个实用的解决方案。
从你的问题中还不太清楚你是否想要";默认应用程序";至:
- 每次运行
wsl -d static
时作为默认应用程序/shell运行,即使它已经在运行 - 或者在第一次启动WSL1实例时只运行一次
我相信你正在寻找第一种选择。
作为默认应用程序运行
在第一种情况下,标准的WSL1/init
进程可能会让您到达需要的位置。正如您所期望的,作为启动的一部分,它读取/etc/passwd
以确定要启动的用户shell。它还读取/etc/wsl.conf
以确定默认用户ID(但如果wsl.conf
中没有设置默认用户,则返回注册表)。
因此,要启动一个不同的应用程序(让我们称之为main
),您可以:
-
将二进制文件放在映像的根目录中。
-
将应用程序设置为";外壳;根用户的单行
/etc/passwd
:user:x:1000:1000:user:/:/main
需要注意的是,这还将主目录设置为
/
,这样我们就不必创建另一个目录。 -
定义具有以下内容的
etc/wsl.conf
:[user] default=user [automount] enabled=false mountFsTab=false [interop] appendWindowsPath=false
这将阻止WSL执行以下启动任务,这将在没有额外图像支持的情况下产生错误:
- 将Windows驱动器装入实例
- 正在尝试处理
/etc/fstab
(因为映像中没有mount
命令) - 追加Windows路径(因为我们的实例无法访问Windows驱动器)
它还将默认用户设置为我们在
/etc/passwd
中创建的UID 1000用户。这并不是绝对必要的——在这个一次性实例中以root用户身份运行可能没有什么问题,但我已经将一个非root用户作为"root"用户包括在内;最佳实践";。
应该是这样。最小的可引导WSL rootfs将仅由以下三个文件组成:
/etc/wsl.conf
/etc/passwd
/main
这将适用于WSL1和WSL2,尽管对于WSL2,您应该使用wsl ~ -d static
进行调用,以确保它不会试图在无法访问的Windows驱动器上启动。否则,您将收到一个init错误,但您的应用程序仍将被调用。
运行一次
例如,如果您正在寻找能够在实例第一次启动时启动守护进程的东西,那么我在这个答案中记录了一些替代方案。如果你使用的是Windows 11,那么有一个通过/etc/wsl.conf
的内置机制。否则,在Windows10上,您可能需要包含一些可以处理条件逻辑的二进制文件。像execline这样的东西可能非常适合这一点,但至少我在WSL2下遇到过问题,我不确定它是否会在WSL1下运行(但它可能)。
WSL1/musl的旁注
musl是一种常用的替代libc实现。例如,Rust(AFAICT)只能使用musl生成真正静态链接的可执行文件。但是,请注意,WSL1不能运行基于musl的静态链接二进制文件。
WSL2可以很好地处理它们。
我设法让它工作起来。最初,在创建TAR档案时,我错过了应用程序上的一个可执行部分。
以标准64位组件为例:
.data
msg:
.ascii "Hello, world!n"
.set len, . - msg
.text
.globl _start
_start:
# write
mov $1, %rax
mov $1, %rdi
mov $msg, %rsi
mov $len, %rdx
syscall
# exit
mov $60, %rax
xor %rdi, %rdi
syscall
并创建一个最小的WSL系统:
wsl as -64 -o minimal.o minimal.s
wsl ld -melf_x86_64 -o minimal minimal.o
tar czf minimal.tar.gz
--mode=a=rx
--xform='s#^minimal#/ #' minimal
wsl --import minimal rootfs-minimal minimal.tar.gz --version 1
wsl --list
wsl -d minimal -e /minimal
要使可执行文件默认(将wsl -d minimal -e /minimal
缩短为wsl -d minimal
),我们需要一个额外的文件/etc/passwd
:
root:x:0:0:root:/root:/minimal
此文件的第一行确定默认用户,因此确定可执行文件的路径(入口点),除非您用/etc/wsl.conf
:覆盖用户
[user]
default=user
基本上,WSL1只将2个文件视为神奇的(除了忽略/sbin/init
之外):
/etc/wsl.conf
/etc/passwd