Skip to content

Releases: branchingjade/reboot-to-windows

Reboot to Windows 1.0.1

Choose a tag to compare

@branchingjade branchingjade released this 04 Oct 05:51

中文

修复:点了「重启进 Windows」只排队、不重启。

  • 根因:Decky Loader 是 PyInstaller onefile 程序,它给插件进程注入的 LD_LIBRARY_PATH 指向自己的 /tmp/_MEIxxxx/ 解包目录,里面自带一个旧版 libcrypto.so.3。插件后端以 root 直接调用 /usr/bin/systemctl reboot 时,动态加载器发现系统 libsystemd-shared 需要 OPENSSL_3.4.0,systemctl 在联系 logind 之前就中止了:

    /usr/bin/systemctl: /tmp/_MEI.../libcrypto.so.3: version `OPENSSL_3.4.0' not found
    (required by /usr/lib/systemd/libsystemd-shared-257.7-*.so)
    

    efibootmgr 不依赖 OpenSSL,所以设置 BootNext 一直成功 —— 于是只有一次性启动项被写好、机器却从不重启,面板看起来就像"已排队"。旧代码用裸 Popen、不读退出码,错误被完全吞掉还返回成功。

  • 修复:所有特权子进程(efibootmgr / systemctl)一律剥掉 LD_LIBRARY_PATH、LD_PRELOAD、LD_AUDIT、LD_DEBUG;重启改为回收子进程并校验退出码,直连失败自动回退 sudo -n(sudo 自身会清理环境),真失败以 reboot_failed 上报面板,不再假装成功。

  • 面板新增 reboot_failed 的中英文案(中文:「重启命令没有生效,本次切换未完成」)。

验证(SteamOS 213 实机,Decky Loader v3.2.10-pre1)

  • 复现对照:LD_LIBRARY_PATH=/tmp/_MEI… systemctl --version → rc=1 同一报错;剥掉该变量 → rc=0。
  • 部署后把 reboot 换成探针脚本实测:父进程 LD_LIBRARY_PATH 有毒时,子进程拿到的是干净环境;换成不存在的二进制时返回 {'ok': False, …} 而不是成功。
  • 用 Decky 自己的 loader/reload_plugin 重载后端:新进程以 root 启动,日志 loaded (euid=0, …, rule=already present)。

English

Fix: pressing "Restart into Windows" only queued the switch and never rebooted.

  • Root cause: Decky Loader is a PyInstaller one-file build. It exports LD_LIBRARY_PATH pointing at its own /tmp/_MEIxxxx/ bundle, which ships an older libcrypto.so.3. When the root plugin backend called /usr/bin/systemctl reboot directly, the dynamic loader saw that the system's libsystemd-shared needs OPENSSL_3.4.0 and aborted before systemctl ever reached logind:

    /usr/bin/systemctl: /tmp/_MEI.../libcrypto.so.3: version `OPENSSL_3.4.0' not found
    (required by /usr/lib/systemd/libsystemd-shared-257.7-*.so)
    

    efibootmgr does not use OpenSSL, so writing the one-shot BootNext kept succeeding — the boot entry was set, the machine never restarted, and the panel looked like it had merely "queued" the switch. The old code used a bare Popen, never checked the exit status, and reported success anyway.

  • Fix: every privileged child (efibootmgr / systemctl) now runs with LD_LIBRARY_PATH, LD_PRELOAD, LD_AUDIT and LD_DEBUG stripped; the reboot command is reaped and its exit status checked, a failing direct exec falls back to sudo -n (sudo sanitizes the environment itself), and a real failure is reported to the panel as reboot_failed instead of a silent success.

  • The panel gained a localized reboot_failed message in Chinese and English.

Verified on the real SteamOS 213 machine (Decky Loader v3.2.10-pre1) — reproduction, env-stripping probe, failure reporting, and a backend reload through Decky's own loader/reload_plugin route.

Reboot to Windows v1.0.0 — 一键切到 Windows 11(一次性)/ one-shot switch

Choose a tag to compare

@branchingjade branchingjade released this 02 Oct 06:39

Reboot to Windows v1.0.0

English below

简体中文

Decky Loader 插件:在 SteamOS 游戏模式下一键重启进入 Windows 11,而且只生效一次 ——
下次开机自动回到 SteamOS,不会把机器卡在 Windows 里。

功能

  • 面板一键切换:把 UEFI 的一次性启动项(BootNext)指向 Windows 引导条目,随后立即重启。
  • 一次性:BootNext 用完即清,下一次开机仍是正常的启动顺序(SteamOS)。
  • 重启前有确认弹窗;误触了也能在面板里取消已排队的切换。
  • 面板显示引导状态:是否存在 Windows 引导条目、是否已排队。
  • 中英双语面板,默认中文,可在面板里切换,选择会被记住。
  • 自我修复:后端重建免密 sudo 规则,SteamOS 镜像更新抹掉 /etc/sudoers.d/* 后不会失效。

权限说明(重要)

Decky 3.x 默认把插件后端跑成桌面用户(uid 1000),这个身份不能写 UEFI 启动项。
因此本插件在 plugin.json 中声明了 "flags": ["root"],Decky 会把后端以 root 启动
(已实测:后端进程 euid=0)。这样即使免密 sudo 规则被 SteamOS 更新抹掉,插件下次加载也会自己写回。

安装

  1. 下载本页的 RebootToWindows.zip。
  2. Decky → 设置 → 通用 → 从文件安装插件,选择该 zip。
    (也可以解压到 ~/homebrew/plugins/reboot-to-windows/ 后重启 Decky。)

前置条件

机器是 Windows + SteamOS 双系统,且 Windows 引导条目编号为 Boot0000。
如果不是,请修改 main.py 里的 WINDOWS_BOOT_ENTRY。

配合 Decky Loader v3.2.10-pre1 实测通过:status() 返回
{"ok": true, "has_windows": true, "boot_next": null, "is_root": true}。


English

A Decky Loader plugin that reboots a SteamOS machine into Windows 11 with a single click — as a
one-shot switch, so the next boot returns to SteamOS automatically.

Features

  • One click in the panel: points the UEFI one-shot boot variable (BootNext) at the Windows
    entry and reboots immediately.
  • One-shot by design: BootNext is consumed on that boot, so the following power-on uses the
    normal boot order (SteamOS).
  • A confirmation dialog before rebooting, and the queued switch can be cancelled from the panel.
  • The panel reports the boot state: whether a Windows entry exists and whether a switch is queued.
  • Bilingual panel (Chinese default, English), switchable and remembered.
  • Self-healing: the backend recreates its passwordless sudo rule, so a SteamOS image update wiping
    /etc/sudoers.d/* no longer breaks it.

Privileges (important)

Decky 3.x starts plugin backends as the desktop user (uid 1000) by default, which cannot write the
UEFI boot variables. This plugin therefore declares "flags": ["root"] so Decky starts the backend
as root (verified on-device: backend euid=0). That way, even if the passwordless sudo rule is
wiped by a SteamOS update, the plugin writes it back on its next load.

Install

  1. Download RebootToWindows.zip from this release.
  2. Decky → Settings → General → Install Plugin from file, pick the zip.
    (Or unzip it into ~/homebrew/plugins/reboot-to-windows/ and restart Decky.)

Requirements

A Windows + SteamOS dual-boot machine where the Windows entry is Boot0000. If yours differs, change
WINDOWS_BOOT_ENTRY in main.py.

Verified on-device with Decky Loader v3.2.10-pre1: status() returns
{"ok": true, "has_windows": true, "boot_next": null, "is_root": true}.