mirror of
https://github.com/Lakr233/vphone-cli.git
synced 2026-09-02 02:34:29 +00:00
cfw: Implement ramdisk-free host-mount CFW install
Add a host-mount install path that replaces the DFU + ramdisk_send +
iproxy + SSH transport: mount the VM's Disk.img volumes on the host, place
every CFW file locally, then flip the boot snapshot offline
(tools/apfs_snap_rename.py). The resulting VM is identical to the
ramdisk-installed one, minus the round-trips.
- cfw_host_mode.sh: sourced by cfw_install*.sh when CFW_HOST_MODE=1;
overrides ssh_cmd/scp_to/scp_from/remote_mount/remote_file_exists to run
locally against volumes mounted at $CFW_HOST_MNT/mnt{1,3,5} (host / is
read-only, so device /mntN tokens are remapped), routes /usr/bin/tar to
gtar (bsdtar lacks the GNU flags), and skips snaputil/dropbearkey/halt.
- cfw_install{,_dev,_jb,_exp}.sh: source the shim after their helper defs
(host-mode is opt-in; the SSH path is unchanged). Also reword progress
messages that assumed the ramdisk/SSH flow ("~3 minutes" scp, "to
device", "Reboot the device") to read correctly in both modes.
- cfw_install_host.sh + `make cfw_install_host VARIANT=regular|dev|jb|exp`:
attach the image, run the chosen installer under CFW_HOST_MODE as root,
detach, and run the offline snapshot flip. Restores ownership of the
host-side artifacts it creates (vm/.vphoned.signed, .cfw_temp, ...) to
the invoking user afterward, so a later user-run `make boot` isn't
blocked by root-owned files.
Runs as root (owners-honored mounts / chown / cp) via a sudo re-exec. No
authenticated-root/ARV change needed; mount_apfs -o rw honors owners.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XZVS9oqVNmHJzpb8mFtKJx
This commit is contained in:
committed by
zqxwce
co-authored by
Claude Opus 4.8
parent
b91f6f4575
commit
d28754e89e
@@ -130,6 +130,8 @@ help:
|
||||
@echo " make cfw_install_dev Install CFW mods via SSH (dev mode)"
|
||||
@echo " make cfw_install_jb Install CFW + JB extensions (jetsam/procursus/basebin)"
|
||||
@echo " make cfw_install_exp Install CFW + JB + EXP experimental (hv_vmm rename, post-restore DT, build spoof)"
|
||||
@echo " make cfw_install_host Ramdisk-free install: host-mount files + offline snapshot flip"
|
||||
@echo " Options: VARIANT=regular|dev|jb|exp (default exp) SPOOF_BUILD=<id> (exp)"
|
||||
@echo ""
|
||||
@echo "Variables: VM_DIR=$(VM_DIR) CPU=$(CPU) MEMORY=$(MEMORY) DISK_SIZE=$(DISK_SIZE)"
|
||||
|
||||
@@ -478,7 +480,7 @@ ramdisk_send:
|
||||
# CFW
|
||||
# ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
.PHONY: cfw_install cfw_install_dev cfw_install_jb cfw_install_exp
|
||||
.PHONY: cfw_install cfw_install_dev cfw_install_jb cfw_install_exp cfw_install_host
|
||||
|
||||
cfw_install:
|
||||
cd $(VM_DIR) && $(if $(SSH_PORT),SSH_PORT="$(SSH_PORT)") _VPHONE_PATH="$$PATH" zsh "$(CURDIR)/$(SCRIPTS)/cfw_install.sh" .
|
||||
@@ -491,3 +493,9 @@ cfw_install_jb:
|
||||
|
||||
cfw_install_exp:
|
||||
cd $(VM_DIR) && $(if $(SSH_PORT),SSH_PORT="$(SSH_PORT)") $(if $(SPOOF_BUILD),SPOOF_BUILD="$(SPOOF_BUILD)") _VPHONE_PATH="$$PATH" zsh "$(CURDIR)/$(SCRIPTS)/cfw_install_exp.sh" .
|
||||
|
||||
# Ramdisk-free CFW install: place files via host mount + flip boot snapshot
|
||||
# offline. No boot_dfu/ramdisk_send/iproxy/SSH. VM must be off. Re-execs sudo.
|
||||
# Options: VARIANT=regular|dev|jb|exp (default exp) SPOOF_BUILD=<id> (exp)
|
||||
cfw_install_host:
|
||||
$(if $(SPOOF_BUILD),SPOOF_BUILD="$(SPOOF_BUILD)") zsh "$(CURDIR)/$(SCRIPTS)/cfw_install_host.sh" --variant $(if $(VARIANT),$(VARIANT),exp) "$(VM_DIR_ABS)"
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# cfw_host_mode.sh — sourced by cfw_install*.sh when CFW_HOST_MODE=1.
|
||||
#
|
||||
# Replaces the SSH-to-ramdisk transport with local operations on the image
|
||||
# volumes mounted on the host (by the host driver). The rest of each
|
||||
# installer's logic (cfw.py patching, ldid signing, ipsw/aea cryptex decrypt,
|
||||
# hdiutil DMG mounts, xcrun builds, DSC/DT patchers) is already host-side and
|
||||
# runs unchanged. Must run as root. The boot-source flip the ramdisk did with
|
||||
# `snaputil` is done separately, offline, by tools/apfs_snap_rename.py.
|
||||
#
|
||||
# The host root (/) is read-only (SSV), so device paths /mnt1,/mnt3,/mnt5 are
|
||||
# remapped onto a writable scratch base (CFW_HOST_MNT). Only those exact
|
||||
# device tokens are remapped, so host source paths (e.g. .../mnt_sysos) are
|
||||
# left untouched.
|
||||
: "${CFW_HOST_CONTAINER:?CFW_HOST_MODE=1 but CFW_HOST_CONTAINER (host apfs container disk, e.g. disk20) unset}"
|
||||
CFW_HOST_MNT="${CFW_HOST_MNT:-/private/tmp/cfwhost}"
|
||||
/bin/mkdir -p "$CFW_HOST_MNT"
|
||||
_HOST_TAR="$(command -v gtar 2>/dev/null || echo /opt/homebrew/bin/gtar)"
|
||||
|
||||
_map() { # remap device /mntN tokens -> $CFW_HOST_MNT/mntN
|
||||
local s="$1"
|
||||
s="${s//\/mnt1/$CFW_HOST_MNT/mnt1}"
|
||||
s="${s//\/mnt2/$CFW_HOST_MNT/mnt2}"
|
||||
s="${s//\/mnt3/$CFW_HOST_MNT/mnt3}"
|
||||
s="${s//\/mnt5/$CFW_HOST_MNT/mnt5}"
|
||||
printf '%s' "$s"
|
||||
}
|
||||
|
||||
ssh_cmd() {
|
||||
local c="$*"
|
||||
case "$c" in
|
||||
*snaputil*) return 0 ;; # flip done offline
|
||||
*dropbearkey*) return 0 ;; # host keys made at first boot
|
||||
*dropbear_rsa_host_key*|*dropbear_ecdsa_host_key*) return 0 ;; # skip chmod of keys not created
|
||||
*/sbin/halt*) return 0 ;; # no VM to halt
|
||||
esac
|
||||
c="${c//\/usr\/bin\/tar/$_HOST_TAR}" # macOS bsdtar lacks GNU flags
|
||||
/bin/sh -c "$(_map "$c")"
|
||||
}
|
||||
scp_to() { /bin/cp -R "$(_map "$1")" "$(_map "$2")"; }
|
||||
scp_from() { /bin/cp "$(_map "$1")" "$(_map "$2")"; }
|
||||
remote_file_exists() { [[ -e "$(_map "$1")" ]]; }
|
||||
remote_mount() {
|
||||
local dev="$1" mnt opts="${3:-rw}"
|
||||
mnt="$(_map "$2")"
|
||||
local slice="${dev##*disk1}" # /dev/disk1sN -> sN
|
||||
local hostdev="/dev/${CFW_HOST_CONTAINER}${slice}"
|
||||
/bin/mkdir -p "$mnt"
|
||||
/sbin/mount | /usr/bin/grep -q " on $mnt " && return 0
|
||||
/sbin/mount_apfs -o "$opts" "$hostdev" "$mnt" 2>/dev/null || true
|
||||
/sbin/mount | /usr/bin/grep -q " on $mnt " || die "host mount failed: $hostdev -> $mnt"
|
||||
}
|
||||
wait_for_device_ssh_ready() { :; }
|
||||
@@ -242,6 +242,10 @@ cleanup_on_exit() {
|
||||
}
|
||||
trap cleanup_on_exit EXIT
|
||||
|
||||
# Host-mode transport override (CFW_HOST_MODE=1): run install against image
|
||||
# volumes mounted locally on the host instead of a device over SSH.
|
||||
[[ -n "${CFW_HOST_MODE:-}" ]] && source "$SCRIPT_DIR/cfw_host_mode.sh"
|
||||
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
# Main
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
@@ -274,7 +278,7 @@ echo ""
|
||||
echo "[1/7] Installing Cryptex (SystemOS + AppOS)..."
|
||||
|
||||
# Mount device rootfs first to check existing state
|
||||
echo " Mounting device rootfs rw..."
|
||||
echo " Mounting rootfs rw..."
|
||||
remote_mount /dev/disk1s1 /mnt1
|
||||
|
||||
# Rename APFS update snapshot to orig-fs (idempotent)
|
||||
@@ -305,7 +309,7 @@ CRYPTEX_OS_COUNT=$(ssh_cmd "/bin/ls /mnt1/System/Cryptexes/OS/ 2>/dev/null | /us
|
||||
CRYPTEX_APP_COUNT=$(ssh_cmd "/bin/ls /mnt1/System/Cryptexes/App/ 2>/dev/null | /usr/bin/wc -l" | tr -d ' ')
|
||||
|
||||
if [[ "${CRYPTEX_OS_COUNT:-0}" -gt 0 && "${CRYPTEX_APP_COUNT:-0}" -gt 0 ]]; then
|
||||
echo " [*] Cryptexes already installed on device (OS=${CRYPTEX_OS_COUNT} entries, App=${CRYPTEX_APP_COUNT} entries), skipping"
|
||||
echo " [*] Cryptexes already installed (OS=${CRYPTEX_OS_COUNT} entries, App=${CRYPTEX_APP_COUNT} entries), skipping"
|
||||
|
||||
# Still ensure dyld symlinks exist
|
||||
ssh_cmd "/bin/ln -sf ../../../System/Cryptexes/OS/System/Library/Caches/com.apple.dyld \
|
||||
@@ -357,7 +361,7 @@ else
|
||||
ssh_cmd "/bin/chmod 0755 /mnt1/System/Cryptexes/App /mnt1/System/Cryptexes/OS"
|
||||
|
||||
# Copy Cryptex files to device
|
||||
echo " Copying Cryptexes to device (this takes ~3 minutes)..."
|
||||
echo " Copying Cryptexes..."
|
||||
scp_to "$MNT_SYSOS/." "/mnt1/System/Cryptexes/OS"
|
||||
scp_to "$MNT_APPOS/." "/mnt1/System/Cryptexes/App"
|
||||
|
||||
@@ -430,7 +434,7 @@ ssh_cmd "/usr/bin/tar --preserve-permissions --no-overwrite-dir \
|
||||
-xf /mnt1/iosbinpack64.tar -C /mnt1"
|
||||
ssh_cmd "/bin/rm -f /mnt1/iosbinpack64.tar"
|
||||
|
||||
echo " Preparing dropbear host keys on Data volume..."
|
||||
echo " Setting up dropbear host keys..."
|
||||
ssh_cmd "/bin/mkdir -p /mnt3/dropbear"
|
||||
ssh_cmd "if [ ! -f /mnt3/dropbear/dropbear_rsa_host_key ]; then /usr/local/bin/dropbearkey -t rsa -f /mnt3/dropbear/dropbear_rsa_host_key >/dev/null; fi"
|
||||
ssh_cmd "if [ ! -f /mnt3/dropbear/dropbear_ecdsa_host_key ]; then /usr/local/bin/dropbearkey -t ecdsa -f /mnt3/dropbear/dropbear_ecdsa_host_key >/dev/null; fi"
|
||||
@@ -562,7 +566,7 @@ rm -f "$TEMP_DIR/seputil" \
|
||||
|
||||
echo ""
|
||||
echo "[+] CFW installation complete!"
|
||||
echo " Reboot the device for changes to take effect."
|
||||
echo " Reboot to apply changes."
|
||||
echo " After boot, SSH will be available on port 22222 (password: alpine)"
|
||||
|
||||
if [[ "$CFW_SKIP_HALT" == "1" ]]; then
|
||||
|
||||
@@ -213,6 +213,10 @@ cleanup_on_exit() {
|
||||
}
|
||||
trap cleanup_on_exit EXIT
|
||||
|
||||
# Host-mode transport override (CFW_HOST_MODE=1): run install against image
|
||||
# volumes mounted locally on the host instead of a device over SSH.
|
||||
[[ -n "${CFW_HOST_MODE:-}" ]] && source "$SCRIPT_DIR/cfw_host_mode.sh"
|
||||
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
# Main
|
||||
# ════════════════════════════════════════════════════════════════
|
||||
@@ -280,7 +284,7 @@ echo " Mounting AppOS..."
|
||||
sudo ${SUDO_ASKPASS:+-A} hdiutil attach -mountpoint "$MNT_APPOS" "$APPOS_DMG" -nobrowse -owners off
|
||||
|
||||
# Mount device rootfs (tolerate already-mounted)
|
||||
echo " Mounting device rootfs rw..."
|
||||
echo " Mounting rootfs rw..."
|
||||
remote_mount /dev/disk1s1 /mnt1
|
||||
|
||||
# Patch launchd jetsum guard
|
||||
@@ -343,7 +347,7 @@ ssh_cmd "/bin/mkdir -p /mnt1/System/Cryptexes/App /mnt1/System/Cryptexes/OS"
|
||||
ssh_cmd "/bin/chmod 0755 /mnt1/System/Cryptexes/App /mnt1/System/Cryptexes/OS"
|
||||
|
||||
# Copy Cryptex files to device
|
||||
echo " Copying Cryptexes to device (this takes ~3 minutes)..."
|
||||
echo " Copying Cryptexes..."
|
||||
scp_to "$MNT_SYSOS/." "/mnt1/System/Cryptexes/OS"
|
||||
scp_to "$MNT_APPOS/." "/mnt1/System/Cryptexes/App"
|
||||
|
||||
@@ -415,7 +419,7 @@ ssh_cmd "/usr/bin/tar --preserve-permissions --no-overwrite-dir \
|
||||
-xf /mnt1/iosbinpack64.tar -C /mnt1"
|
||||
ssh_cmd "/bin/rm -f /mnt1/iosbinpack64.tar"
|
||||
|
||||
echo " Preparing dropbear host keys on Data volume..."
|
||||
echo " Setting up dropbear host keys..."
|
||||
ssh_cmd "/bin/mkdir -p /mnt3/dropbear"
|
||||
ssh_cmd "if [ ! -f /mnt3/dropbear/dropbear_rsa_host_key ]; then /usr/local/bin/dropbearkey -t rsa -f /mnt3/dropbear/dropbear_rsa_host_key >/dev/null; fi"
|
||||
ssh_cmd "if [ ! -f /mnt3/dropbear/dropbear_ecdsa_host_key ]; then /usr/local/bin/dropbearkey -t ecdsa -f /mnt3/dropbear/dropbear_ecdsa_host_key >/dev/null; fi"
|
||||
@@ -544,7 +548,7 @@ rm -f "$TEMP_DIR/seputil" \
|
||||
|
||||
echo ""
|
||||
echo "[+] CFW installation complete!"
|
||||
echo " Reboot the device for changes to take effect."
|
||||
echo " Reboot to apply changes."
|
||||
echo " After boot, SSH will be available on port 22222 (password: alpine)"
|
||||
|
||||
if [[ "$CFW_SKIP_HALT" == "1" ]]; then
|
||||
|
||||
@@ -370,6 +370,10 @@ apply_dev_overlay() {
|
||||
die "Dev overlay not found (cfw_dev/rpcserver_ios)"
|
||||
}
|
||||
|
||||
# Host-mode transport override (CFW_HOST_MODE=1): run install against image
|
||||
# volumes mounted locally on the host instead of a device over SSH.
|
||||
[[ -n "${CFW_HOST_MODE:-}" ]] && source "$SCRIPT_DIR/cfw_host_mode.sh"
|
||||
|
||||
# ── Check JB prerequisites ────────────────────────────────────
|
||||
command -v zstd >/dev/null 2>&1 || die "'zstd' not found (required for JB bootstrap phase)"
|
||||
|
||||
@@ -761,7 +765,7 @@ rm -f "$TEMP_DIR/launchd" \
|
||||
|
||||
echo ""
|
||||
echo "[+] CFW + JB + EXP installation complete!"
|
||||
echo " Reboot the device for changes to take effect."
|
||||
echo " Reboot to apply changes."
|
||||
echo " After boot, SSH will be available on port 22222 (password: alpine)"
|
||||
|
||||
ssh_cmd "/sbin/halt" || true
|
||||
|
||||
Executable
+94
@@ -0,0 +1,94 @@
|
||||
#!/bin/zsh
|
||||
# cfw_install_host.sh — ramdisk-free CFW install.
|
||||
#
|
||||
# Replaces the DFU + ramdisk_send + iproxy + SSH install path: places every
|
||||
# CFW file by mounting the VM's Disk.img on the host (CFW_HOST_MODE, see
|
||||
# cfw_host_mode.sh) and flips the boot snapshot offline
|
||||
# (tools/apfs_snap_rename.py) so the VM boots the live volume. The resulting
|
||||
# VM is identical to the ramdisk-installed one, minus the ramdisk round-trips.
|
||||
#
|
||||
# Prereqs: VM restored (make restore) and powered off; host has gnu-tar, ipsw,
|
||||
# aea, ldid, zstd, project venv (make setup_tools). SIP disabled (project
|
||||
# baseline); NO authenticated-root/ARV change needed.
|
||||
#
|
||||
# Usage: cfw_install_host.sh [--variant regular|dev|jb|exp] [vm_dir]
|
||||
# Runs as root (mount_apfs/chown/cp to owners-honored mounts); re-execs under
|
||||
# sudo automatically (honors SUDO_ASKPASS for non-interactive use).
|
||||
set -euo pipefail
|
||||
SCRIPT_DIR="${0:a:h}"
|
||||
PROJ="${SCRIPT_DIR:h}"
|
||||
|
||||
VARIANT=exp
|
||||
VM_DIR="$PROJ/vm"
|
||||
while (( $# )); do
|
||||
case "$1" in
|
||||
--variant) VARIANT="$2"; shift 2 ;;
|
||||
*) VM_DIR="$1"; shift ;;
|
||||
esac
|
||||
done
|
||||
|
||||
case "$VARIANT" in
|
||||
regular) INSTALLER=cfw_install.sh ;;
|
||||
dev) INSTALLER=cfw_install_dev.sh ;;
|
||||
jb) INSTALLER=cfw_install_jb.sh ;;
|
||||
exp) INSTALLER=cfw_install_exp.sh ;;
|
||||
*) echo "[-] unknown variant: $VARIANT (regular|dev|jb|exp)" >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
# Re-exec as root; owners-honored mounts + chown/cp require it.
|
||||
if [[ "${EUID:-$(id -u)}" -ne 0 ]]; then
|
||||
exec sudo ${SUDO_ASKPASS:+-A} -E /bin/zsh "$0" --variant "$VARIANT" "$VM_DIR"
|
||||
fi
|
||||
unset SUDO_ASKPASS # already root: host_hdiutil/pre-step use plain sudo/hdiutil
|
||||
|
||||
VM_DIR="${VM_DIR:a}"
|
||||
IMG="$VM_DIR/Disk.img"
|
||||
[[ -f "$IMG" ]] || { echo "[-] no Disk.img at $IMG" >&2; exit 1; }
|
||||
|
||||
# Host-side install toolchain (gnu-tar/ipsw/aea/ldid/zstd + venv python).
|
||||
P="$PROJ/.tools/bin:$PROJ/.venv/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin"
|
||||
export PATH="$P"
|
||||
PY="$PROJ/.venv/bin/python3"
|
||||
|
||||
if lsof "$IMG" >/dev/null 2>&1; then
|
||||
echo "[-] $IMG is in use — stop the VM first." >&2; exit 1
|
||||
fi
|
||||
|
||||
echo "[*] host-mode CFW install: variant=$VARIANT vm=$VM_DIR"
|
||||
AO=$(hdiutil attach -nomount -imagekey diskimage-class=CRawDiskImage "$IMG" 2>/dev/null)
|
||||
BASEDISK=$(echo "$AO" | head -1 | awk '{print $1}')
|
||||
SYS=$(diskutil apfs list 2>/dev/null | awk '/APFS Volume Disk \(Role\):/{for(i=1;i<=NF;i++) if($i ~ /^disk[0-9]+s[0-9]+$/) dev=$i} /Name:.*System \(Case-sensitive\)/{print dev; exit}')
|
||||
CONT="${SYS%s*}"
|
||||
[[ -n "$CONT" ]] || { echo "[-] System volume not found in $IMG" >&2; hdiutil detach "$BASEDISK" 2>/dev/null; exit 1; }
|
||||
echo "[*] attached: container=$CONT system=$SYS"
|
||||
|
||||
cleanup() {
|
||||
for m in /private/tmp/cfwhost/mnt1 /private/tmp/cfwhost/mnt2 /private/tmp/cfwhost/mnt3 /private/tmp/cfwhost/mnt5; do
|
||||
umount "$m" 2>/dev/null || true
|
||||
done
|
||||
hdiutil detach "$BASEDISK" 2>/dev/null || diskutil eject "$BASEDISK" 2>/dev/null || true
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
echo "[*] running $INSTALLER in CFW_HOST_MODE (files placed on host mounts)..."
|
||||
( cd "$VM_DIR" && CFW_HOST_MODE=1 CFW_HOST_CONTAINER="$CONT" _VPHONE_PATH="$P" \
|
||||
${SPOOF_BUILD:+SPOOF_BUILD="$SPOOF_BUILD"} zsh "$SCRIPT_DIR/$INSTALLER" . )
|
||||
|
||||
cleanup
|
||||
trap - EXIT
|
||||
|
||||
echo "[*] flipping boot snapshot offline (com.apple.os.update -> live volume)..."
|
||||
"$PY" "$PROJ/tools/apfs_snap_rename.py" "$IMG"
|
||||
|
||||
# The whole install ran as root (owners-honored mounts / chown / cp). Hand the
|
||||
# host-side artifacts it created (vm/.vphoned.signed, vm/.cfw_temp, extracted
|
||||
# cfw_input/cfw_jb_input, the vphoned build) back to the invoking user, so the
|
||||
# subsequent user-run steps (make boot / setup_machine first boot, which rewrite
|
||||
# vm/.vphoned.signed) don't hit "Permission denied".
|
||||
if [[ -n "${SUDO_USER:-}" ]]; then
|
||||
chown -R "$SUDO_USER" "$VM_DIR" 2>/dev/null || true
|
||||
[[ -e "$PROJ/scripts/vphoned/vphoned" ]] && chown "$SUDO_USER" "$PROJ/scripts/vphoned/vphoned" 2>/dev/null || true
|
||||
echo "[*] restored ownership of host-side artifacts to $SUDO_USER"
|
||||
fi
|
||||
|
||||
echo "[+] host-mode CFW install complete. Boot with: make boot"
|
||||
@@ -201,6 +201,10 @@ apply_dev_overlay() {
|
||||
die "Dev overlay not found (cfw_dev/rpcserver_ios)"
|
||||
}
|
||||
|
||||
# Host-mode transport override (CFW_HOST_MODE=1): run the JB phases against
|
||||
# image volumes mounted locally on the host instead of a device over SSH.
|
||||
[[ -n "${CFW_HOST_MODE:-}" ]] && source "$SCRIPT_DIR/cfw_host_mode.sh"
|
||||
|
||||
# ── Check JB prerequisites ────────────────────────────────────
|
||||
command -v zstd >/dev/null 2>&1 || die "'zstd' not found (required for JB bootstrap phase)"
|
||||
|
||||
@@ -422,7 +426,7 @@ rm -f "$TEMP_DIR/launchd" \
|
||||
|
||||
echo ""
|
||||
echo "[+] CFW + JB installation complete!"
|
||||
echo " Reboot the device for changes to take effect."
|
||||
echo " Reboot to apply changes."
|
||||
echo " After boot, SSH will be available on port 22222 (password: alpine)"
|
||||
|
||||
ssh_cmd "/sbin/halt" || true
|
||||
|
||||
Reference in New Issue
Block a user