Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions read_dmesg.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,17 @@

gw.run_cmd("rm -f " + fn_remote)

with open(fn_local, "r") as file:
with open(fn_local, "r", encoding="utf-8", errors="replace") as file:
data = file.read()
with open(fn_local, "w") as file:
with open(fn_local, "w", encoding="utf-8") as file:
file.write(data)

print("Kernel logs written to file {}".format(fn_local))

fn_old = 'outdir/syslog_old.txt'
fn_local = 'outdir/syslog.txt'
fn_remote = '/tmp/syslog.txt'
if os.path.exists(fn_local):
if os.path.exists(fn_local):
if os.path.exists(fn_old):
os.remove(fn_old)
os.rename(fn_local, fn_old)
Expand All @@ -50,9 +50,9 @@
gw.download(fn_remote, fn_local)
gw.run_cmd("rm -f " + fn_remote)

with open(fn_local, "r") as file:
with open(fn_local, "r", encoding="utf-8", errors="replace") as file:
data = file.read()
with open(fn_local, "w") as file:
with open(fn_local, "w", encoding="utf-8") as file:
file.write(data)

print("System logs are written to a file {}".format(fn_local))
print("System logs are written to a file {}".format(fn_local))
115 changes: 115 additions & 0 deletions reset_password.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Script to reset a forgotten root password (SSH/TELNET).
Attempts to connect via SSH (if password is saved in config) or via TELNET,
then sets a new password.

Usage:
./run.sh reset_password.py [new_password]
./run.sh reset_password.py --ip 192.168.31.1 new_password

Requirements:
- The device must be on the same network
- Either SSH (with known password) OR TELNET (usually password "root") must be accessible
"""

import sys
import time

import xmir_base
import gateway
from gateway import die


def reset_password_via_gateway(gw, new_passw):
"""Resets the password using an already connected gateway (SSH or TELNET)."""
gw.run_cmd('echo -e "{new_passw}\\n{new_passw}" | passwd root'.format(new_passw=new_passw))
time.sleep(0.5)
if gw.use_ssh:
gw.ssh_close()
else:
gw.shutdown()
if gw.check_ssh(gw.ip_addr, gw.ssh_port, new_passw) != 0:
die('Failed to verify the new password via SSH')
gw.passw = new_passw
print("Root password successfully changed.")


def main():
if len(sys.argv) > 1 and sys.argv[1] == '--ip':
if len(sys.argv) < 4:
die("Usage: reset_password.py --ip <IP> <new_password>")
ip_addr = sys.argv[2]
new_passw = sys.argv[3]
elif len(sys.argv) > 1:
new_passw = sys.argv[1]
ip_addr = None
else:
new_passw = input("Enter new password for root user: ")
ip_addr = None

new_passw = new_passw.strip()
if len(new_passw) == 0:
die('Password cannot be empty!')

# Create gateway without automatic SSH detection
gw = gateway.Gateway(detect_ssh=False)

if ip_addr:
gw.ip_addr = ip_addr
print("Using IP: {}".format(ip_addr))

if gw.status < 1:
gw.detect_device()
if gw.status < 1:
die("Xiaomi device not found (IP: {})".format(gw.ip_addr))

print("Device: {}".format(gw.device_name))
print("IP: {} SSH port: {}".format(gw.ip_addr, gw.ssh_port))

# 1. Try SSH with saved password (if present in memcfg)
if gw.passw:
ret = gw.check_ssh(gw.ip_addr, gw.ssh_port, gw.passw)
if ret >= 0:
print("SSH connection with saved password — OK")
gw.use_ssh = True
reset_password_via_gateway(gw, new_passw)
return

# 2. Try TELNET (password is usually "root" after unlock)
if not gw.check_telnet(timeout=3):
die("Neither SSH (with known password) nor TELNET is accessible.\n"
"Ensure TELNET is enabled on the device (telnet_en=1).")

print("TELNET detected. Attempting to connect...")

telnet_passwords = ['root']
if gw.passw and gw.passw != 'root':
telnet_passwords.insert(0, gw.passw)
if gw.xqpassword and gw.xqpassword not in telnet_passwords:
telnet_passwords.append(gw.xqpassword)

tn = None
used_passw = None
for psw in telnet_passwords:
tn = gw.get_telnet(verbose=0, password=psw)
if tn:
used_passw = psw
break

if not tn:
die("Failed to connect via TELNET.\n"
"Tried passwords: " + ", ".join(repr(p) for p in telnet_passwords) +
"\nTry the default password: root")

print("TELNET connection — OK (password: {})".format(repr(used_passw)))
gw.use_ssh = False
gw.passw = used_passw
gw.ping(verbose=0)

reset_password_via_gateway(gw, new_passw)


if __name__ == "__main__":
main()
96 changes: 96 additions & 0 deletions test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
XMiR Patcher environment diagnostic test.
Checks imports, configuration, and device availability.
"""

import sys

def main():
print("=" * 50)
print("XMiR Patcher — Environment Diagnostic")
print("=" * 50)

# 1. Import tests
print("\n[1] Imports...")
try:
import xmir_base
print(" xmir_base — OK")
except Exception as e:
print(" xmir_base — ERROR:", e)
return 1

try:
import gateway
print(" gateway — OK")
except Exception as e:
print(" gateway — ERROR:", e)
return 1

try:
import xqmodel
print(" xqmodel — OK")
except Exception as e:
print(" xqmodel — ERROR:", e)
return 1

try:
import read_info
print(" read_info — OK")
except Exception as e:
print(" read_info — ERROR:", e)

# 2. Configuration
print("\n[2] Configuration...")
try:
gw = gateway.Gateway(detect_device=False, detect_ssh=False)
print(" Device IP: {}".format(gw.ip_addr))
print(" SSH port: {}".format(gw.ssh_port))
if gw.passw:
print(" Password (memcfg): saved")
else:
print(" Password (memcfg): not set")
except PermissionError as e:
print(" Shared memory error (possibly sandboxed): {}".format(e))
gw = None
except Exception as e:
print(" Initialization error: {}".format(e))
gw = None

# 3. Device detection (without SSH)
print("\n[3] Device detection...")
if gw:
try:
gw.detect_device()
if gw.status >= 1:
print(" Device found: {}".format(gw.device_name))
print(" ROM: {} {}".format(gw.rom_version or "?", gw.rom_channel or ""))
else:
print(" Device not found (IP: {})".format(gw.ip_addr))
except SystemExit:
print(" Device unavailable or requires initial setup via WEB UI")
except Exception as e:
print(" Error: {}".format(e))
else:
print(" Skipped (Gateway not initialized)")

# 4. Supported models
print("\n[4] Known models (examples): R3G, R3P, RM2100, R4A, WR30...")
print(" Total in xqmodel: {} models".format(len(xqmodel.xqModelList)))

# 5. Unsupported models
print("\n[5] Unsupported features:")
print(" BE3600, BE2600 2.5G and other Wi-Fi 7 (BE-series) routers:")
print(" — Reason: use Qualcomm IPQ (ARM), not MediaTek MT7621 (MIPS)")
print(" — Breed bootloader and certain features are designed only for MIPS")
print(" — Supported models: R3G, R3P, RM2100")

print("\n" + "=" * 50)
print("Diagnostic completed.")
print("=" * 50)
return 0


if __name__ == "__main__":
sys.exit(main())