From 33672c7458763f20b70014bd6ffaee7592ce4cd5 Mon Sep 17 00:00:00 2001 From: 6zev Date: Thu, 3 Sep 2026 04:55:32 +0000 Subject: [PATCH] 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 --- __init__.py | 48 +++++++++++++++++++++++++++++++++++------ dashboard/manifest.json | 4 ++-- dashboard/plugin_api.py | 41 +++++++++++++++++++++++++++++++---- plugin.yaml | 2 +- 4 files changed, 82 insertions(+), 13 deletions(-) diff --git a/__init__.py b/__init__.py index bcfc898..1428404 100644 --- a/__init__.py +++ b/__init__.py @@ -174,8 +174,8 @@ def _read_link_file() -> str | None: def _run_sshx_nohup() -> str | None: - """Run sshx via nohup & disown so hermes doesn't kill it. Returns link or None.""" - global _sshx_link, _sshx_process + """Run sshx via nohup & (with fallback if nohup missing) so hermes doesn't kill it. Returns link or None.""" + global _sshx_link, _sshx_process, _sshx_last_output, _sshx_last_error bin_path = _ensure_sshx_installed() if not bin_path: return None @@ -185,11 +185,47 @@ def _run_sshx_nohup() -> str | None: os.remove(p) except Exception: 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: + logger.info("nohup/setsid not found, falling back to Python detached Popen") + 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 + 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 bash to launch detached nohup: captures pid to file - cmd = f"nohup {bin_path} --quiet > {SSHX_LINK_FILE} 2>&1 < /dev/null & echo $!" - result = subprocess.run(["bash", "-c", cmd], capture_output=True, text=True, timeout=5) + # 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 "" try: pid = int(pid_str) diff --git a/dashboard/manifest.json b/dashboard/manifest.json index db10fb7..f0410e9 100644 --- a/dashboard/manifest.json +++ b/dashboard/manifest.json @@ -1,9 +1,9 @@ { "name": "sshx-link", "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", - "version": "2.3.0", + "version": "2.3.1", "tab": { "path": "/sshx", "position": "end" diff --git a/dashboard/plugin_api.py b/dashboard/plugin_api.py index 4668a6b..486cd9c 100644 --- a/dashboard/plugin_api.py +++ b/dashboard/plugin_api.py @@ -177,7 +177,7 @@ def _read_link_file() -> str | None: def _run_sshx_nohup() -> str | None: - global _sshx_link + global _sshx_link, _sshx_process, _sshx_last_error bin_path = _ensure_sshx() if not bin_path: return None @@ -186,10 +186,43 @@ def _run_sshx_nohup() -> str | None: os.remove(p) except Exception: 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: + logger.info("nohup/setsid not found, falling back to Python detached Popen") + 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: - cmd = f"nohup {bin_path} --quiet > {_sshx_link_file} 2>&1 < /dev/null & echo $!" - result = subprocess.run(["bash", "-c", cmd], capture_output=True, text=True, timeout=5) + 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 "" try: pid = int(pid_str) diff --git a/plugin.yaml b/plugin.yaml index 090143e..8a7de52 100644 --- a/plugin.yaml +++ b/plugin.yaml @@ -1,5 +1,5 @@ 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 author: sisyphus provides_tools: