Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

os: format-and-install on blank SSDs (`w` in devices view)

Adds a true install path for unformatted disks the user just plugged
in (no GPT, no partitions, fully blank).

Three coordinated changes:

1. js-bindings.c flashTargets: enumerate whole disks (/dev/nvme0n1,
/dev/sda, /dev/mmcblk0, /dev/sdb) when the disk node exists but
its first partition does NOT. Tagged `blank: true` so the UI can
render them differently.

2. js-bindings.c flash_thread_fn: when the flash target is a whole
disk (no /sys/class/block/<dev>/partition file), partition + format
it first — wipe first 16 MiB, sfdisk single GPT ESP spanning the
disk (type C12A7328-…), poke kernel for partition reread, wait up
to 5s for the new partition node, mkfs.vfat. Then redirect
flash_device at the new partition and continue the existing
mount + copy flow. Uses the bundled initramfs sfdisk + mkfs.vfat
already present (no new tools).

3. os.mjs devices view: render blank disks with a yellow "blank" badge
instead of "usb"/"boot". Add `w` key handler that prompts confirmation
then routes through the existing clone-confirm UI. Clone-confirm
passes /mnt/initramfs.cpio.gz alongside the kernel so the freshly
flashed disk has both files (without the initramfs the new install
would panic with "no init" on first boot).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

