Add wimtools and startnet.cmd editor for boot.wim modification
- Added wimtools to offline packages and playbook verification - Webapp startnet.cmd editor: extract, view, edit, save back to boot.wim - Uses wimextract/wimupdate for in-place WIM modification - Dark-themed code editor with tab support and common command reference Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
114
webapp/app.py
114
webapp/app.py
@@ -29,6 +29,8 @@ app.config["MAX_CONTENT_LENGTH"] = 16 * 1024 * 1024 * 1024 # 16 GB max upload
|
||||
# ---------------------------------------------------------------------------
|
||||
SAMBA_SHARE = os.environ.get("SAMBA_SHARE", "/srv/samba/winpeapps")
|
||||
CLONEZILLA_SHARE = os.environ.get("CLONEZILLA_SHARE", "/srv/samba/clonezilla")
|
||||
WEB_ROOT = os.environ.get("WEB_ROOT", "/var/www/html")
|
||||
BOOT_WIM = os.path.join(WEB_ROOT, "win11", "sources", "boot.wim")
|
||||
|
||||
IMAGE_TYPES = [
|
||||
"gea-standard",
|
||||
@@ -638,6 +640,118 @@ def clonezilla_delete(filename):
|
||||
return redirect(url_for("clonezilla_backups"))
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Routes — startnet.cmd Editor (WIM)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _wim_extract_startnet(wim_path):
|
||||
"""Extract startnet.cmd from a WIM file using wimextract."""
|
||||
import tempfile
|
||||
tmpdir = tempfile.mkdtemp()
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["wimextract", wim_path, "1",
|
||||
"/Windows/System32/startnet.cmd",
|
||||
"--dest-dir", tmpdir],
|
||||
capture_output=True, text=True, timeout=30,
|
||||
)
|
||||
startnet_path = os.path.join(tmpdir, "startnet.cmd")
|
||||
if result.returncode == 0 and os.path.isfile(startnet_path):
|
||||
content = open(startnet_path, "r", encoding="utf-8", errors="replace").read()
|
||||
return content
|
||||
return None
|
||||
except Exception:
|
||||
return None
|
||||
finally:
|
||||
shutil.rmtree(tmpdir, ignore_errors=True)
|
||||
|
||||
|
||||
def _wim_update_startnet(wim_path, content):
|
||||
"""Update startnet.cmd inside a WIM file using wimupdate."""
|
||||
import tempfile
|
||||
tmpdir = tempfile.mkdtemp()
|
||||
try:
|
||||
startnet_path = os.path.join(tmpdir, "startnet.cmd")
|
||||
with open(startnet_path, "w", encoding="utf-8", newline="\r\n") as fh:
|
||||
fh.write(content)
|
||||
# wimupdate reads commands from stdin
|
||||
update_cmd = f"add {startnet_path} /Windows/System32/startnet.cmd\n"
|
||||
result = subprocess.run(
|
||||
["wimupdate", wim_path, "1"],
|
||||
input=update_cmd,
|
||||
capture_output=True, text=True, timeout=60,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
return False, result.stderr.strip()
|
||||
return True, ""
|
||||
except Exception as exc:
|
||||
return False, str(exc)
|
||||
finally:
|
||||
shutil.rmtree(tmpdir, ignore_errors=True)
|
||||
|
||||
|
||||
def _wim_list_files(wim_path, path="/"):
|
||||
"""List files inside a WIM at the given path."""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["wimdir", wim_path, "1", path],
|
||||
capture_output=True, text=True, timeout=30,
|
||||
)
|
||||
if result.returncode == 0:
|
||||
return [l.strip() for l in result.stdout.splitlines() if l.strip()]
|
||||
return []
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
|
||||
@app.route("/startnet")
|
||||
def startnet_editor():
|
||||
wim_exists = os.path.isfile(BOOT_WIM)
|
||||
content = ""
|
||||
wim_info = {}
|
||||
|
||||
if wim_exists:
|
||||
content = _wim_extract_startnet(BOOT_WIM) or ""
|
||||
# Get WIM info
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["wiminfo", BOOT_WIM],
|
||||
capture_output=True, text=True, timeout=15,
|
||||
)
|
||||
if result.returncode == 0:
|
||||
for line in result.stdout.splitlines():
|
||||
if ":" in line:
|
||||
key, _, val = line.partition(":")
|
||||
wim_info[key.strip()] = val.strip()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return render_template(
|
||||
"startnet_editor.html",
|
||||
wim_exists=wim_exists,
|
||||
wim_path=BOOT_WIM,
|
||||
content=content,
|
||||
wim_info=wim_info,
|
||||
image_types=IMAGE_TYPES,
|
||||
friendly_names=FRIENDLY_NAMES,
|
||||
)
|
||||
|
||||
|
||||
@app.route("/startnet/save", methods=["POST"])
|
||||
def startnet_save():
|
||||
if not os.path.isfile(BOOT_WIM):
|
||||
flash("boot.wim not found.", "danger")
|
||||
return redirect(url_for("startnet_editor"))
|
||||
|
||||
content = request.form.get("content", "")
|
||||
ok, err = _wim_update_startnet(BOOT_WIM, content)
|
||||
if ok:
|
||||
flash("startnet.cmd updated successfully in boot.wim.", "success")
|
||||
else:
|
||||
flash(f"Failed to update boot.wim: {err}", "danger")
|
||||
return redirect(url_for("startnet_editor"))
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Routes — API
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user