Fiabiliser le simulateur et déverrouiller SpringBoard après installation #1
No files matched your search
@@ -146,3 +146,59 @@ Debug : `IPOD_QEMU_EXTRA="-d unimp,guest_errors -D ~/ipod-emu/run/int.log"` ; `I
|
||||
- `-f` efface la session persistée. Ne pas l'utiliser pour vérifier la conservation d'un fichier.
|
||||
- QEMU et netd sont lancés avec `setsid` pour survivre à la fin du terminal appelant. Le launcher suit netd par PID.
|
||||
- Un `.deb` 2.x qui dépend d'un jailbreak (bash, etc.) ne marchera pas : aucun shell dans l'image.
|
||||
|
||||
## Reprise du 30 septembre 2026 — après déplacement des homes
|
||||
|
||||
- Projets retrouvés sous `/srv/homes/iphoneos2/{ipod-emu,qemu-ios}`.
|
||||
- Bibliothèques QEMU/libslirp et ImageMagick réinstallées dans le conteneur courant ;
|
||||
lien BootROM 5H11a corrigé en relatif ; commandes accessibles par wrappers dans
|
||||
`/home/dev/.local/bin`. Ces installations locales ne modifient pas l'image Docker.
|
||||
- Lanceur adapté aux chemins déplacés, sélection automatique des keymaps via `-L`,
|
||||
contrôle du démarrage QEMU et du relais, nettoyage du relais même après arrêt QEMU.
|
||||
`ipod-qmp` prend en compte `IPOD_EMU_HOME`.
|
||||
- Test sur une copie de NAND dans `ipod-emu/work/reprise-20260930` : boot de l'image
|
||||
de base en 28 s, Safari et HTTP validés. `push-app HelloEmu.app` copie les deux
|
||||
fichiers, redémarre sans réinitialiser la NAND ; HelloEmu apparaît ensuite dans
|
||||
le catalogue `apps`. Le lancement répond toujours `device locked`, écran noir.
|
||||
Le programme de diagnostic `unlock` retourne 0 sans débloquer le lancement.
|
||||
Ne pas considérer le lancement après installation comme validé.
|
||||
- La copie de la session initiale est conservée dans
|
||||
`work/reprise-20260930/run-session-initiale` ; la session d'origine `run/nand`
|
||||
n'a pas été modifiée. Les captures et préférences de diagnostic sont dans le
|
||||
dossier de reprise. Les sessions de test ont été arrêtées.
|
||||
- Un ancien relais survivant à QEMU occupait 7788 : supprimé avant de refaire le
|
||||
test. L'ancien code continuait malgré l'échec de redirection ; le nouveau échoue.
|
||||
- Vérifications : syntaxe Bash/Python, compilation du relais avec `-Wall`,
|
||||
échec QEMU volontaire détecté immédiatement, port 7788 occupé détecté et QEMU
|
||||
arrêté, `stop` après échec. Aucun changement des modèles matériels dans cette reprise.
|
||||
|
||||
## Correction du verrouillage — agent v11
|
||||
|
||||
- `SBGetScreenLockStatus` confirme `locked=1 passcode=0` après redémarrage.
|
||||
`SBApplicationRequestedDeviceUnlock` réveille un clavier de code sans déverrouiller.
|
||||
- Solution validée : `SBDimScreen(port, false)`, attendre deux secondes, glisser
|
||||
`(60,450)` → `(319,450)`, attendre deux secondes, vérifier `locked=0`.
|
||||
Le geste historique `(40,430)` → `(280,430)` n'atteint pas correctement le bord
|
||||
de la surface tactile émulée. Home/Power et gestes lors de la reprise du pilote
|
||||
peuvent encore provoquer un arrêt QEMU ; aucun correctif matériel n'est revendiqué.
|
||||
- Agent v11 : commandes `screen` et `wake`. Client : `unlock`, vérification des
|
||||
marqueurs de disponibilité, refus si un code est actif, trois essais maximum.
|
||||
`start -W` / `wait` ne rendent la main avec succès qu'après déverrouillage.
|
||||
- Validations sans débogueur sur la session copiée : démarrage en 36 s ; nouvelle
|
||||
installation de HelloEmu avec `push-app`, redémarrage conservant la NAND en 47 s,
|
||||
`launch` réussi et `front` = `com.allovoisins.helloemu`. Capture :
|
||||
`work/reprise-20260930/hello-v11-apres-push.png`.
|
||||
- L'agent v11 a été installé atomiquement dans la session de test puis synchronisé
|
||||
avant redémarrage ; aucune relance à chaud de l'agent/PPP.
|
||||
Nouvelle image `images/5H11a-agent-v11` construite avec l'overlay de l'agent,
|
||||
sans modifier l'image 5H11a ni la NAND d'origine. L'image de base v10 doit être
|
||||
mise à jour avant d'utiliser le déverrouillage automatique.
|
||||
- La faute `diff_y` utilisant `x` dans `get_frame` reste à étudier séparément ;
|
||||
elle n'a pas été modifiée pour cette validation.
|
||||
|
||||
## Relecture avant merge
|
||||
|
||||
- Corrigé `start -W` sur une session déjà lancée : attendre et vérifier le
|
||||
déverrouillage avant de rendre la main, au lieu de retourner immédiatement.
|
||||
- Image distincte 5H11a-agent-v11 démarrée et déverrouillée en 27 s ; agent v11
|
||||
confirmé. Les deux sessions de test antérieures sont conservées séparément.
|
||||
@@ -1,12 +1,33 @@
|
||||
# Simulateur iPod Touch 2G (iPhone OS 2.2.1)
|
||||
|
||||
Émulateur [qemu-ios](https://git.mahtan-melwasul.com/Mahtan/qemu-ios) (branche iPod Touch 2G, N72AP), adapté pour
|
||||
démarrer **iPhone OS 2.2.1 (5H11a)**. iPhone OS 2.1.1 (5F138) reste disponible. Les outils sont dans `/opt/ios-legacy/bin`.
|
||||
démarrer **iPhone OS 2.2.1 (5H11a)**. iPhone OS 2.1.1 (5F138) reste disponible. Les outils sont dans `ipod-emu/bin` ; dans le workbench actuel, des wrappers les exposent via `/home/dev/.local/bin`.
|
||||
|
||||
## Environnement déplacé
|
||||
|
||||
Dans le workbench actuel, les projets sont sous `/srv/homes/iphoneos2` :
|
||||
`ipod-emu` contient les images et les outils, `qemu-ios` contient QEMU.
|
||||
Les outils utilisés directement depuis `ipod-emu/bin` retrouvent ce dossier ;
|
||||
le lanceur cherche QEMU dans le dossier voisin et transmet son dossier `pc-bios`
|
||||
pour retrouver les keymaps VNC après déplacement. `IPOD_EMU_HOME`, `IPOD_QEMU`,
|
||||
`IPOD_QEMU_DATA` et `IPOD_QMP` permettent de choisir d'autres chemins.
|
||||
`ipod-qmp` respecte également `IPOD_EMU_HOME` pour le socket de session.
|
||||
|
||||
Vérifier les liens symboliques des images après déplacement : le lien de
|
||||
`images/5H11a/bootrom` doit viser `../5F138/bootrom`, plutôt qu'un ancien home absolu.
|
||||
Sur Arch, le binaire construit dans cet environnement utilise notamment `pixman`,
|
||||
`libpng`, `libjpeg-turbo`, `sdl2` et `libslirp` ; les captures PNG utilisent
|
||||
`imagemagick`. Compiler le relais réseau demande aussi `pkgconf` et `glib2-devel`.
|
||||
Ces dépendances doivent être présentes dans chaque nouveau conteneur.
|
||||
|
||||
Le lanceur échoue explicitement si QEMU ou le relais réseau s'arrête au démarrage.
|
||||
Un port agent déjà occupé est une erreur : le relais ne poursuit plus sans sa
|
||||
redirection. `stop` nettoie le relais suivi par PID même si QEMU est déjà arrêté.
|
||||
|
||||
## Utilisation
|
||||
|
||||
```bash
|
||||
ipod-emu start -W # démarre 2.2.1 en conservant la NAND et attend SpringBoard (~25–50 s)
|
||||
ipod-emu start -W # agent v11 : conserve la NAND, attend SpringBoard et déverrouille (~35–50 s)
|
||||
# Ajouter -f uniquement pour remettre la NAND à zéro.
|
||||
ipod-qmp screenshot ecran.png # capture 320x480
|
||||
ipod-qmp tap 160 326 # touche (coordonnées écran), ipod-qmp tap X Y 1.5 = appui long
|
||||
@@ -21,11 +42,41 @@ ipod-emu stop
|
||||
- VNC sur `127.0.0.1:5900` pour interagir à la main (tunnel SSH : `ssh -L 5900:127.0.0.1:5900 …`).
|
||||
- Le lancement d'une app prend 10-20 s.
|
||||
|
||||
## Déverrouillage après redémarrage
|
||||
|
||||
Avec l'agent **v11**, `start -W` et `wait` vérifient le verrouillage, réveillent
|
||||
l'écran et effectuent le glissement normal avant de rendre la main.
|
||||
`ipod-agent screen` retourne `locked=0 passcode=0` une fois déverrouillé ;
|
||||
`ipod-agent unlock` permet de refaire ce parcours après démarrage.
|
||||
Si un code est activé, le client s'arrête et demande un déverrouillage manuel.
|
||||
Aucun geste n'est envoyé avant les marqueurs de démarrage du pilote tactile.
|
||||
|
||||
Le réveil utilise `SBDimScreen(port, false)`, puis un glissement de `(60,450)`
|
||||
à `(319,450)` adapté à la surface tactile du modèle. Le client laisse deux
|
||||
secondes au réveil et à la fin du geste, puis vérifie le verrouillage ; trois
|
||||
essais maximum. `SBApplicationRequestedDeviceUnlock` affiche le clavier de code
|
||||
sur 2.2.1 même sans code actif : ce n'est pas le parcours utilisé.
|
||||
|
||||
Une image contenant l'agent v10 doit être mise à jour avant d'utiliser ce workflow.
|
||||
Créer une image distincte préserve l'image de base :
|
||||
|
||||
```bash
|
||||
cd /srv/homes/iphoneos2/ipod-emu/agent
|
||||
PATH=/opt/cctools/bin:$PATH make
|
||||
ipod-mkimage -o 5H11a-agent-v11 overlay
|
||||
```
|
||||
|
||||
Le firmware se choisit avec `start -w 5H11a-agent-v11 -W`. Attention : comme pour
|
||||
tout changement de firmware, cette commande remplace la NAND du dossier `run` ;
|
||||
conserver sa session précédente ou utiliser un environnement de test séparé.
|
||||
Le dossier de diagnostic `work/reprise-20260930` conserve une session avec l'agent
|
||||
v11 et HelloEmu, indépendante de la session d'origine.
|
||||
|
||||
## Tester nos apps
|
||||
|
||||
```bash
|
||||
ipod-mkimage MonApp.app autre.ipa paquet.deb # -> images/5H11a-apps (base : -b 5H11a ou -b 5F138)
|
||||
ipod-emu start -f -W -w 5H11a-apps
|
||||
ipod-mkimage -b 5H11a-agent-v11 MonApp.app autre.ipa paquet.deb # -> images/5H11a-agent-v11-apps
|
||||
ipod-emu start -f -W -w 5H11a-agent-v11-apps
|
||||
ipod-agent launch com.exemple.monapp --log /private/var/mobile/monapp.log
|
||||
ipod-agent get /private/var/mobile/monapp.log
|
||||
|
||||
@@ -51,8 +102,10 @@ la toolchain de l'environnement (`arm-apple-darwin9-gcc -isysroot /opt/theos/sdk
|
||||
avant la fin du démarrage de SpringBoard.
|
||||
L'image de base est en français, région France, fuseau Europe/Paris.
|
||||
- **Relance de SpringBoard** : `respring` peut bloquer la reconstruction du catalogue d'apps. `push-app` redémarre
|
||||
donc l'émulateur. Après un redémarrage d'une session conservée, le verrouillage iOS peut encore empêcher un
|
||||
lancement (`device locked`) ; le lancement d'une app installée ainsi n'est pas encore validé.
|
||||
donc l'émulateur sans reconstruire l'image ni réinitialiser la NAND. Avec l'agent v11, le déverrouillage puis
|
||||
le lancement de HelloEmu au premier plan sont validés après cette installation. Les gestes Home/Power restent
|
||||
susceptibles de déclencher un défaut du pilote lors de la reprise de l'écran ; le workflow automatique utilise
|
||||
le réveil par l'API d'affichage et vérifie le verrouillage.
|
||||
- **Veille** : l'agent v10 pose `SleepDisabled` sur `IOPMrootDomain`, le SoC ne sachant pas reprendre une veille profonde.
|
||||
- Pas de son, pas d'accélération graphique (SpringBoard tourne avec `LK_ENABLE_MBX2D=0`).
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ struct rt_msghdr {
|
||||
#include <notify.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define VERSION "10"
|
||||
#define VERSION "11"
|
||||
#define PORT 7788
|
||||
#define PPP_TTY "/dev/tty.bluetooth"
|
||||
#define GUEST_IP "10.0.2.15"
|
||||
@@ -332,6 +332,9 @@ static void cmd_exec(int fd, char **args, int nargs)
|
||||
static int (*p_SBSLaunchApplication)(CFStringRef, CFURLRef, CFArrayRef, CFDictionaryRef, CFStringRef, CFStringRef, unsigned);
|
||||
static CFStringRef (*p_SBSApplicationLaunchingErrorString)(int);
|
||||
static CFStringRef (*p_SBSCopyFrontmostApplicationDisplayIdentifier)(void);
|
||||
static unsigned (*p_SBSSpringBoardServerPort)(void);
|
||||
static int (*p_SBGetScreenLockStatus)(unsigned, unsigned char *, unsigned char *);
|
||||
static int (*p_SBDimScreen)(unsigned, unsigned char);
|
||||
|
||||
static void load_sbs(void)
|
||||
{
|
||||
@@ -339,6 +342,9 @@ static void load_sbs(void)
|
||||
if (h) return;
|
||||
h = dlopen("/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices", RTLD_NOW);
|
||||
if (!h) return;
|
||||
p_SBSSpringBoardServerPort = dlsym(h, "SBSSpringBoardServerPort");
|
||||
p_SBGetScreenLockStatus = dlsym(h, "SBGetScreenLockStatus");
|
||||
p_SBDimScreen = dlsym(h, "SBDimScreen");
|
||||
p_SBSLaunchApplication = dlsym(h, "SBSLaunchApplication");
|
||||
p_SBSApplicationLaunchingErrorString = dlsym(h, "SBSApplicationLaunchingErrorString");
|
||||
p_SBSCopyFrontmostApplicationDisplayIdentifier = dlsym(h, "SBSCopyFrontmostApplicationDisplayIdentifier");
|
||||
@@ -350,6 +356,26 @@ static void cfstr(CFStringRef s, char *out, size_t len)
|
||||
if (s) CFStringGetCString(s, out, len, kCFStringEncodingUTF8);
|
||||
}
|
||||
|
||||
/* API MIG du firmware 2.2.1 : les deux états sont des octets, retour kern_return_t. */
|
||||
static void cmd_screen(int fd, int wake)
|
||||
{
|
||||
load_sbs();
|
||||
if (!p_SBSSpringBoardServerPort || !p_SBGetScreenLockStatus || !p_SBDimScreen) {
|
||||
reply_str(fd, 0, "API d'écran indisponible"); return;
|
||||
}
|
||||
unsigned port = p_SBSSpringBoardServerPort();
|
||||
unsigned char locked = 0, passcode = 0;
|
||||
int rc = p_SBGetScreenLockStatus(port, &locked, &passcode);
|
||||
if (rc) { reply_str(fd, 0, "SBGetScreenLockStatus : %d", rc); return; }
|
||||
if (wake) {
|
||||
/* SBApplicationRequestedDeviceUnlock affiche le clavier de code même
|
||||
sans code activé. Réveiller seulement l'écran, puis glisser côté hôte. */
|
||||
rc = p_SBDimScreen(port, 0);
|
||||
if (rc) { reply_str(fd, 0, "SBDimScreen : %d", rc); return; }
|
||||
}
|
||||
reply_str(fd, 1, "locked=%u passcode=%u", locked, passcode);
|
||||
}
|
||||
|
||||
static void cmd_launch(int fd, char **args, int nargs)
|
||||
{
|
||||
load_sbs();
|
||||
@@ -710,6 +736,8 @@ static void handle(int fd, char *line)
|
||||
else if (!strcmp(cmd, "exec")) cmd_exec(fd, a, na);
|
||||
else if (!strcmp(cmd, "launch")) cmd_launch(fd, a, na);
|
||||
else if (!strcmp(cmd, "front")) cmd_front(fd);
|
||||
else if (!strcmp(cmd, "screen")) cmd_screen(fd, 0);
|
||||
else if (!strcmp(cmd, "wake")) cmd_screen(fd, 1);
|
||||
else if (!strcmp(cmd, "fetch")) cmd_fetch(fd, a, na);
|
||||
else if (!strcmp(cmd, "sc")) cmd_sc(fd, a, na);
|
||||
else if (!strcmp(cmd, "routes")) cmd_routes(fd);
|
||||
@@ -733,7 +761,7 @@ static void handle(int fd, char *line)
|
||||
else if (!strcmp(cmd, "net")) cmd_net(fd);
|
||||
else if (!strcmp(cmd, "respring")) reply_str(fd, kill_by_name("SpringBoard", SIGTERM) > 0, "SpringBoard relancé");
|
||||
else if (!strcmp(cmd, "sync")) { sync(); reply_str(fd, 1, "ok"); }
|
||||
else reply_str(fd, 0, "commande inconnue : %s (ping exec launch fetch sc routes settime front apps put get ls rm mkdir ps kill net respring sync)", cmd);
|
||||
else reply_str(fd, 0, "commande inconnue : %s (ping exec launch fetch sc routes settime screen wake front apps put get ls rm mkdir ps kill net respring sync)", cmd);
|
||||
}
|
||||
|
||||
static void serve_client(int fd)
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
lance une app (stdout/stderr, donc NSLog, dans F sur l'iPod ; URL à ouvrir)
|
||||
ipod-agent fetch http://hôte/chemin requête HTTP depuis l'iPod (test réseau : DNS + TCP)
|
||||
ipod-agent front app au premier plan
|
||||
ipod-agent screen | wake état du verrouillage / réveil sans clavier de code (agent v11)
|
||||
ipod-agent unlock réveille puis glisse et vérifie le déverrouillage (sans code)
|
||||
ipod-agent exec PROG [ARGS...] exécute un programme (pas de shell : chemin absolu)
|
||||
ipod-agent ps | net | respring | sync
|
||||
ipod-agent kill PID|NOM [SIGNAL]
|
||||
@@ -51,15 +53,63 @@ def out(body):
|
||||
sys.stdout.buffer.write(b"\n")
|
||||
|
||||
|
||||
def emu_home():
|
||||
tools_home = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
default_home = tools_home if os.path.isdir(os.path.join(tools_home, "images")) else os.path.expanduser("~/ipod-emu")
|
||||
return os.environ.get("IPOD_EMU_HOME", default_home)
|
||||
|
||||
|
||||
def unlock(a):
|
||||
def screen():
|
||||
ok, body, _ = a.call("screen")
|
||||
if not ok:
|
||||
sys.exit("État d'écran indisponible (agent v11 requis) : " + body.decode())
|
||||
return dict(field.split("=", 1) for field in body.decode().split())
|
||||
|
||||
state = screen()
|
||||
if state.get("locked") == "0":
|
||||
print("Écran déverrouillé")
|
||||
return
|
||||
if state.get("passcode") != "0":
|
||||
sys.exit("Un code de verrouillage est activé : déverrouiller manuellement.")
|
||||
# Le pilote tactile doit avoir terminé son démarrage avant tout glissement.
|
||||
try:
|
||||
with open(os.path.join(emu_home(), "run", "serial.log"), "rb") as f:
|
||||
serial = f.read()
|
||||
except OSError as e:
|
||||
sys.exit(f"Console de session inaccessible : {e}")
|
||||
helper_ready = any(b"SCHelper" in line and b'"EXIT"' in line for line in serial.splitlines())
|
||||
if serial.count(b"AppleMultitouchSPIUserClient::attach") < 2 or not helper_ready:
|
||||
sys.exit("Contrôleur tactile pas encore prêt : attendre ipod-emu wait.")
|
||||
qmp = os.path.join(os.path.dirname(os.path.abspath(__file__)), "ipod-qmp")
|
||||
sock = os.environ.get("IPOD_QMP", os.path.join(emu_home(), "run", "qmp.sock"))
|
||||
for attempt in range(3):
|
||||
ok, body, _ = a.call("wake")
|
||||
if not ok:
|
||||
sys.exit(body.decode())
|
||||
time.sleep(2) # laisser le pilote réactiver l'écran et le tactile
|
||||
# La surface tactile émulée est légèrement plus petite que l'écran :
|
||||
# le geste doit atteindre le bord droit pour terminer le déverrouillage.
|
||||
subprocess.run([qmp, "-s", sock, "swipe", "60", "450", "319", "450"], check=True)
|
||||
time.sleep(2)
|
||||
state = screen()
|
||||
if state.get("locked") == "0":
|
||||
print("Écran déverrouillé")
|
||||
return
|
||||
if state.get("passcode") != "0":
|
||||
sys.exit("Un code de verrouillage est activé : déverrouiller manuellement.")
|
||||
sys.exit("Écran toujours verrouillé après trois glissements.")
|
||||
|
||||
|
||||
def push_app(a, app):
|
||||
emu_home = os.environ.get("IPOD_EMU_HOME", os.path.expanduser("~/ipod-emu"))
|
||||
run = os.path.join(emu_home, "run")
|
||||
home = emu_home()
|
||||
run = os.path.join(home, "run")
|
||||
try:
|
||||
with open(os.path.join(run, "nand", ".ipod-nand-format")) as f:
|
||||
layout = f.read().strip()
|
||||
with open(os.path.join(run, "fw")) as f:
|
||||
firmware = f.read().strip()
|
||||
with open(os.path.join(emu_home, "images", firmware, "machine-opts")) as f:
|
||||
with open(os.path.join(home, "images", firmware, "machine-opts")) as f:
|
||||
machine_opts = f.read()
|
||||
except OSError:
|
||||
sys.exit("push-app nécessite une image locale avec persistance NAND (ipod-mkimage / ipod-build-fw).")
|
||||
@@ -120,6 +170,10 @@ def main():
|
||||
except OSError as e:
|
||||
sys.exit(f"agent injoignable sur {HOST}:{PORT} ({e}) — ipod-netd lancé ?")
|
||||
|
||||
if cmd == "unlock":
|
||||
a.s.settimeout(15)
|
||||
unlock(a)
|
||||
return
|
||||
if cmd == "get":
|
||||
ok, body, _ = a.call("get", rest[0])
|
||||
if not ok:
|
||||
|
||||
@@ -2,8 +2,13 @@
|
||||
# Lance / arrête l'émulateur iPod Touch 2G (qemu-ios, N72AP).
|
||||
set -euo pipefail
|
||||
|
||||
EMU_HOME="${IPOD_EMU_HOME:-$HOME/ipod-emu}"
|
||||
QEMU="${IPOD_QEMU:-$HOME/qemu-ios/build/qemu-system-arm}"
|
||||
TOOLS_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
|
||||
DEFAULT_EMU_HOME="$HOME/ipod-emu"
|
||||
# Les outils peuvent être utilisés directement depuis un home de toolchain déplacé.
|
||||
[ ! -d "$TOOLS_DIR/../images" ] || DEFAULT_EMU_HOME=$(cd "$TOOLS_DIR/.." && pwd)
|
||||
EMU_HOME="${IPOD_EMU_HOME:-$DEFAULT_EMU_HOME}"
|
||||
QEMU="${IPOD_QEMU:-$(dirname "$EMU_HOME")/qemu-ios/build/qemu-system-arm}"
|
||||
QEMU_DATA="${IPOD_QEMU_DATA:-$(dirname "$(dirname "$QEMU")")/pc-bios}"
|
||||
FW="${IPOD_FW:-5H11a}" # dossier $EMU_HOME/images/<FW>/ : bootrom, nor.bin, nand/ (5H11a = 2.2.1, 5F138 = 2.1.1)
|
||||
RUN="$EMU_HOME/run"
|
||||
VNC="${IPOD_VNC:-127.0.0.1:0}" # :0 => port 5900
|
||||
@@ -39,7 +44,9 @@ wait_ready() {
|
||||
[ $((SECONDS - s)) -lt "$t" ] || { echo "Timeout : SpringBoard pas prêt après ${t}s" >&2; return 1; }
|
||||
sleep 2
|
||||
done
|
||||
sleep 3; echo "SpringBoard prêt ($((SECONDS - s)) s)"
|
||||
sleep 3
|
||||
"$(dirname "$0")/ipod-agent" unlock
|
||||
echo "SpringBoard prêt et déverrouillé ($((SECONDS - s)) s)"
|
||||
}
|
||||
|
||||
pid() { [ -f "$RUN/qemu.pid" ] && kill -0 "$(cat "$RUN/qemu.pid")" 2>/dev/null && cat "$RUN/qemu.pid"; }
|
||||
@@ -61,11 +68,22 @@ start)
|
||||
while getopts "fWw:" o; do case $o in f) fresh=1 ;; W) waitr=1 ;; w) FW=$OPTARG ;; *) usage 1 ;; esac; done
|
||||
img="$EMU_HOME/images/$FW"
|
||||
[ -d "$img" ] || { echo "Firmware inconnu : $img" >&2; exit 1; }
|
||||
[ -z "$(pid)" ] || { echo "Déjà lancé (pid $(pid))"; exit 0; }
|
||||
if [ -n "$(pid)" ]; then
|
||||
echo "Déjà lancé (pid $(pid))"
|
||||
[ $waitr = 0 ] || wait_ready
|
||||
exit 0
|
||||
fi
|
||||
[ -x "$QEMU" ] || { echo "QEMU introuvable : $QEMU (définir IPOD_QEMU)" >&2; exit 1; }
|
||||
[ -r "$img/bootrom" ] || { echo "BootROM introuvable : $img/bootrom (vérifier les liens après déplacement du home)" >&2; exit 1; }
|
||||
[ -x "$EMU_HOME/netd/ipod-netd" ] || { echo "Relais réseau introuvable : $EMU_HOME/netd/ipod-netd" >&2; exit 1; }
|
||||
"$QEMU" --version >/dev/null
|
||||
qemu_data_args=()
|
||||
[ ! -d "$QEMU_DATA/keymaps" ] || qemu_data_args=(-L "$QEMU_DATA")
|
||||
mkdir -p "$RUN"
|
||||
if [ $fresh = 1 ] || [ ! -d "$RUN/nand" ] || [ "$(cat "$RUN/fw" 2>/dev/null)" != "$FW" ]; then
|
||||
rm -rf "$RUN/nand"; cp -rL "$img/nand" "$RUN/nand"; echo "$FW" > "$RUN/fw"
|
||||
fi
|
||||
stop_netd
|
||||
rm -f "$RUN/qmp.sock" "$RUN/serial.log"
|
||||
mopts=$(cat "$img/machine-opts" 2>/dev/null || true) # ex. ",legacy-nor=off"
|
||||
if [[ "$mopts" == *",nand-write=on"* ]] &&
|
||||
@@ -74,21 +92,44 @@ start)
|
||||
exit 1
|
||||
fi
|
||||
nohup setsid "$QEMU" -M "iPod-Touch,bootrom=$img/bootrom,nand=$RUN/nand,nor=$img/nor.bin$mopts" \
|
||||
-cpu max -m 2G -serial "file:$RUN/serial.log" -serial "unix:$RUN/uart1.sock,server=on,wait=off" \
|
||||
"${qemu_data_args[@]}" -cpu max -m 2G -serial "file:$RUN/serial.log" -serial "unix:$RUN/uart1.sock,server=on,wait=off" \
|
||||
-display none -vnc "$VNC" -qmp "unix:$RUN/qmp.sock,server,nowait" \
|
||||
-pidfile "$RUN/qemu.pid" ${IPOD_QEMU_EXTRA:-} > "$RUN/qemu.log" 2>&1 &
|
||||
for _ in $(seq 50); do [ -S "$RUN/qmp.sock" ] && break; sleep 0.2; done
|
||||
qemu_pid=$!
|
||||
for _ in $(seq 50); do
|
||||
if ! kill -0 "$qemu_pid" 2>/dev/null; then
|
||||
echo "Échec du démarrage de QEMU :" >&2
|
||||
cat "$RUN/qemu.log" >&2
|
||||
exit 1
|
||||
fi
|
||||
[ ! -S "$RUN/qmp.sock" ] || [ -z "$(pid)" ] || break
|
||||
sleep 0.2
|
||||
done
|
||||
if [ ! -S "$RUN/qmp.sock" ] || [ -z "$(pid)" ]; then
|
||||
kill "$qemu_pid" 2>/dev/null || true
|
||||
echo "QEMU n'a pas ouvert son socket QMP (voir $RUN/qemu.log)" >&2
|
||||
exit 1
|
||||
fi
|
||||
# réseau : PPP sur l'UART1 -> slirp (NAT, DNS, 127.0.0.1:7788 -> agent de l'iPod)
|
||||
stop_netd
|
||||
nohup setsid "$EMU_HOME/netd/ipod-netd" -s "$RUN/uart1.sock" ${IPOD_NETD_FWD:-} > "$RUN/netd.log" 2>&1 &
|
||||
echo "$!" > "$RUN/netd.pid"
|
||||
netd_pid=$!
|
||||
echo "$netd_pid" > "$RUN/netd.pid"
|
||||
sleep 0.3
|
||||
if ! kill -0 "$netd_pid" 2>/dev/null; then
|
||||
echo "Échec du relais réseau :" >&2
|
||||
cat "$RUN/netd.log" >&2
|
||||
"$(dirname "$0")/ipod-qmp" -s "$RUN/qmp.sock" quit 2>/dev/null || kill "$qemu_pid"
|
||||
stop_netd
|
||||
exit 1
|
||||
fi
|
||||
echo "Démarré ($FW) — pid $(pid), VNC $VNC. SpringBoard apparaît en ~1 min."
|
||||
echo "Logs iOS : $RUN/serial.log"
|
||||
[ $waitr = 0 ] || wait_ready
|
||||
;;
|
||||
wait) wait_ready "${1:-300}" ;;
|
||||
stop)
|
||||
p=$(pid) || { echo "Pas lancé"; exit 0; }
|
||||
p=$(pid) || { stop_netd; echo "Pas lancé"; exit 0; }
|
||||
"$(dirname "$0")/ipod-qmp" -s "$RUN/qmp.sock" quit 2>/dev/null || kill "$p"
|
||||
for _ in $(seq 50); do kill -0 "$p" 2>/dev/null || break; sleep 0.2; done
|
||||
kill -0 "$p" 2>/dev/null && kill -9 "$p"
|
||||
|
||||
@@ -59,7 +59,10 @@ def key(q, qcode):
|
||||
|
||||
def main():
|
||||
p = argparse.ArgumentParser(usage=__doc__)
|
||||
p.add_argument("-s", "--sock", default=os.environ.get("IPOD_QMP", os.path.expanduser("~/ipod-emu/run/qmp.sock")))
|
||||
tools_home = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
default_home = tools_home if os.path.isdir(os.path.join(tools_home, "images")) else os.path.expanduser("~/ipod-emu")
|
||||
emu_home = os.environ.get("IPOD_EMU_HOME", default_home)
|
||||
p.add_argument("-s", "--sock", default=os.environ.get("IPOD_QMP", os.path.join(emu_home, "run", "qmp.sock")))
|
||||
p.add_argument("action")
|
||||
p.add_argument("args", nargs="*")
|
||||
a = p.parse_args()
|
||||
|
||||
@@ -556,6 +556,8 @@ static void add_fwd(const char *spec)
|
||||
}
|
||||
if (slirp_add_hostfwd(slirp, 0, host, hp, guest, gp) < 0) {
|
||||
logm("redirection %s impossible (port occupé ?)", spec);
|
||||
/* Ne pas laisser le client contacter le relais d'une autre session. */
|
||||
exit(1);
|
||||
} else {
|
||||
logm("redirection tcp %s:%d -> iPod:%d", inet_ntoa(host), hp, gp);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user