try to install busybox into a tmpfs /bin (with fallback)

This code path requires gokrazy/tools at this commit or newer:
37e2f95c5c

And gokrazy/serial-breakglass at this commit or newer:
bf9bc19235

Afterwards, with an ~/.ssh/config entry like this:

    Host scan2drive
        ProxyCommand breakglass -proxy %h

…using Emacs TRAMP should just work:

    emacs /ssh:scan2drive:/perm/keep/index.md
This commit is contained in:
Michael Stapelberg 2024-12-31 09:50:32 +01:00
parent 6c59aaaf28
commit c9528b4abb
2 changed files with 63 additions and 0 deletions

53
busybox.go Normal file
View File

@ -0,0 +1,53 @@
package main
import (
"fmt"
"log"
"os"
"os/exec"
"strings"
"syscall"
)
const wellKnownBusybox = "/usr/local/bin/busybox"
// mountBin bind-mounts /bin to a tmpfs.
func mountBin() error {
b, err := os.ReadFile("/proc/self/mountinfo")
if err != nil {
return err
}
for _, line := range strings.Split(strings.TrimSpace(string(b)), "\n") {
parts := strings.Fields(line)
if len(parts) < 5 {
continue
}
mountpoint := parts[4]
log.Printf("Found mountpoint %q", parts[4])
if mountpoint == "/bin" {
log.Printf("/bin file system already mounted, nothing to do")
return nil
}
}
if err := syscall.Mount("tmpfs", "/bin", "tmpfs", 0, ""); err != nil {
return fmt.Errorf("mounting tmpfs on /bin: %v", err)
}
return nil
}
func installBusybox() error {
// /bin is read-only by default, so mount a tmpfs over it
if err := mountBin(); err != nil {
return err
}
install := exec.Command(wellKnownBusybox, "--install", "-s", "/bin")
install.Stdout = os.Stdout
install.Stderr = os.Stderr
if err := install.Run(); err != nil {
return fmt.Errorf("%v: %v", install.Args, err)
}
return nil
}

10
ssh.go
View File

@ -215,6 +215,16 @@ type exitStatus struct {
}
func findShell() string {
if _, err := os.Stat(wellKnownBusybox); err == nil {
// Install busybox to /bin to provide the typical userspace utilities
// in standard locations (makes Emacs TRAMP work, for example).
if err := installBusybox(); err != nil {
log.Printf("installing busybox failed: %v", err)
// fallthrough
} else {
return "/bin/sh" // available after installation
}
}
if path, err := exec.LookPath("sh"); err == nil {
return path
}