mirror of
https://github.com/holdmysocks/ps5-tailscale.git
synced 2026-10-06 13:00:17 +02:00
Stop registering with payload autoloaders
The installer no longer adds the daemon to Payload Manager's or ps5_autoloader's load order. It writes /data/tailscale/tailscale.elf, adds the home screen icon and starts the daemon; starting it after a reboot is left to the user. The daemon's status page and Uninstall no longer look at autoloaders either.
This commit is contained in:
1 parent
4554502591
commit
0156e4e210
10 files changed
+70
-283
No files matched your search
@@ -7,8 +7,7 @@ Puts a jailbroken PS5 on your [Tailscale](https://tailscale.com) network.
|
||||
your other Tailscale devices.
|
||||
- **Stream games to the console over Tailscale.** A Moonlight client on the
|
||||
PS5 (such as ProsperoLight) can connect to a Sunshine host on your tailnet.
|
||||
- **Starts by itself** after each jailbreak if you use a payload autoloader,
|
||||
and adds a home screen icon for its status page.
|
||||
- **Home screen icon** that opens its status page.
|
||||
|
||||
It runs the real Tailscale client code (v1.104.0) as a single payload.
|
||||
|
||||
@@ -36,11 +35,8 @@ VPN here. It runs inside one process:
|
||||
- A jailbroken PS5 with an ELF loader listening on port 9021
|
||||
(for example [elfldr](https://github.com/ps5-payload-dev/elfldr)).
|
||||
- A Tailscale account.
|
||||
- Optional: a payload autoloader, so Tailscale starts after every jailbreak.
|
||||
[Payload Manager](https://github.com/itsPLK/ps5-payload-manager) and
|
||||
`ps5_autoloader` folders are detected.
|
||||
|
||||
Tested on firmware 13.42 with elfldr 0.26 and Payload Manager 0.5.2.
|
||||
Tested on firmware 13.42 with elfldr 0.26.
|
||||
|
||||
## Install
|
||||
|
||||
@@ -59,8 +55,7 @@ Tested on firmware 13.42 with elfldr 0.26 and Payload Manager 0.5.2.
|
||||
```
|
||||
|
||||
The installer prints what it does. It:
|
||||
- stores the daemon payload (`tailscale.elf`),
|
||||
- adds it to the end of your autoloader's load order, if it finds one,
|
||||
- stores the daemon payload as `/data/tailscale/tailscale.elf`,
|
||||
- adds a **Tailscale** icon to the home screen (media section),
|
||||
- starts Tailscale.
|
||||
|
||||
@@ -73,6 +68,11 @@ The console now has a tailnet address, shown on the status page.
|
||||
Sending the installer again upgrades and restarts Tailscale. The login is
|
||||
kept.
|
||||
|
||||
Tailscale runs until the console restarts. After a restart and jailbreak,
|
||||
send `/data/tailscale/tailscale.elf` (or the installer) to the ELF loader
|
||||
again. The installer does not change any payload autoloader; if you use one,
|
||||
you can add that file to it yourself.
|
||||
|
||||
## Using it
|
||||
|
||||
### Reaching the console
|
||||
@@ -141,7 +141,7 @@ The daemon also runs an HTTP proxy on `127.0.0.1:8118` that reaches tailnet
|
||||
hosts, for apps that have their own proxy setting. **Do not set it as the
|
||||
PS5's system proxy.** The system then sends everything through it, including
|
||||
pages on `127.0.0.1`, and it is not running until Tailscale has been loaded.
|
||||
On the test console that stopped Payload Manager's page from opening.
|
||||
On the test console that stopped another homebrew tool's page from opening.
|
||||
|
||||
## Configuration
|
||||
|
||||
@@ -184,20 +184,19 @@ Files on the console:
|
||||
| `/data/tailscale/state/` | Tailscale's state, including the login. |
|
||||
| `/data/tailscale/tailscale.log` | The daemon's log, rotated at 2 MB. |
|
||||
| `/data/tailscale/tailscale-debug.log` | Tailscale's detailed log, up to 4 MB plus one older file. |
|
||||
| `/data/pldmgr/payloads/Tailscale/tailscale.elf` | The daemon, when Payload Manager is used. |
|
||||
| `/data/tailscale/tailscale.elf` | The daemon, when no autoloader was found. |
|
||||
| `/data/tailscale/tailscale.elf` | The daemon payload. |
|
||||
| `/user/app/TSCL00001/` | The home screen icon. |
|
||||
|
||||
## Uninstall
|
||||
|
||||
Press **Uninstall** on the status page. It removes the autoloader entry and
|
||||
the daemon payload and stops Tailscale. It asks whether to also log out and
|
||||
delete the saved login.
|
||||
Press **Uninstall** on the status page. It deletes the daemon payload and
|
||||
stops Tailscale. It asks whether to also log out and delete the saved login.
|
||||
|
||||
Two things are left to do by hand:
|
||||
|
||||
- Delete the home screen icon (Options button, then Delete).
|
||||
- Remove the device in the Tailscale admin console.
|
||||
- If you added the payload to an autoloader yourself, remove it there.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
@@ -229,13 +228,12 @@ lowest scheduling priority on at most 4 cores, so it gives way to games.
|
||||
## What has and has not been tested
|
||||
|
||||
Tested on the one console: install and upgrade, login with device approval,
|
||||
autostart after a reboot through Payload Manager, reaching the console over
|
||||
starting again after a reboot with the saved login, reaching the console over
|
||||
the tailnet, a ProsperoLight stream from a Sunshine host through the forward,
|
||||
the HTTP proxy, the home screen icon.
|
||||
|
||||
Not tested: rest mode, the `ps5_autoloader` and USB autoloader paths,
|
||||
Uninstall on a console, other firmware versions, coordination servers other
|
||||
than Tailscale's.
|
||||
Not tested: rest mode, Uninstall on a console, other firmware versions,
|
||||
coordination servers other than Tailscale's.
|
||||
|
||||
## Building
|
||||
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ These folders are not in the repository.
|
||||
|
||||
```powershell
|
||||
# daemon payload: C launcher + Go program -> out\tailscale.elf
|
||||
.\tools\build-payload.ps1 -GoDir tsd -Name tailscale -Version 0.2.1
|
||||
.\tools\build-payload.ps1 -GoDir tsd -Name tailscale -Version 0.3.0
|
||||
|
||||
# installer -> out\tailscale-installer.elf (embeds out\tailscale.elf)
|
||||
.\tools\build-installer.ps1
|
||||
|
||||
+5
-15
@@ -37,10 +37,11 @@ specification.
|
||||
- A payload that is sent again stops the running instance (through the
|
||||
status page, or failing that by the pid it recorded) and takes over.
|
||||
|
||||
**The installer** (`installer/`, C) embeds `tailscale.elf`. It stores it
|
||||
where the console's autoloader looks, appends it to the load order, registers
|
||||
a home screen app whose `param.json` has a `deeplinkUri` to the status page,
|
||||
and starts the daemon by sending it to the ELF loader on `127.0.0.1:9021`.
|
||||
**The installer** (`installer/`, C) embeds `tailscale.elf`. It writes it to
|
||||
`/data/tailscale/tailscale.elf`, registers a home screen app whose
|
||||
`param.json` has a `deeplinkUri` to the status page, and starts the daemon by
|
||||
sending it to the ELF loader on `127.0.0.1:9021`. It does not modify any
|
||||
payload autoloader.
|
||||
|
||||
## The PS5 as a Go target
|
||||
|
||||
@@ -136,17 +137,6 @@ Linking `libSceAppInstUtil` alone leaves the payload stopped before it runs.
|
||||
It needs `-lSceIpmi -lSceAppInstUtil -lSceUserService -lSceSystemService`, in
|
||||
that order, as in the SDK's `install_app` sample.
|
||||
|
||||
## Autoloaders
|
||||
|
||||
- Payload Manager: load order in `/data/pldmgr/autoload.txt`, one file name
|
||||
per line, `!N` for a delay in milliseconds. It finds a named file anywhere
|
||||
below `/data/pldmgr` and launches it by streaming it to `127.0.0.1:9021`.
|
||||
- `ps5_autoloader`: `autoload.txt` in `/data/ps5_autoloader` or the same
|
||||
folder on a USB drive, with the payloads next to it.
|
||||
|
||||
The table of autoloaders exists twice, in `installer/main.c` and
|
||||
`tsd/autostart.go`.
|
||||
|
||||
## Known problems
|
||||
|
||||
- Once, switching the console from Wi-Fi to Ethernet during a Moonlight
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 55 KiB |
+13
-105
@@ -1,9 +1,9 @@
|
||||
/* Tailscale installer payload for jailbroken PS5s.
|
||||
*
|
||||
* Stores the Tailscale daemon payload on the console, registers it with the
|
||||
* payload autoloader if one is set up, adds a home screen icon that opens
|
||||
* the status page, and starts the daemon through the ELF loader on this
|
||||
* console. Build with tools\build-installer.ps1, which sets DAEMON_ELF and
|
||||
* Stores the Tailscale daemon payload on the console, adds a home screen
|
||||
* icon that opens the status page, and starts the daemon through the ELF
|
||||
* loader on this console. It does not touch any payload autoloader. Build
|
||||
* with tools\build-installer.ps1, which sets DAEMON_ELF and
|
||||
* ASSET_DIR and links the system libraries the app installer needs. */
|
||||
|
||||
#include <errno.h>
|
||||
@@ -69,23 +69,6 @@ int sceAppInstUtilInitialize(void);
|
||||
int sceAppInstUtilTerminate(void);
|
||||
int sceAppInstUtilAppInstallAll(void *);
|
||||
|
||||
/* Where payload autoloaders keep their load order, and where the daemon has
|
||||
* to be stored for each. Keep in sync with tsd/autostart.go. */
|
||||
static const struct autoloader {
|
||||
const char *name;
|
||||
const char *list; /* load order: one file name per line */
|
||||
const char *payload_dir; /* where the payload goes */
|
||||
} autoloaders[] = {
|
||||
/* Payload Manager finds entries by file name anywhere below /data/pldmgr
|
||||
* and keeps each payload in a folder of its own. */
|
||||
{"Payload Manager", "/data/pldmgr/autoload.txt", "/data/pldmgr/payloads/Tailscale"},
|
||||
{"PS5 autoloader", "/data/ps5_autoloader/autoload.txt", "/data/ps5_autoloader"},
|
||||
{"PS5 autoloader (usb0)", "/mnt/usb0/ps5_autoloader/autoload.txt", "/mnt/usb0/ps5_autoloader"},
|
||||
{"PS5 autoloader (usb1)", "/mnt/usb1/ps5_autoloader/autoload.txt", "/mnt/usb1/ps5_autoloader"},
|
||||
{"PS5 autoloader (usb2)", "/mnt/usb2/ps5_autoloader/autoload.txt", "/mnt/usb2/ps5_autoloader"},
|
||||
{"PS5 autoloader (usb3)", "/mnt/usb3/ps5_autoloader/autoload.txt", "/mnt/usb3/ps5_autoloader"},
|
||||
};
|
||||
|
||||
typedef struct notify_request {
|
||||
char useless1[45];
|
||||
char message[3075];
|
||||
@@ -122,7 +105,7 @@ write_all(int fd, const uint8_t *data, size_t size) {
|
||||
}
|
||||
|
||||
/* Write a file through a temporary name so a failed write never leaves a
|
||||
* truncated payload where the autoloader would pick it up. */
|
||||
* truncated payload behind. */
|
||||
static int
|
||||
write_file(const char *path, const uint8_t *data, size_t size) {
|
||||
char tmp[512];
|
||||
@@ -159,71 +142,6 @@ install_daemon(const char *dir) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Report whether the load order already lists the daemon on a line of its own. */
|
||||
static int
|
||||
autoload_lists_daemon(const char *text) {
|
||||
size_t namelen = strlen(DAEMON_NAME);
|
||||
|
||||
for (const char *line = text; line && *line;) {
|
||||
const char *end = strchr(line, '\n');
|
||||
size_t len = end ? (size_t)(end - line) : strlen(line);
|
||||
while (len > 0 && (line[len - 1] == '\r' || line[len - 1] == ' ' || line[len - 1] == '\t')) {
|
||||
len--;
|
||||
}
|
||||
if (len == namelen && !strncmp(line, DAEMON_NAME, namelen)) {
|
||||
return 1;
|
||||
}
|
||||
line = end ? end + 1 : 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If this autoloader is set up on the console, store the daemon for it and
|
||||
* add it to the end of the load order. Returns 1 if registered, 0 if the
|
||||
* autoloader is not present, -1 on error. */
|
||||
static int
|
||||
register_autoload(const struct autoloader *al) {
|
||||
struct stat st;
|
||||
char *text;
|
||||
size_t got;
|
||||
FILE *f;
|
||||
|
||||
if (stat(al->list, &st)) {
|
||||
return 0;
|
||||
}
|
||||
printf("%s:\n", al->name);
|
||||
if (install_daemon(al->payload_dir)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(f = fopen(al->list, "rb"))) {
|
||||
printf(" could not read %s: %s\n", al->list, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
text = calloc(1, st.st_size + 1);
|
||||
got = fread(text, 1, st.st_size, f);
|
||||
fclose(f);
|
||||
text[got] = 0;
|
||||
|
||||
if (autoload_lists_daemon(text)) {
|
||||
printf(" %s already lists %s\n", al->list, DAEMON_NAME);
|
||||
} else {
|
||||
if (!(f = fopen(al->list, "ab"))) {
|
||||
printf(" could not update %s: %s\n", al->list, strerror(errno));
|
||||
free(text);
|
||||
return -1;
|
||||
}
|
||||
if (got > 0 && text[got - 1] != '\n') {
|
||||
fputc('\n', f);
|
||||
}
|
||||
fputs(DAEMON_NAME "\n", f);
|
||||
fclose(f);
|
||||
printf(" added %s to the end of %s\n", DAEMON_NAME, al->list);
|
||||
}
|
||||
free(text);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Report whether the file at path already has exactly these contents. */
|
||||
static int
|
||||
file_matches(const char *path, const uint8_t *data, size_t size) {
|
||||
@@ -346,7 +264,6 @@ int
|
||||
main(void) {
|
||||
pid_t pid = getpid();
|
||||
intptr_t rootvnode;
|
||||
int registered = 0;
|
||||
|
||||
setvbuf(stdout, 0, _IONBF, 0);
|
||||
|
||||
@@ -368,23 +285,11 @@ main(void) {
|
||||
#endif
|
||||
|
||||
printf("Tailscale for PS5 installer\n\n");
|
||||
mkdir(DATA_DIR, 0755);
|
||||
|
||||
for (size_t i = 0; i < sizeof(autoloaders) / sizeof(autoloaders[0]); i++) {
|
||||
if (register_autoload(&autoloaders[i]) > 0) {
|
||||
registered++;
|
||||
}
|
||||
}
|
||||
if (!registered) {
|
||||
/* No autoloader: keep the payload where the user can find it. */
|
||||
printf("No payload autoloader found on this console.\n");
|
||||
if (install_daemon(DATA_DIR)) {
|
||||
notify("Tailscale install failed:\ncould not write to %s", DATA_DIR);
|
||||
return 1;
|
||||
}
|
||||
printf(" Tailscale will not start by itself after a reboot.\n"
|
||||
" Send %s/%s to the ELF loader to start it.\n",
|
||||
DATA_DIR, DAEMON_NAME);
|
||||
printf("Daemon payload:\n");
|
||||
if (install_daemon(DATA_DIR)) {
|
||||
notify("Tailscale install failed:\ncould not write to %s", DATA_DIR);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Home screen icon:\n");
|
||||
@@ -397,6 +302,9 @@ main(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("\nDone. The status page is on port 8090 of this console.\n");
|
||||
printf("\nDone. The status page is on port 8090 of this console.\n"
|
||||
"Tailscale runs until the console restarts. To start it again, send\n"
|
||||
"%s/%s to the ELF loader.\n",
|
||||
DATA_DIR, DAEMON_NAME);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// The installer registers the daemon with whichever payload autoloader the
|
||||
// console uses: it copies the payload where the autoloader looks for files
|
||||
// and adds its file name to the autoloader's load order (one payload per
|
||||
// line, "!N" lines are delays). This file is the daemon's side of that:
|
||||
// reporting the registration and undoing it. Keep the table in sync with
|
||||
// installer/main.c.
|
||||
|
||||
const daemonFileName = "tailscale.elf"
|
||||
|
||||
// An autoloader is one place a payload autoloader keeps its load order.
|
||||
type autoloader struct {
|
||||
name string // for messages
|
||||
list string // the load order file
|
||||
payloadDir string // where the daemon payload is stored for it
|
||||
}
|
||||
|
||||
var autoloaders = func() []autoloader {
|
||||
al := []autoloader{
|
||||
// Payload Manager finds entries by file name anywhere below
|
||||
// /data/pldmgr and keeps each payload in a folder of its own.
|
||||
{"Payload Manager", "/data/pldmgr/autoload.txt", "/data/pldmgr/payloads/Tailscale"},
|
||||
{"PS5 autoloader", "/data/ps5_autoloader/autoload.txt", "/data/ps5_autoloader"},
|
||||
}
|
||||
for _, usb := range []string{"usb0", "usb1", "usb2", "usb3"} {
|
||||
dir := "/mnt/" + usb + "/ps5_autoloader"
|
||||
al = append(al, autoloader{"PS5 autoloader (" + usb + ")", dir + "/autoload.txt", dir})
|
||||
}
|
||||
return al
|
||||
}()
|
||||
|
||||
// autostartNames returns the autoloaders whose load order includes the daemon.
|
||||
func autostartNames() []string {
|
||||
names := []string{}
|
||||
for _, al := range autoloaders {
|
||||
b, err := os.ReadFile(al.list)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if _, found := removeAutoloadEntry(string(b), daemonFileName); found {
|
||||
names = append(names, al.name)
|
||||
}
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
// removeAutoloadEntry returns text without the lines that name the payload,
|
||||
// and whether there were any. Everything else, including line endings, is
|
||||
// kept as it was.
|
||||
func removeAutoloadEntry(text, name string) (string, bool) {
|
||||
var out strings.Builder
|
||||
found := false
|
||||
for len(text) > 0 {
|
||||
line := text
|
||||
if i := strings.IndexByte(text, '\n'); i >= 0 {
|
||||
line = text[:i+1]
|
||||
}
|
||||
text = text[len(line):]
|
||||
if strings.TrimSpace(line) == name {
|
||||
found = true
|
||||
continue
|
||||
}
|
||||
out.WriteString(line)
|
||||
}
|
||||
return out.String(), found
|
||||
}
|
||||
|
||||
// uninstall removes the daemon from every autoloader and deletes the
|
||||
// installed payload. With purge it also deletes the Tailscale state and
|
||||
// config, which forgets the login. The running process is not affected.
|
||||
func uninstall(purge bool, logf func(string, ...any)) error {
|
||||
var errs []error
|
||||
remove := func(path string) {
|
||||
if err := os.Remove(path); err != nil && !errors.Is(err, fs.ErrNotExist) {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
for _, al := range autoloaders {
|
||||
b, err := os.ReadFile(al.list)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if text, found := removeAutoloadEntry(string(b), daemonFileName); found {
|
||||
if err := os.WriteFile(al.list, []byte(text), 0o644); err != nil {
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
logf("removed %s from %s", daemonFileName, al.list)
|
||||
}
|
||||
remove(filepath.Join(al.payloadDir, daemonFileName))
|
||||
if filepath.Base(al.payloadDir) == "Tailscale" {
|
||||
// A folder the installer created just for this payload.
|
||||
os.Remove(al.payloadDir)
|
||||
}
|
||||
}
|
||||
remove(filepath.Join(dataDir, daemonFileName))
|
||||
if purge {
|
||||
for _, name := range []string{"state", "config.json", ".cache"} {
|
||||
if err := os.RemoveAll(filepath.Join(dataDir, name)); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
@@ -6,27 +6,6 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRemoveAutoloadEntry(t *testing.T) {
|
||||
tests := []struct {
|
||||
name, in, want string
|
||||
found bool
|
||||
}{
|
||||
{"absent", "kstuff.elf\n!500\nftpsrv.elf\n", "kstuff.elf\n!500\nftpsrv.elf\n", false},
|
||||
{"last line", "kstuff.elf\ntailscale.elf\n", "kstuff.elf\n", true},
|
||||
{"no trailing newline", "kstuff.elf\ntailscale.elf", "kstuff.elf\n", true},
|
||||
{"middle, CRLF kept", "a.elf\r\ntailscale.elf\r\nb.elf\r\n", "a.elf\r\nb.elf\r\n", true},
|
||||
{"listed twice", "tailscale.elf\na.elf\n tailscale.elf \n", "a.elf\n", true},
|
||||
{"similar names stay", "# tailscale.elf\nmy-tailscale.elf\ntailscale.elf.bak\n", "# tailscale.elf\nmy-tailscale.elf\ntailscale.elf.bak\n", false},
|
||||
{"empty", "", "", false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
got, found := removeAutoloadEntry(tt.in, daemonFileName)
|
||||
if got != tt.want || found != tt.found {
|
||||
t.Errorf("%s: got %q, %v; want %q, %v", tt.name, got, found, tt.want, tt.found)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pipe must pass a half-close through: the ELF loader protocol and FTP data
|
||||
// connections both rely on the reader seeing EOF while the other direction
|
||||
// stays open.
|
||||
+1
-2
@@ -161,7 +161,6 @@ async function refresh() {
|
||||
if (s.ips.length) row(dl, 'Tailnet address', s.ips.join(', '), true);
|
||||
if (s.tailnet) row(dl, 'Tailnet', s.tailnet);
|
||||
if (s.proxy) row(dl, 'HTTP proxy', s.proxy, true);
|
||||
row(dl, 'Starts with the console', s.autostart.length ? 'Yes, via ' + s.autostart.join(', ') : 'No');
|
||||
|
||||
const health = $('health');
|
||||
health.replaceChildren(...(s.health || []).map(h => { const li = document.createElement('li'); li.textContent = h; return li; }));
|
||||
@@ -240,7 +239,7 @@ $('btn-sunshine').onclick = async () => {
|
||||
$('sunshine-select').dataset.signature = '';
|
||||
};
|
||||
$('btn-uninstall').onclick = () => {
|
||||
if (!confirm('Remove Tailscale from this PS5? It will stop now and no longer start with the console.')) return;
|
||||
if (!confirm('Remove Tailscale from this PS5? It stops now and its payload is deleted.')) return;
|
||||
const purge = confirm('Also log out and delete the saved login?\n\nOK: delete everything.\nCancel: keep the login, so reinstalling reconnects without logging in again.');
|
||||
act('/api/uninstall' + (purge ? '?purge=1' : ''));
|
||||
};
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// daemonFileName is the name the installer stores the daemon payload under,
|
||||
// in the data directory.
|
||||
const daemonFileName = "tailscale.elf"
|
||||
|
||||
// uninstall deletes the installed daemon payload. With purge it also deletes
|
||||
// the Tailscale state and config, which forgets the login. The running
|
||||
// process is not affected.
|
||||
func uninstall(purge bool) error {
|
||||
var errs []error
|
||||
if err := os.Remove(filepath.Join(dataDir, daemonFileName)); err != nil && !errors.Is(err, fs.ErrNotExist) {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if purge {
|
||||
for _, name := range []string{"state", "config.json", ".cache"} {
|
||||
if err := os.RemoveAll(filepath.Join(dataDir, name)); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
+4
-7
@@ -43,8 +43,6 @@ type statusInfo struct {
|
||||
Health []string `json:"health,omitempty"`
|
||||
Peers []peerInfo `json:"peers"`
|
||||
Proxy string `json:"proxy,omitempty"`
|
||||
// Autostart lists the autoloaders that start the daemon.
|
||||
Autostart []string `json:"autostart"`
|
||||
// SunshineHost and Forwards describe the local forwards.
|
||||
SunshineHost string `json:"sunshineHost"`
|
||||
Forwards []string `json:"forwards"`
|
||||
@@ -141,7 +139,6 @@ func (d *daemon) handleStatus(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
info.SunshineHost = d.cfg.SunshineHost
|
||||
d.mu.Unlock()
|
||||
info.Autostart = autostartNames()
|
||||
info.Forwards = []string{}
|
||||
for _, r := range d.fwd.rules() {
|
||||
info.Forwards = append(info.Forwards, r.String())
|
||||
@@ -299,9 +296,9 @@ func (d *daemon) stop() {
|
||||
d.quitOnce.Do(func() { close(d.quit) })
|
||||
}
|
||||
|
||||
// handleUninstall removes the autostart entry and the installed payload, then
|
||||
// stops. With ?purge=1 it first logs the console out of the tailnet and
|
||||
// deletes the saved state as well.
|
||||
// handleUninstall removes the installed payload, then stops. With ?purge=1 it
|
||||
// first logs the console out of the tailnet and deletes the saved state as
|
||||
// well.
|
||||
func (d *daemon) handleUninstall(w http.ResponseWriter, r *http.Request) {
|
||||
purge := r.URL.Query().Get("purge") == "1"
|
||||
if purge && d.lc != nil {
|
||||
@@ -309,7 +306,7 @@ func (d *daemon) handleUninstall(w http.ResponseWriter, r *http.Request) {
|
||||
d.logf("uninstall: logout: %v", err)
|
||||
}
|
||||
}
|
||||
if err := uninstall(purge, d.logf); err != nil {
|
||||
if err := uninstall(purge); err != nil {
|
||||
d.logf("uninstall: %v", err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
|
||||
Reference in new issue
Block a user