+152 -9
+42 -9
fedac/native/pieces/os.mjs
··· 232 232 } 233 233 return; 234 234 } 235 + // 'w' to wipe + format + install onto a blank/unformatted disk. 236 + // The C flash_thread_fn detects the whole-disk target and runs 237 + // sfdisk + mkfs.vfat before the normal copy step, so this is just 238 + // an OTA update that targets the parent disk node. 239 + if (e.is("keyboard:down:w")) { 240 + const tgt = targets[deviceIdx]; 241 + if (tgt && tgt.blank) { 242 + cloneTarget = tgt; // re-use clone-confirm UI 243 + state = "clone-confirm"; // confirm before wiping 244 + sound?.synth({ type: "sawtooth", tone: 220, duration: 0.12, volume: 0.14, attack: 0.005, decay: 0.10 }); 245 + } else { 246 + // Not a blank disk — refuse with a low buzz. 247 + sound?.synth({ type: "square", tone: 110, duration: 0.15, volume: 0.10, attack: 0.005, decay: 0.12 }); 248 + } 249 + return; 250 + } 235 251 if (e.is("keyboard:down:escape") || e.is("keyboard:down:backspace")) { 236 252 state = "idle"; 237 253 return; ··· 239 255 return; 240 256 } 241 257 242 - // Clone confirmation 258 + // Clone confirmation (also reused for blank-disk wipe+install) 243 259 if (state === "clone-confirm") { 244 260 if (e.is("keyboard:down:y") || e.is("keyboard:down:enter") || e.is("keyboard:down:return")) { 245 261 state = "cloning"; 246 262 telemetry.length = 0; 247 - addTelemetry("cloning to " + cloneTarget.device); 248 - // Clone = flash the currently running kernel to the target device 249 - // The running kernel is at /mnt/EFI/BOOT/BOOTX64.EFI or KERNEL.EFI 263 + const verb = cloneTarget?.blank ? "wiping + installing" : "cloning"; 264 + addTelemetry(verb + " to " + cloneTarget.device); 265 + // Clone = flash the currently running kernel + initramfs to the 266 + // target device. /mnt is the partition this OS booted from, so 267 + // its EFI tree IS our running OS. Pass initramfs explicitly — 268 + // the kernel's baked-in cmdline expects /initramfs.cpio.gz at the 269 + // ESP root, and flash_thread_fn copies it when the third arg is 270 + // present. (Without this, a blank-disk install would boot the 271 + // kernel but immediately panic with "no init".) 250 272 const bootKernel = "/mnt/EFI/BOOT/BOOTX64.EFI"; 273 + const bootInitramfs = "/mnt/initramfs.cpio.gz"; 251 274 globalThis.__osFlashDevice = cloneTarget.device; 252 - system?.flashUpdate?.(bootKernel, cloneTarget.device); 275 + system?.flashUpdate?.(bootKernel, cloneTarget.device, bootInitramfs); 253 276 sound?.synth({ type: "triangle", tone: 784, duration: 0.1, volume: 0.12, attack: 0.003, decay: 0.08 }); 254 277 return; 255 278 } ··· 615 638 ink(80, 80, 100); 616 639 write(tgt.device, { x: pad + 100, y: ry, size: 1, font }); 617 640 618 - // Boot indicator 641 + // Boot / blank / usb indicator (precedence: boot > blank > usb). 619 642 if (isBoot) { 620 643 ink(60, 200, 120); 621 644 write("boot", { x: w - pad - 30, y: ry, size: 1, font }); 645 + } else if (tgt.blank) { 646 + ink(255, 180, 60); 647 + write("blank", { x: w - pad - 36, y: ry, size: 1, font }); 622 648 } else if (tgt.removable) { 623 649 ink(100, 140, 200); 624 650 write("usb", { x: w - pad - 24, y: ry, size: 1, font }); ··· 633 659 ink(80, 80, 100); 634 660 write("tab/arrows: select", { x: pad, y: actY, size: 1, font }); 635 661 636 - if (!isBootDev) { 662 + let hintY = actY + 14; 663 + if (sel?.blank) { 664 + // Blank disk — only meaningful action is wipe + format + install. 665 + ink(255, 180, 60); 666 + write("w: wipe + install (formats!)", { x: pad, y: hintY, size: 1, font }); 667 + hintY += 14; 668 + } else if (!isBootDev) { 637 669 ink(100, 200, 140); 638 - write("c: clone current os", { x: pad, y: actY + 14, size: 1, font }); 670 + write("c: clone current os", { x: pad, y: hintY, size: 1, font }); 671 + hintY += 14; 639 672 } 640 673 ink(100, 160, 220); 641 - write("u: update from cloud", { x: pad, y: actY + 28, size: 1, font }); 674 + write("u: update from cloud", { x: pad, y: hintY, size: 1, font }); 642 675 } 643 676 644 677 } else if (state === "clone-confirm") {
+110
fedac/native/src/js-bindings.c
··· 4024 4024 flash_trace("device exists mode=0%o", dev_st.st_mode); 4025 4025 } 4026 4026 4027 + // Whole-disk target? If flash_device names a disk (no /sys/.../partition 4028 + // file — that file only exists for partition nodes), partition + format 4029 + // it first, then redirect flash_device to the new ESP partition. Used 4030 + // for installing onto blank/unformatted SSDs the user just plugged in. 4031 + { 4032 + const char *base = strrchr(rt->flash_device, '/'); 4033 + base = base ? base + 1 : rt->flash_device; 4034 + char part_marker[128]; 4035 + snprintf(part_marker, sizeof(part_marker), "/sys/class/block/%s/partition", base); 4036 + int is_whole_disk = (access(part_marker, F_OK) != 0); 4037 + if (is_whole_disk) { 4038 + ac_log("[flash] %s is a whole disk — running format-and-install (sfdisk + mkfs.vfat)", rt->flash_device); 4039 + flash_tlog(rt, "format-and-install: whole disk %s", rt->flash_device); 4040 + // Wipe first 16 MiB so any old partition table / FS signatures 4041 + // don't confuse sfdisk or the kernel after re-read. 4042 + char cmd[512]; 4043 + snprintf(cmd, sizeof(cmd), 4044 + "dd if=/dev/zero of=%s bs=1M count=16 conv=fsync 2>&1", 4045 + rt->flash_device); 4046 + FILE *p = popen(cmd, "r"); 4047 + if (p) { 4048 + char buf[256]; 4049 + while (fgets(buf, sizeof(buf), p)) flash_tlog(rt, "wipe: %s", buf); 4050 + pclose(p); 4051 + } 4052 + // sfdisk: single GPT ESP spanning the whole disk. Type 4053 + // C12A7328-F81F-11D2-BA4B-00A0C93EC93B = EFI System Partition. 4054 + snprintf(cmd, sizeof(cmd), 4055 + "echo 'label: gpt\\nname=ACBOOT,type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B\\n' | " 4056 + "sfdisk --force --no-reread %s 2>&1", 4057 + rt->flash_device); 4058 + ac_log("[flash] sfdisk: %s", cmd); 4059 + int sfdisk_rc = -1; 4060 + p = popen(cmd, "r"); 4061 + if (p) { 4062 + char buf[256]; 4063 + while (fgets(buf, sizeof(buf), p)) ac_log("[flash] sfdisk: %s", buf); 4064 + sfdisk_rc = pclose(p); 4065 + } 4066 + ac_log("[flash] sfdisk exit=%d", sfdisk_rc); 4067 + // Tell the kernel to re-read the partition table. 4068 + char rereadcmd[256]; 4069 + snprintf(rereadcmd, sizeof(rereadcmd), "blockdev --rereadpt %s 2>/dev/null; partx -u %s 2>/dev/null", 4070 + rt->flash_device, rt->flash_device); 4071 + system(rereadcmd); 4072 + // Determine partition node name. NVMe + mmcblk use pN, sd* use N. 4073 + char part_node[64]; 4074 + if (strstr(rt->flash_device, "nvme") || strstr(rt->flash_device, "mmc")) 4075 + snprintf(part_node, sizeof(part_node), "%sp1", rt->flash_device); 4076 + else 4077 + snprintf(part_node, sizeof(part_node), "%s1", rt->flash_device); 4078 + // Wait up to 5s for the partition node to materialize. 4079 + int part_ready = 0; 4080 + for (int wait = 0; wait < 50; wait++) { 4081 + if (access(part_node, F_OK) == 0) { part_ready = 1; break; } 4082 + usleep(100000); 4083 + } 4084 + if (!part_ready) { 4085 + ac_log("[flash] partition %s did not appear after sfdisk", part_node); 4086 + flash_trace("partition %s missing after sfdisk", part_node); 4087 + flash_trace_close_and_archive(); 4088 + rt->flash_phase = 4; 4089 + rt->flash_ok = 0; 4090 + rt->flash_pending = 0; 4091 + rt->flash_done = 1; 4092 + return NULL; 4093 + } 4094 + // Format the new ESP as FAT32. 4095 + snprintf(cmd, sizeof(cmd), "mkfs.vfat -F 32 -n ACBOOT %s 2>&1", part_node); 4096 + int mkfs_rc = -1; 4097 + p = popen(cmd, "r"); 4098 + if (p) { 4099 + char buf[256]; 4100 + while (fgets(buf, sizeof(buf), p)) ac_log("[flash] mkfs: %s", buf); 4101 + mkfs_rc = pclose(p); 4102 + } 4103 + ac_log("[flash] mkfs.vfat %s exit=%d", part_node, mkfs_rc); 4104 + // Redirect the rest of flash_thread_fn at the new partition. 4105 + strncpy(rt->flash_device, part_node, sizeof(rt->flash_device) - 1); 4106 + rt->flash_device[sizeof(rt->flash_device) - 1] = 0; 4107 + ac_log("[flash] format-and-install: redirected to %s", rt->flash_device); 4108 + } 4109 + } 4110 + 4027 4111 // Mount the EFI partition for flashing. 4028 4112 // IMPORTANT: If the flash target is the same device already mounted at /mnt 4029 4113 // (e.g. NVMe-to-NVMe OTA), we MUST use /mnt directly. Mounting the same ··· 6431 6515 JS_SetPropertyStr(ctx, t, "label", 6432 6516 JS_NewString(ctx, rem[0] == '1' ? "USB (sdb)" : "Disk (sdb)")); 6433 6517 JS_SetPropertyStr(ctx, t, "removable", JS_NewBool(ctx, rem[0] == '1')); 6518 + JS_SetPropertyUint32(ctx, targets, idx++, t); 6519 + } 6520 + // Blank whole-disks — disks that exist but have no usable 6521 + // partition[1]. These need format-and-install (sfdisk → mkfs.vfat 6522 + // → write boot tree). Marked `blank: true` so os.mjs can render 6523 + // them differently and prompt before wiping. 6524 + struct { const char *disk; const char *part1; const char *label; const char *bus; } whole_disks[] = { 6525 + {"/dev/nvme0n1", "/dev/nvme0n1p1", "Internal (NVMe — blank)", "nvme0n1"}, 6526 + {"/dev/mmcblk0", "/dev/mmcblk0p1", "Internal (eMMC — blank)", "mmcblk0"}, 6527 + {"/dev/sda", "/dev/sda1", "Disk sda — blank", "sda"}, 6528 + {"/dev/sdb", "/dev/sdb1", "Disk sdb — blank", "sdb"}, 6529 + {NULL, NULL, NULL, NULL}, 6530 + }; 6531 + for (int i = 0; whole_disks[i].disk; i++) { 6532 + // Disk node must exist AND its first partition must NOT exist. 6533 + if (access(whole_disks[i].disk, F_OK) != 0) continue; 6534 + if (access(whole_disks[i].part1, F_OK) == 0) continue; // already partitioned — covered above 6535 + char rem[8] = {0}; 6536 + char rempath[64]; 6537 + snprintf(rempath, sizeof(rempath), "/sys/block/%s/removable", whole_disks[i].bus); 6538 + read_sysfs(rempath, rem, sizeof(rem)); 6539 + JSValue t = JS_NewObject(ctx); 6540 + JS_SetPropertyStr(ctx, t, "device", JS_NewString(ctx, whole_disks[i].disk)); 6541 + JS_SetPropertyStr(ctx, t, "label", JS_NewString(ctx, whole_disks[i].label)); 6542 + JS_SetPropertyStr(ctx, t, "removable", JS_NewBool(ctx, rem[0] == '1')); 6543 + JS_SetPropertyStr(ctx, t, "blank", JS_NewBool(ctx, 1)); 6434 6544 JS_SetPropertyUint32(ctx, targets, idx++, t); 6435 6545 } 6436 6546 JS_SetPropertyStr(ctx, sys, "flashTargets", targets);