max / alloy
| 1 | #!/bin/sh |
| 2 | # alloy-mesh-up — start the mesh daemon, then sign in, under one escalation. |
| 3 | # |
| 4 | # `tailscale up` talks to tailscaled over a local socket and does nothing on its |
| 5 | # own behalf. etc/systemd/system-preset/50-alloy.preset ships |
| 6 | # `disable tailscaled.service`, deliberately: joining a mesh reaches out to a |
| 7 | # control server and is a question the machine should be asked rather than |
| 8 | # assume. So on a fresh install the daemon is not running, and a sign-in that |
| 9 | # runs `tailscale up` alone escalates, takes the user's password, and then fails |
| 10 | # reading a socket nothing is listening on. That is the whole bug this exists to |
| 11 | # close, and it failed *after* the password, which is the expensive place to |
| 12 | # fail: the user has already paid the one cost the screen asked them for. |
| 13 | # |
| 14 | # Enrolling IS the opt-in the preset is waiting for, so this enables the unit |
| 15 | # rather than merely starting it. A mesh that evaporates at the next boot is not |
| 16 | # a mesh anyone asked for, and the preset's comment already names enrollment as |
| 17 | # where the unit is meant to come on. |
| 18 | # |
| 19 | # Why a script and not two commands from the console. Both halves need root, and |
| 20 | # two `run0` invocations are two polkit questions unless the caching happens to |
| 21 | # hold. One file is one prompt. It is also why this is not `run0 sh -c '...'` |
| 22 | # from the console: crates/alloy/src/cli.rs holds Invocation as argv precisely so |
| 23 | # a command is executed exactly as displayed, with no shell and no quoting |
| 24 | # round-trip, and --login-server carries a value the user typed. Passing it as |
| 25 | # argv to "$@" keeps that property. |
| 26 | # |
| 27 | # Every argument is forwarded to `tailscale up` untouched. |
| 28 | # |
| 29 | # The two real commands are echoed before they run. The console's log pane shows |
| 30 | # this script's path rather than what it drives, and mesh.rs is explicit that the |
| 31 | # abstraction must not conceal which tool is running, so the terminal the user |
| 32 | # was just handed says it. |
| 33 | |
| 34 | |
| 35 | |
| 36 | |
| 37 | |
| 38 | |
| 39 | # Not a fixed sleep. `tailscale up` fails on a socket that exists but is not yet |
| 40 | # answering, and `systemctl --now` returns when the unit is active rather than |
| 41 | # when tailscaled has finished opening it. Ten tries at a tenth of a second is |
| 42 | # a second of patience for something that normally takes one round. |
| 43 | i=0 |
| 44 | while [; do |
| 45 | && break |
| 46 | # `status` exits non-zero on a running daemon that is merely logged out, |
| 47 | # which is the state this script is always in. Distinguish "not answering" |
| 48 | # from "answering that there is nothing to report" by asking for the version, |
| 49 | # which needs the socket and not an account. |
| 50 | && break |
| 51 | i= |
| 52 | |
| 53 | done |
| 54 | |
| 55 | |
| 56 | |
| 57 |