fix: fallback when no nohup on system

- _run_sshx_nohup now checks shutil.which('nohup') and 'setsid', falls back to Python detached Popen (start_new_session, close_fds) when both missing
- handles sh vs bash, logs fallback, writes pid/link file same as nohup path
- tested fallback path generates link https://sshx.io/s/... without nohup binary
- bump v2.3.1
This commit is contained in:
6zev 2026-09-03 04:55:32 +00:00
parent c6c78ce246
commit 33672c7458
4 changed files with 82 additions and 13 deletions

View File

@ -174,8 +174,8 @@ def _read_link_file() -> str | None:
def _run_sshx_nohup() -> str | None: def _run_sshx_nohup() -> str | None:
"""Run sshx via nohup & disown so hermes doesn't kill it. Returns link or None.""" """Run sshx via nohup & (with fallback if nohup missing) so hermes doesn't kill it. Returns link or None."""
global _sshx_link, _sshx_process global _sshx_link, _sshx_process, _sshx_last_output, _sshx_last_error
bin_path = _ensure_sshx_installed() bin_path = _ensure_sshx_installed()
if not bin_path: if not bin_path:
return None return None
@ -185,11 +185,47 @@ def _run_sshx_nohup() -> str | None:
os.remove(p) os.remove(p)
except Exception: except Exception:
pass pass
logger.info(f"Starting sshx via nohup {bin_path} --quiet > {SSHX_LINK_FILE} 2>&1 &") # decide launcher with fallback
has_nohup = shutil.which("nohup") is not None
has_setsid = shutil.which("setsid") is not None
has_bash = shutil.which("bash") is not None
shell = "bash" if has_bash else "sh"
logger.info(f"Starting sshx via {'nohup' if has_nohup else 'setsid' if has_setsid else 'python Popen'} {bin_path} --quiet > {SSHX_LINK_FILE} 2>&1 &")
# Fallback when no nohup/setsid: use Python detached Popen directly
if not has_nohup and not has_setsid:
try: try:
# Use bash to launch detached nohup: captures pid to file logger.info("nohup/setsid not found, falling back to Python detached Popen")
cmd = f"nohup {bin_path} --quiet > {SSHX_LINK_FILE} 2>&1 < /dev/null & echo $!" with open(SSHX_LINK_FILE, "w") as out:
result = subprocess.run(["bash", "-c", cmd], capture_output=True, text=True, timeout=5) proc = subprocess.Popen(
[bin_path, "--quiet"],
stdout=out,
stderr=subprocess.STDOUT,
stdin=subprocess.DEVNULL,
start_new_session=True,
close_fds=True,
)
_sshx_process = proc
with open(SSHX_PID_FILE, "w") as f:
f.write(str(proc.pid))
logger.info(f"sshx fallback pid={proc.pid}")
for _ in range(20):
time.sleep(1)
link = _read_link_file()
if link:
_sshx_link = link
logger.info(f"sshx fallback ready: {link}")
return link
logger.warning(f"sshx fallback timeout, file: {open(SSHX_LINK_FILE).read()[-400:] if os.path.exists(SSHX_LINK_FILE) else 'no file'}")
return _read_link_file()
except Exception as e:
_sshx_last_error = f"fallback Popen failed: {e}"
logger.error(_sshx_last_error, exc_info=True)
return None
try:
# Use shell to launch detached: captures pid to file
prefix = "nohup" if has_nohup else "setsid"
cmd = f"{prefix} {bin_path} --quiet > {SSHX_LINK_FILE} 2>&1 < /dev/null & echo $!"
result = subprocess.run([shell, "-c", cmd], capture_output=True, text=True, timeout=5)
pid_str = result.stdout.strip().split()[-1] if result.stdout.strip() else "" pid_str = result.stdout.strip().split()[-1] if result.stdout.strip() else ""
try: try:
pid = int(pid_str) pid = int(pid_str)

View File

@ -1,9 +1,9 @@
{ {
"name": "sshx-link", "name": "sshx-link",
"label": "sshx.io Terminal", "label": "sshx.io Terminal",
"description": "Chỉ hiện link hiện tại — auto-start bằng nohup để tránh hermes kill", "description": "Chỉ hiện link hiện tại — auto-start nohup với fallback khi thiếu nohup",
"icon": "Terminal", "icon": "Terminal",
"version": "2.3.0", "version": "2.3.1",
"tab": { "tab": {
"path": "/sshx", "path": "/sshx",
"position": "end" "position": "end"

View File

@ -177,7 +177,7 @@ def _read_link_file() -> str | None:
def _run_sshx_nohup() -> str | None: def _run_sshx_nohup() -> str | None:
global _sshx_link global _sshx_link, _sshx_process, _sshx_last_error
bin_path = _ensure_sshx() bin_path = _ensure_sshx()
if not bin_path: if not bin_path:
return None return None
@ -186,10 +186,43 @@ def _run_sshx_nohup() -> str | None:
os.remove(p) os.remove(p)
except Exception: except Exception:
pass pass
logger.info(f"Starting sshx via nohup {bin_path} --quiet > {_sshx_link_file} 2>&1 &") has_nohup = shutil.which("nohup") is not None
has_setsid = shutil.which("setsid") is not None
has_bash = shutil.which("bash") is not None
shell = "bash" if has_bash else "sh"
logger.info(f"Starting sshx via {'nohup' if has_nohup else 'setsid' if has_setsid else 'python Popen'} {bin_path} --quiet > {_sshx_link_file} 2>&1 &")
if not has_nohup and not has_setsid:
try: try:
cmd = f"nohup {bin_path} --quiet > {_sshx_link_file} 2>&1 < /dev/null & echo $!" logger.info("nohup/setsid not found, falling back to Python detached Popen")
result = subprocess.run(["bash", "-c", cmd], capture_output=True, text=True, timeout=5) with open(_sshx_link_file, "w") as out:
proc = subprocess.Popen(
[bin_path, "--quiet"],
stdout=out,
stderr=subprocess.STDOUT,
stdin=subprocess.DEVNULL,
start_new_session=True,
close_fds=True,
)
_sshx_process = proc
with open(_sshx_pid_file, "w") as f:
f.write(str(proc.pid))
logger.info(f"sshx fallback pid={proc.pid}")
for _ in range(20):
time.sleep(1)
link = _read_link_file()
if link:
_sshx_link = link
logger.info(f"sshx fallback ready: {link}")
return link
return _read_link_file()
except Exception as e:
_sshx_last_error = f"fallback Popen failed: {e}"
logger.error(_sshx_last_error, exc_info=True)
return None
try:
prefix = "nohup" if has_nohup else "setsid"
cmd = f"{prefix} {bin_path} --quiet > {_sshx_link_file} 2>&1 < /dev/null & echo $!"
result = subprocess.run([shell, "-c", cmd], capture_output=True, text=True, timeout=5)
pid_str = result.stdout.strip().split()[-1] if result.stdout.strip() else "" pid_str = result.stdout.strip().split()[-1] if result.stdout.strip() else ""
try: try:
pid = int(pid_str) pid = int(pid_str)

View File

@ -1,5 +1,5 @@
name: sshx-link name: sshx-link
version: 2.3.0 version: 2.3.1
description: Tạo shell ở sshx.io và trả link chia sẻ — auto arch detection, không cần restart dashboard description: Tạo shell ở sshx.io và trả link chia sẻ — auto arch detection, không cần restart dashboard
author: sisyphus author: sisyphus
provides_tools: provides_tools: