buninu-linux 0.7.0 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +147 -20
- package/build-uki.sh +1 -5
- package/fetch-alpine.sh +16 -0
- package/graphics.md +23 -7
- package/initramfs/bin/bunterm +3 -1
- package/initramfs/buninu/CHANGELOG.md +8 -0
- package/initramfs/buninu/README.md +1 -0
- package/initramfs/buninu/package.json +2 -2
- package/initramfs/init.js +26 -0
- package/initramfs/lib/bunterm/clipboard.js +51 -0
- package/initramfs/lib/bunterm/terminal.js +5 -0
- package/initramfs/usr/share/doc/buninu-linux/bunterm.md +14 -2
- package/package.json +1 -1
- package/scripts/pack-initramfs.sh +23 -0
package/README.md
CHANGED
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
* `start` starts the Buninu userspace shell
|
|
37
37
|
* `cfg.disk` + shell `mount` mounts local disks
|
|
38
38
|
* `cfg.net` loads common wired NIC and Android USB-tethering drivers
|
|
39
|
+
* `cfg.sound` loads every packaged ALSA sound module
|
|
39
40
|
* Android phone USB tethering over RNDIS has been tested successfully, allowing Buninu Linux to access the Internet through an Android phone
|
|
40
41
|
* IP addresses and routes are configured manually because the image does not yet include a DHCP client.
|
|
41
42
|
* The bundled `jmi` editor, jsmdcui App runtime, and local JavaScript execution also work.
|
|
@@ -45,6 +46,7 @@
|
|
|
45
46
|
+ Also has mouse click, wheel, and cursor drawing
|
|
46
47
|
+ Simplified browser works: @sanohiro/casty in chroot debian
|
|
47
48
|
+ (Use at your own risk: We haven't fully examined its code)
|
|
49
|
+
+ Playing YouTube with sound (experimental); see [Playing YouTube with sound](#playing-youtube-with-sound-experimental)
|
|
48
50
|
+ See [Commands inside `/bin`](#commands-inside-bin) for browser usage instructions
|
|
49
51
|
|
|
50
52
|
---
|
|
@@ -142,7 +144,7 @@ display and USB keyboard with a welcome ending like this:
|
|
|
142
144
|
Welcome to Buninu Linux!
|
|
143
145
|
Bun 1.4.2 is now PID 1
|
|
144
146
|
Type start() to run buninu --local
|
|
145
|
-
Configuration getters: cfg.all, cfg.disk, cfg.net, cfg.power
|
|
147
|
+
Configuration getters: cfg.all, cfg.disk, cfg.net, cfg.power, cfg.sound
|
|
146
148
|
|
|
147
149
|
bun-repl>
|
|
148
150
|
```
|
|
@@ -157,6 +159,7 @@ Load only the subsystem needed, then enter the Buninu shell:
|
|
|
157
159
|
cfg.net // wired NIC and Android USB-tethering drivers
|
|
158
160
|
cfg.disk // SATA/NVMe/USB storage drivers and detected block devices
|
|
159
161
|
cfg.power // battery, AC, button and thermal drivers
|
|
162
|
+
cfg.sound // all packaged ALSA sound modules and detected sound devices
|
|
160
163
|
start()
|
|
161
164
|
```
|
|
162
165
|
|
|
@@ -208,6 +211,8 @@ bun ./index.js -fbr
|
|
|
208
211
|
The first boot line from `run-qemu.sh` names the guest, machine, accelerator
|
|
209
212
|
and firmware it picked. A bare `-r` boots whichever architecture `vda.img`
|
|
210
213
|
was last built for; `-br --arch arm64` is the aarch64 edit-and-boot loop.
|
|
214
|
+
To run `bunterm` in a QEMU window on the aarch64 guest, see
|
|
215
|
+
[What differs on aarch64](#what-differs-on-aarch64).
|
|
211
216
|
|
|
212
217
|
#### amd64 Linux
|
|
213
218
|
|
|
@@ -231,9 +236,32 @@ qemu-efi-aarch64` to run.
|
|
|
231
236
|
Alpine's aarch64 packages and `bun-linux-aarch64-musl`.
|
|
232
237
|
* The serial console is `ttyAMA0` (QEMU `virt`'s PL011) instead of `ttyS0`.
|
|
233
238
|
* `--real` is x86_64 only: its module set is PC hardware.
|
|
234
|
-
*
|
|
235
|
-
|
|
236
|
-
|
|
239
|
+
* QEMU's `virt` machine has no display or PS/2 devices, so by default
|
|
240
|
+
`bunterm` has nothing to draw on; the serial REPL and the Buninu shell work
|
|
241
|
+
as on x86_64. To run `bunterm`, build with `--linux-lts` and give QEMU a
|
|
242
|
+
`ramfb` display and virtio input devices. On a Mac, `-display cocoa` opens
|
|
243
|
+
the window:
|
|
244
|
+
|
|
245
|
+
```sh
|
|
246
|
+
bun ./index.js -fbr --arch arm64 --linux-lts -- \
|
|
247
|
+
-device ramfb -device virtio-keyboard-pci -device virtio-mouse-pci -display cocoa
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Once that image is built, boot it again without rebuilding (and without
|
|
251
|
+
Docker). `--linux-lts` belongs to the build, so leave it off `-r`:
|
|
252
|
+
|
|
253
|
+
```sh
|
|
254
|
+
bun ./index.js -r --arch arm64 -- \
|
|
255
|
+
-device ramfb -device virtio-keyboard-pci -device virtio-mouse-pci -display cocoa
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
`start()` in the serial REPL, then `bunterm 2` opens bunterm on VT 2 in the
|
|
259
|
+
QEMU window and returns to the serial shell; type into the window. The
|
|
260
|
+
serial console is not a VT, so a bare `bunterm` there takes the active VT 1
|
|
261
|
+
and holds the serial shell until it exits; naming another VT starts it
|
|
262
|
+
detached (see [Multiple virtual consoles with bunterm](#multiple-virtual-consoles-with-bunterm)). The
|
|
263
|
+
firmware sets up ramfb at 800×600, and `init.js` loads `simpledrm` so it
|
|
264
|
+
becomes `/dev/fb0` (see [graphics.md](graphics.md#trying-it)).
|
|
237
265
|
* `--export` writes `buninu-linux-<version>-aarch64.img`.
|
|
238
266
|
* Before the kernel starts, Homebrew's aarch64 EDK2 prints a few
|
|
239
267
|
`Error: Image at … start failed` lines (its own drivers for hardware `virt`
|
|
@@ -283,6 +311,7 @@ Load only the hardware subsystem you need:
|
|
|
283
311
|
cfg.net
|
|
284
312
|
cfg.disk
|
|
285
313
|
cfg.power
|
|
314
|
+
cfg.sound
|
|
286
315
|
```
|
|
287
316
|
|
|
288
317
|
`cfg.net` loads the packaged wired-network and Android USB-tethering drivers and prints detected
|
|
@@ -298,7 +327,10 @@ ip route add default via 192.168.1.1
|
|
|
298
327
|
The real image initializes `/etc/resolv.conf` with `1.1.1.1` and `8.8.8.8`;
|
|
299
328
|
replace them if your network requires different DNS servers. `cfg.disk` loads
|
|
300
329
|
common SATA/PATA/SCSI, NVMe/VMD and USB-storage drivers so detected disks and
|
|
301
|
-
partitions appear in `/dev`.
|
|
330
|
+
partitions appear in `/dev`. `cfg.sound` unconditionally loads every sound
|
|
331
|
+
module packaged in the image, then lists the resulting `/dev/snd` devices; it
|
|
332
|
+
does not probe the hardware before loading modules. To inspect a filesystem
|
|
333
|
+
without mounting it:
|
|
302
334
|
|
|
303
335
|
```sh
|
|
304
336
|
mount -fv /dev/sda1 /mnt
|
|
@@ -341,7 +373,7 @@ If `Enter` is not recognized in a particular terminal, try `Ctrl-J` or
|
|
|
341
373
|
- Be careful not to run markdown files from strangers
|
|
342
374
|
* Otherwise it can run any command on your PC
|
|
343
375
|
- `jsmdcui --cdp-maze` runs a self-solving maze game
|
|
344
|
-
* Run `bunterm` first to show its Emojis
|
|
376
|
+
* Run `bunterm 2` first to show its Emojis
|
|
345
377
|
|
|
346
378
|
### Multitasking modes
|
|
347
379
|
|
|
@@ -448,11 +480,13 @@ syntax, interactive controls, builtins, and current compatibility details.
|
|
|
448
480
|
### Showing images
|
|
449
481
|
|
|
450
482
|
The Linux text console cannot draw pictures, so first start `bunterm`, the
|
|
451
|
-
graphical terminal on the framebuffer, and run the image commands inside it
|
|
483
|
+
graphical terminal on the framebuffer, and run the image commands inside it.
|
|
484
|
+
Start it on another virtual console so tty1 keeps the `bun-repl>` prompt for
|
|
485
|
+
hardware setup (`Ctrl+Alt+F1` goes back to it):
|
|
452
486
|
|
|
453
487
|
```sh
|
|
454
|
-
# Start the graphical terminal on
|
|
455
|
-
bunterm
|
|
488
|
+
# Start the graphical terminal on VT 2 (same as bunterm /dev/tty2)
|
|
489
|
+
bunterm 2
|
|
456
490
|
|
|
457
491
|
# Show an image with the kitty graphics protocol (jsgotty --viu)
|
|
458
492
|
showimg /buninu/icon.png
|
|
@@ -465,7 +499,8 @@ buninu-help
|
|
|
465
499
|
jsmdcui --allow-url README.md
|
|
466
500
|
|
|
467
501
|
# The mouse works in bunterm; --no-mouse leaves /dev/input alone
|
|
468
|
-
|
|
502
|
+
# (VT 3, since VT 2 already has the bunterm started above)
|
|
503
|
+
bunterm 3 -e jsmdcui --allow-url README.md
|
|
469
504
|
```
|
|
470
505
|
|
|
471
506
|
`bunterm` draws with Skia (CanvasKit) and understands the kitty graphics
|
|
@@ -475,7 +510,93 @@ below a shown image, and images scroll with the text. When the program you
|
|
|
475
510
|
started exits, the console returns to text mode. `bunterm --help` has the
|
|
476
511
|
options; [graphics.md](graphics.md) describes how it is built. The image
|
|
477
512
|
needs a kernel with a framebuffer: build with `--linux-lts` or `--real`
|
|
478
|
-
(the default `linux-virt` builds one only as modules the image omits).
|
|
513
|
+
(the default `linux-virt` builds one only as modules the image omits). The
|
|
514
|
+
aarch64 guest also needs a QEMU display; see
|
|
515
|
+
[What differs on aarch64](#what-differs-on-aarch64).
|
|
516
|
+
|
|
517
|
+
### Clipboard
|
|
518
|
+
|
|
519
|
+
`bunterm` supports copy and paste through OSC 52, so programs such as
|
|
520
|
+
`casty` and `jsmdcui` can use the clipboard. bunterm keeps nothing itself; it
|
|
521
|
+
passes every copy and paste to Buninu's `xclip -selection clipboard`. For
|
|
522
|
+
now that clipboard is a file, `$HOME/.xclip.clipboard`, read and written in
|
|
523
|
+
the ramdisk, so all bunterm sessions share it and it is gone after a reboot.
|
|
524
|
+
`bunterm --no-clipboard` turns OSC 52 off.
|
|
525
|
+
|
|
526
|
+
For Chinese input, run the pinyin input method
|
|
527
|
+
[jspinyin](https://www.npmjs.com/package/@drxiaozhi/jspinyin) in a bunterm
|
|
528
|
+
that is not inside a chroot, so it uses Buninu's `xclip`:
|
|
529
|
+
|
|
530
|
+
```sh
|
|
531
|
+
bun x @drxiaozhi/jspinyin
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
- jspinyin → casty: press `Ctrl-C` in jspinyin to copy its result box, then
|
|
535
|
+
`Ctrl-V` in casty pastes it through OSC 52.
|
|
536
|
+
- casty → jsmdcui / jspinyin: `Alt-C` in casty copies the selection through
|
|
537
|
+
OSC 52, and `Ctrl-V` pastes it in jsmdcui or jspinyin, since jsmdcui reads
|
|
538
|
+
from `xclip` first by default.
|
|
539
|
+
|
|
540
|
+
### Playing YouTube with sound (experimental)
|
|
541
|
+
|
|
542
|
+
[jspulse](https://www.npmjs.com/package/@drxiaozhi/jspulse) is a
|
|
543
|
+
PulseAudio-compatible sound server written for Bun. It runs natively in
|
|
544
|
+
Buninu, outside any chroot, and plays through ALSA. Chromium-based programs
|
|
545
|
+
such as `casty` inside the Debian chroot connect to it over `127.0.0.1`,
|
|
546
|
+
because a chroot shares Buninu's network. Several programs can play at once.
|
|
547
|
+
|
|
548
|
+
This assumes the Debian chroot and `casty` from
|
|
549
|
+
[Commands inside /bin](#commands-inside-bin) are already set up, with the
|
|
550
|
+
chroot shell on tty2. `bun x` needs network access; see
|
|
551
|
+
[Basic configuration](#basic-configuration).
|
|
552
|
+
|
|
553
|
+
1. **Load the sound drivers.** Press `Ctrl+Alt+F1` to go to the `bun-repl>`
|
|
554
|
+
prompt on tty1 and run:
|
|
555
|
+
|
|
556
|
+
```js
|
|
557
|
+
cfg.sound
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
2. **Open a native Buninu terminal.** Still on tty1, enter the Buninu shell
|
|
561
|
+
with `start()`, then open another virtual console from that shell (see
|
|
562
|
+
[Multitasking modes](#multitasking-modes)). Run the next two steps there,
|
|
563
|
+
*not* inside the chroot:
|
|
564
|
+
|
|
565
|
+
```js
|
|
566
|
+
start()
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
```sh
|
|
570
|
+
bunterm 3
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
3. **Set the volume, then test the speakers.** Setting a volume also unmutes
|
|
574
|
+
the output, so the 3-second test tone is guaranteed to be audible. Adjust
|
|
575
|
+
the percentage afterwards if it is too quiet or too loud:
|
|
576
|
+
|
|
577
|
+
```sh
|
|
578
|
+
bun x @drxiaozhi/jspulse --volume 50
|
|
579
|
+
bun x @drxiaozhi/jspulse --play
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
4. **Start the sound server.** It keeps running in the foreground, so leave
|
|
583
|
+
this terminal as it is; `Ctrl+C` stops it:
|
|
584
|
+
|
|
585
|
+
```sh
|
|
586
|
+
bun x @drxiaozhi/jspulse --alsa
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
5. **Start casty with sound.** Press `Ctrl+Alt+F2` to return to the chroot
|
|
590
|
+
shell, point PulseAudio clients at jspulse, and start casty:
|
|
591
|
+
|
|
592
|
+
```sh
|
|
593
|
+
export PULSE_SERVER=127.0.0.1
|
|
594
|
+
cd ~/casty/bin
|
|
595
|
+
bun casty.js https://www.youtube.com
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
If there is no sound, check step 4's terminal for errors, and make sure
|
|
599
|
+
`PULSE_SERVER` was exported in the same shell that started casty.
|
|
479
600
|
|
|
480
601
|
## Commands inside /bin
|
|
481
602
|
|
|
@@ -524,14 +645,14 @@ umount -R /mnt
|
|
|
524
645
|
bun x bunproot --git clone https://github.com/jjtseng93/bunproot
|
|
525
646
|
|
|
526
647
|
# Read bunproot's Git manual without ANSI formatting in jmi
|
|
527
|
-
bunterm
|
|
648
|
+
bunterm 2
|
|
528
649
|
bun x bunproot --git --readme | stripansi | jmi
|
|
529
650
|
|
|
530
651
|
|
|
531
652
|
|
|
532
653
|
# Download and enter an x64 Debian rootfs
|
|
533
654
|
# Make sure you have run this already:
|
|
534
|
-
# bunterm --font-size 13
|
|
655
|
+
# bunterm 2 --font-size 13
|
|
535
656
|
bun x bunproot --git --yes clone https://github.com/jjtseng93/js-udocker
|
|
536
657
|
cd js-udocker
|
|
537
658
|
bun udocker.js pull --platform=linux/amd64 debian:13
|
|
@@ -561,7 +682,8 @@ git clone https://github.com/jjtseng93/casty
|
|
|
561
682
|
cd casty/bin
|
|
562
683
|
# When clicking around, don’t release the mouse button immediately after pressing it, to make sure the mouse-down event is triggered
|
|
563
684
|
bun casty.js buninu.org
|
|
564
|
-
|
|
685
|
+
# For sound in casty (YouTube), start jspulse first:
|
|
686
|
+
# see "Playing YouTube with sound (experimental)" under "Using Buninu Linux"
|
|
565
687
|
|
|
566
688
|
|
|
567
689
|
# Download and enter an x64 Alpine minirootfs
|
|
@@ -608,9 +730,9 @@ tar xvf /tmp/buninu.tar -C /tmp/buninu-copy
|
|
|
608
730
|
# Add z to create a gzip-compressed archive
|
|
609
731
|
tar czvf /tmp/buninu.tar.gz README.md package.json
|
|
610
732
|
|
|
611
|
-
# On
|
|
612
|
-
bunterm
|
|
613
|
-
bunterm /dev/
|
|
733
|
+
# On another virtual console: a graphical terminal with CJK, emoji and images
|
|
734
|
+
bunterm 2
|
|
735
|
+
bunterm /dev/tty3 --font-size 13 -e bun /buninu/apps/jsmdcui/src/index.js --demo
|
|
614
736
|
```
|
|
615
737
|
|
|
616
738
|
The graphics stack behind `bunterm` — the framebuffer module, CanvasKit,
|
|
@@ -753,7 +875,7 @@ its own.
|
|
|
753
875
|
```text
|
|
754
876
|
index.js entry point: -f / -b / -r / --arch / --docker / --export / --linux-lts / --real
|
|
755
877
|
Dockerfile the Debian 13 build toolchain for --docker (and macOS)
|
|
756
|
-
fetch-alpine.sh [fetch] kernel, EFI stub, musl, network/input modules
|
|
878
|
+
fetch-alpine.sh [fetch] kernel, EFI stub, musl, network/input/display modules
|
|
757
879
|
fetch-bun.sh [fetch] Bun, libstdc++, libgcc
|
|
758
880
|
build-uki.sh [build] UKI; calls scripts/pack-initramfs.sh
|
|
759
881
|
build-image.sh [build] GPT disk image; shared with the hello-world EFI
|
|
@@ -1089,7 +1211,7 @@ until `cfg.net` loads the packaged drivers and the user assigns an address and
|
|
|
1089
1211
|
route.
|
|
1090
1212
|
|
|
1091
1213
|
On a `--real` image the REPL also offers the getter-based `cfg` namespace:
|
|
1092
|
-
`cfg.net`, `cfg.disk`, `cfg.power` and `cfg.all` run as soon as the property is read, without
|
|
1214
|
+
`cfg.net`, `cfg.disk`, `cfg.power`, `cfg.sound` and `cfg.all` run as soon as the property is read, without
|
|
1093
1215
|
parentheses. `cfg.net` loads every packaged network module (including PHY and bus support),
|
|
1094
1216
|
then reads the `modalias` of every PCI and USB network device, matches it
|
|
1095
1217
|
against the `pci:`/`usb:` lines
|
|
@@ -1101,7 +1223,10 @@ declared dependencies. `--real` ships Intel `e1000`/`e1000e`/`igb`/`igc`,
|
|
|
1101
1223
|
Realtek `r8169`, Atheros `alx`, Broadcom `tg3`, common USB dongles, and
|
|
1102
1224
|
`rndis_host`/`cdc_ether`/`cdc_ncm`/`cdc_eem`/`cdc_subset`/`zaurus` for Android
|
|
1103
1225
|
USB tethering. `cfg.net` unconditionally attempts all of these packaged
|
|
1104
|
-
network modules. `cfg.
|
|
1226
|
+
network modules. `cfg.sound` likewise unconditionally attempts every packaged
|
|
1227
|
+
module below `kernel/sound/`, then lists `/dev/snd`; it does no hardware probe.
|
|
1228
|
+
The packaged sound set covers QEMU ES1371/HDA and common PC HDA/HDMI and USB
|
|
1229
|
+
audio where the selected kernel flavor provides them. `cfg.power` loads the ACPI
|
|
1105
1230
|
`battery`, `ac`, `button` and `thermal` modules through `/lib/modprobe.js`
|
|
1106
1231
|
and lists `/sys/class/power_supply` (a desktop without a battery simply
|
|
1107
1232
|
reports nothing registered). Nothing loads them at boot. PID 1 also installs
|
|
@@ -1136,6 +1261,8 @@ for the userspace session.
|
|
|
1136
1261
|
- [Pane and tab controls](#pane-and-tab-controls)
|
|
1137
1262
|
* [Using Bun Modern Shell](#using-bun-modern-shell)
|
|
1138
1263
|
* [Showing images](#showing-images)
|
|
1264
|
+
* [Clipboard](#clipboard)
|
|
1265
|
+
* [Playing YouTube with sound (experimental)](#playing-youtube-with-sound-experimental)
|
|
1139
1266
|
- [Commands inside /bin](#commands-inside-bin)
|
|
1140
1267
|
- [Environment and dependencies](#environment-and-dependencies)
|
|
1141
1268
|
* [Build environment](#build-environment)
|
package/build-uki.sh
CHANGED
|
@@ -14,11 +14,7 @@ fi
|
|
|
14
14
|
./scripts/pack-initramfs.sh
|
|
15
15
|
|
|
16
16
|
mkdir -p build vda/EFI/BOOT
|
|
17
|
-
|
|
18
|
-
'NAME="Buninu Linux"' \
|
|
19
|
-
'ID=buninu-linux' \
|
|
20
|
-
'PRETTY_NAME="Buninu Linux 1"' \
|
|
21
|
-
'VERSION_ID=1' > build/os-release
|
|
17
|
+
# build/os-release is written by pack-initramfs.sh from package.json.
|
|
22
18
|
# Bun itself is PID 1: no native bootstrap. `-e import('/init.js')` avoids the
|
|
23
19
|
# entry-file open that would readlink /proc/self/fd/N before /proc exists;
|
|
24
20
|
# init.js mounts /proc, /sys, /dev and /tmp as its first action.
|
package/fetch-alpine.sh
CHANGED
|
@@ -81,6 +81,22 @@ if [ "$arch" = x86_64 ]; then
|
|
|
81
81
|
else
|
|
82
82
|
select_module virtio_input
|
|
83
83
|
fi
|
|
84
|
+
# The framebuffer for bunterm. Both lts kernels set CONFIG_SYSFB_SIMPLEFB, so
|
|
85
|
+
# the UEFI GOP (QEMU's ramfb on aarch64 virt) becomes a simple-framebuffer
|
|
86
|
+
# device that only simpledrm drives: x86_64 lts builds it in, aarch64 lts has
|
|
87
|
+
# it as a module. init.js loads it at boot, which is what makes /dev/fb0.
|
|
88
|
+
if [ "$linux_flavor" = lts ]; then
|
|
89
|
+
select_optional_module simpledrm
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
# Sound: a compact set covering QEMU's emulated AC97/HDA devices and the
|
|
93
|
+
# usual PC HDA/HDMI and USB-audio paths. Dependencies pull in the ALSA core,
|
|
94
|
+
# PCM, timer, codec and USB support needed by each available leaf driver.
|
|
95
|
+
# Some kernel flavors build fewer of these, so keep every leaf optional.
|
|
96
|
+
for module in snd-ens1371 snd-hda-intel snd-hda-codec-generic \
|
|
97
|
+
snd-hda-codec-hdmi snd-usb-audio; do
|
|
98
|
+
select_optional_module "$module"
|
|
99
|
+
done
|
|
84
100
|
|
|
85
101
|
if [ "${REAL_MACHINE:-}" = 1 ]; then
|
|
86
102
|
# USB keyboard for the console; common storage paths (SATA/AHCI HDD and
|
package/graphics.md
CHANGED
|
@@ -174,13 +174,22 @@ needs about 1 GB.
|
|
|
174
174
|
|
|
175
175
|
## Trying it
|
|
176
176
|
|
|
177
|
-
The framebuffer needs a kernel that provides one.
|
|
178
|
-
`
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
177
|
+
The framebuffer needs a kernel that provides one. Both `linux-lts` kernels
|
|
178
|
+
set `CONFIG_SYSFB_SIMPLEFB`, so the UEFI GOP becomes a `simple-framebuffer`
|
|
179
|
+
device, which only `simpledrm` drives (`efifb` never sees it). The x86_64
|
|
180
|
+
`linux-lts` builds `simpledrm` in. The aarch64 one has it as a module:
|
|
181
|
+
`fetch-alpine.sh` ships it and its DRM dependencies for lts builds, and
|
|
182
|
+
`init.js` loads it at boot. The default `linux-virt` builds the framebuffer
|
|
183
|
+
drivers as modules, and the image ships only the network, storage, USB and
|
|
184
|
+
HID modules, so there `/dev/fb0` never appears. Build with
|
|
185
|
+
`./index.js -b --linux-lts` (or `--real` on x86_64). Under QEMU, the x86_64
|
|
186
|
+
lts kernel gets a 1280×800 `simpledrm` framebuffer from the UEFI GOP even
|
|
187
|
+
with `-display none`, and the monitor's `screendump` shows it. QEMU's aarch64
|
|
188
|
+
`virt` machine has no display until you add `-device ramfb`; EDK2 then
|
|
189
|
+
provides an 800×600 GOP, and `virtio-keyboard-pci` gives the VTs a keyboard
|
|
190
|
+
(see the README's
|
|
191
|
+
[What differs on aarch64](README.md#what-differs-on-aarch64)). From a virtual
|
|
192
|
+
console in the guest:
|
|
184
193
|
|
|
185
194
|
```sh
|
|
186
195
|
bunterm # /bin/sh on this console
|
|
@@ -206,6 +215,13 @@ host, `jsmdcui --tui` on a Markdown file with a JPEG (bunterm sets
|
|
|
206
215
|
`JSMDCUI_KITTY_MODE=extended` for the program it runs) places the image
|
|
207
216
|
through its transmit / `a=p` / `a=d` sequence exactly as in the browser.
|
|
208
217
|
|
|
218
|
+
Verified on aarch64 (lts kernel, Hypervisor.framework, `-device ramfb
|
|
219
|
+
-device virtio-keyboard-pci -device virtio-mouse-pci`, `-display none`):
|
|
220
|
+
`/proc/fb` lists `simpledrmdrmfb`; `bunterm 2` from the serial shell returns
|
|
221
|
+
at once and draws on VT 2; and keys sent with the monitor's `sendkey` reach
|
|
222
|
+
it: `showimg /buninu/icon.png` places the kitty image, and the prompt's
|
|
223
|
+
colour emoji and the pointer render, all checked with `screendump`.
|
|
224
|
+
|
|
209
225
|
## Not done yet
|
|
210
226
|
|
|
211
227
|
- Selection and scrollback viewing in `bunterm` (the pointer itself works,
|
package/initramfs/bin/bunterm
CHANGED
|
@@ -11,7 +11,7 @@ const CANONICAL_BUNTERM = "/bin/bunterm";
|
|
|
11
11
|
|
|
12
12
|
const usage = () => {
|
|
13
13
|
console.error(`Usage:
|
|
14
|
-
bunterm [N | /dev/ttyN] [-s N | --font-size N] [--fb /dev/fb0] [--no-mouse] [-e command [argument...]]
|
|
14
|
+
bunterm [N | /dev/ttyN] [-s N | --font-size N] [--fb /dev/fb0] [--no-mouse] [--no-clipboard] [-e command [argument...]]
|
|
15
15
|
bunterm -h | --help`);
|
|
16
16
|
};
|
|
17
17
|
|
|
@@ -58,6 +58,8 @@ const main = async () => {
|
|
|
58
58
|
options.mouse = true;
|
|
59
59
|
} else if (argument === "--no-mouse") {
|
|
60
60
|
options.mouse = false;
|
|
61
|
+
} else if (argument === "--no-clipboard") {
|
|
62
|
+
options.clipboard = false;
|
|
61
63
|
} else if (/^[1-9][0-9]*$/.test(argument) || argument.startsWith("/dev/")) {
|
|
62
64
|
const number = /^[1-9][0-9]*$/.test(argument) ? Number(argument) : virtualConsoleNumber(argument);
|
|
63
65
|
if (number === null) throw new Error(`expected N or /dev/ttyN, got ${argument}`);
|
|
@@ -23,6 +23,7 @@ npx buninu
|
|
|
23
23
|
> (`--local`, bunmsh) has no job control yet, so use the browser terminal when
|
|
24
24
|
> you need to background a job.
|
|
25
25
|
|
|
26
|
+
- Homepage: <https://buninu.org>
|
|
26
27
|
- Source: [github.com/jjtseng93/buninu](https://github.com/jjtseng93/buninu)
|
|
27
28
|
|
|
28
29
|
- Core components:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "buninu",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.17",
|
|
4
4
|
"description": "Buninu is a portable, self-bootstrapping Unix-like userspace built on Bun that runs across operating systems",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./bin/init.js",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"type": "git",
|
|
11
11
|
"url": "git+https://github.com/jjtseng93/buninu.git"
|
|
12
12
|
},
|
|
13
|
-
"homepage": "https://
|
|
13
|
+
"homepage": "https://buninu.org",
|
|
14
14
|
"bugs": {
|
|
15
15
|
"url": "https://github.com/jjtseng93/buninu/issues"
|
|
16
16
|
},
|
package/initramfs/init.js
CHANGED
|
@@ -179,6 +179,16 @@ try {
|
|
|
179
179
|
console.error(`init.js: input modules: ${error?.message ?? error}`);
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
+
// The framebuffer for bunterm: the firmware's GOP is a simple-framebuffer
|
|
183
|
+
// device, and simpledrm turns it into /dev/fb0. x86_64 linux-lts builds it
|
|
184
|
+
// in and linux-virt images do not ship it; tryModprobe skips both.
|
|
185
|
+
try {
|
|
186
|
+
const { tryModprobe } = await import("/lib/modprobe.js");
|
|
187
|
+
if (tryModprobe("simpledrm")?.length) console.log("init.js: loaded simpledrm");
|
|
188
|
+
} catch (error) {
|
|
189
|
+
console.error(`init.js: simpledrm: ${error?.message ?? error}`);
|
|
190
|
+
}
|
|
191
|
+
|
|
182
192
|
const { default: repl } = await import("node:repl");
|
|
183
193
|
const { mkdirSync, writeFileSync } = await import("node:fs");
|
|
184
194
|
|
|
@@ -549,11 +559,26 @@ const configureDisks = () => {
|
|
|
549
559
|
return devices;
|
|
550
560
|
};
|
|
551
561
|
|
|
562
|
+
// Load the complete sound stack packaged in the image. Like cfg.net this is
|
|
563
|
+
// deliberately unconditional: it does not probe modaliases first, so codec
|
|
564
|
+
// and helper modules without their own discoverable device are loaded too.
|
|
565
|
+
const configureSound = () => {
|
|
566
|
+
const { modprobeAll } = require("/lib/modprobe.js");
|
|
567
|
+
const { readdirSync } = require("node:fs");
|
|
568
|
+
const report = modprobeAll({ accept: (_module, path) => path.startsWith("kernel/sound/") });
|
|
569
|
+
console.log(`sound: loaded all packaged sound modules (${report.inserted.length} newly loaded, ${report.errors.length} failed)`);
|
|
570
|
+
for (const { module, error } of report.errors) console.log(`sound: ${module}: ${error}`);
|
|
571
|
+
const devices = (() => { try { return readdirSync("/dev/snd"); } catch { return []; } })();
|
|
572
|
+
console.log(`sound: ${devices.length ? devices.map((name) => `/dev/snd/${name}`).join(" ") : "no sound devices registered"}`);
|
|
573
|
+
return devices;
|
|
574
|
+
};
|
|
575
|
+
|
|
552
576
|
globalThis.cfg = Object.freeze(Object.defineProperties({}, {
|
|
553
577
|
all: { enumerable: true, get: configureModules },
|
|
554
578
|
disk: { enumerable: true, get: configureDisks },
|
|
555
579
|
net: { enumerable: true, get: configureEthernet },
|
|
556
580
|
power: { enumerable: true, get: configureBattery },
|
|
581
|
+
sound: { enumerable: true, get: configureSound },
|
|
557
582
|
}));
|
|
558
583
|
|
|
559
584
|
// Compatibility aliases for images and notes that used the original API.
|
|
@@ -562,6 +587,7 @@ globalThis.cfgNet = configureEthernet;
|
|
|
562
587
|
globalThis.cfgDisk = configureDisks;
|
|
563
588
|
globalThis.cfgMod = configureModules;
|
|
564
589
|
globalThis.cfgBat = configureBattery;
|
|
590
|
+
globalThis.cfgSound = configureSound;
|
|
565
591
|
|
|
566
592
|
const showWelcome = () => {
|
|
567
593
|
console.log(`
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// /lib/bunterm/clipboard.js — OSC 52 clipboard for bunterm, backed by xclip.
|
|
2
|
+
//
|
|
3
|
+
// program ── ESC ] 52 ; c ; <base64> BEL ──▶ xclip -selection clipboard
|
|
4
|
+
// program ── ESC ] 52 ; c ; ? BEL ─────────▶ xclip -selection clipboard -o
|
|
5
|
+
// ◀── ESC ] 52 ; c ; <base64> BEL ──
|
|
6
|
+
//
|
|
7
|
+
// bunterm keeps nothing itself: every copy and paste goes through xclip, so
|
|
8
|
+
// all bunterm sessions (and anything else using xclip) share one clipboard.
|
|
9
|
+
// Buninu's xclip prints status lines on stderr, which must not reach the
|
|
10
|
+
// console under the framebuffer, so stderr is discarded.
|
|
11
|
+
|
|
12
|
+
const runXclip = async (args, input) => {
|
|
13
|
+
const command = ["xclip", "-selection", "clipboard", ...args];
|
|
14
|
+
const proc = Bun.spawn(command, {
|
|
15
|
+
stdin: input === undefined ? "ignore" : input,
|
|
16
|
+
stdout: input === undefined ? "pipe" : "ignore",
|
|
17
|
+
stderr: "ignore",
|
|
18
|
+
});
|
|
19
|
+
const [output, exitCode] = await Promise.all([
|
|
20
|
+
input === undefined ? new Response(proc.stdout).arrayBuffer() : null,
|
|
21
|
+
proc.exited,
|
|
22
|
+
]);
|
|
23
|
+
if (exitCode !== 0) throw new Error(`${command.join(" ")} exited with ${exitCode}`);
|
|
24
|
+
return output;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// Registers the OSC 52 handler on an xterm.js terminal. `reply` sends bytes
|
|
28
|
+
// back to the program, as the terminal's other replies do. A read the xclip
|
|
29
|
+
// call cannot answer is still answered, with empty contents, so the program
|
|
30
|
+
// does not wait out its own timeout.
|
|
31
|
+
export const attachClipboard = ({ term, reply, onError = () => {} }) =>
|
|
32
|
+
term.parser.registerOscHandler(52, (data) => {
|
|
33
|
+
const separator = data.indexOf(";");
|
|
34
|
+
if (separator < 0) return true;
|
|
35
|
+
const target = data.slice(0, separator);
|
|
36
|
+
const payload = data.slice(separator + 1);
|
|
37
|
+
|
|
38
|
+
if (payload === "?") {
|
|
39
|
+
// The reply is sent after xclip returns, when the program may have exited
|
|
40
|
+
// and the PTY closed; writing then throws, and an unhandled rejection
|
|
41
|
+
// would end bunterm before it restores the console.
|
|
42
|
+
runXclip(["-o"])
|
|
43
|
+
.catch((error) => { onError(error); return new ArrayBuffer(0); })
|
|
44
|
+
.then((bytes) => reply(`\u001b]52;${target};${Buffer.from(bytes).toString("base64")}\u0007`))
|
|
45
|
+
.catch(onError);
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
runXclip([], Buffer.from(payload, "base64")).catch(onError);
|
|
50
|
+
return true;
|
|
51
|
+
});
|
|
@@ -21,6 +21,7 @@ import { Renderer, defaultTheme } from "./renderer.js";
|
|
|
21
21
|
import { ImageStore } from "./images.js";
|
|
22
22
|
import { openKeyboard, translateKeys } from "./input.js";
|
|
23
23
|
import { claimVirtualConsole } from "./vt.js";
|
|
24
|
+
import { attachClipboard } from "./clipboard.js";
|
|
24
25
|
|
|
25
26
|
const require = createRequire(import.meta.url);
|
|
26
27
|
|
|
@@ -52,6 +53,7 @@ export const createSession = ({
|
|
|
52
53
|
scrollback = 1000,
|
|
53
54
|
cursorBlink = true,
|
|
54
55
|
mouse = true,
|
|
56
|
+
clipboard = true,
|
|
55
57
|
env = {},
|
|
56
58
|
onError = (error) => console.error(`bunterm: ${error?.stack ?? error}`),
|
|
57
59
|
}) => {
|
|
@@ -158,6 +160,9 @@ export const createSession = ({
|
|
|
158
160
|
});
|
|
159
161
|
backend.onData(pump);
|
|
160
162
|
term.onData((data) => backend.write(Buffer.from(data, "utf8")));
|
|
163
|
+
// OSC 52 copy and paste go straight to xclip; replies return to the program.
|
|
164
|
+
// Without it (--no-clipboard) xterm.js ignores OSC 52 and nothing reaches xclip.
|
|
165
|
+
if (clipboard) attachClipboard({ term, reply: (text) => backend.write(Buffer.from(text, "utf8")), onError });
|
|
161
166
|
|
|
162
167
|
// Keyboard bytes from the console, rewritten for the program's key mode.
|
|
163
168
|
const input = (bytes) => {
|
|
@@ -6,12 +6,13 @@ xterm-compatible terminal with anti-aliased text, CJK, colour emoji, seamless
|
|
|
6
6
|
box drawing and kitty graphics protocol images — no X11, Wayland or GPU.
|
|
7
7
|
|
|
8
8
|
```sh
|
|
9
|
-
bunterm # run /bin/sh on the console you are on
|
|
10
9
|
bunterm 2 # start a detached bunterm on /dev/tty2
|
|
11
|
-
bunterm /dev/
|
|
10
|
+
bunterm /dev/tty2 # the full virtual-console spelling also works
|
|
11
|
+
bunterm # take over the console you are on (on tty1 that hides the bun-repl)
|
|
12
12
|
bunterm -s 20 # short for --font-size 20
|
|
13
13
|
bunterm -e bun /buninu/apps/jsmdcui/src/index.js --demo
|
|
14
14
|
bunterm --no-mouse # keyboard only
|
|
15
|
+
bunterm --no-clipboard # ignore OSC 52 copy and paste
|
|
15
16
|
bunterm -h
|
|
16
17
|
```
|
|
17
18
|
|
|
@@ -39,6 +40,7 @@ identified from the process task name and its open console descriptor under
|
|
|
39
40
|
| `--fb /dev/fbN` | The framebuffer device (default `/dev/fb0`). |
|
|
40
41
|
| `--no-blink` | A steady cursor. |
|
|
41
42
|
| `--no-mouse` | Do not attach a pointing device; nothing then reads `/dev/input`. |
|
|
43
|
+
| `--no-clipboard` | Ignore OSC 52: programs can neither copy to nor read from the clipboard, and `xclip` is never run. |
|
|
42
44
|
|
|
43
45
|
## What is drawn
|
|
44
46
|
|
|
@@ -101,6 +103,16 @@ mouse also needs the `usbhid` stack, which a `--real` image carries and
|
|
|
101
103
|
ones (a tablet or touchscreen) alike; a device that cannot be opened is
|
|
102
104
|
reported and the session continues without it.
|
|
103
105
|
|
|
106
|
+
## Clipboard
|
|
107
|
+
|
|
108
|
+
Programs copy and paste through OSC 52, as `casty` and `jsmdcui` do.
|
|
109
|
+
bunterm keeps no clipboard of its own: `ESC ] 52 ; c ; <base64>` is passed to
|
|
110
|
+
`xclip -selection clipboard`, and a query (`ESC ] 52 ; c ; ?`) is answered
|
|
111
|
+
with the output of `xclip -selection clipboard -o`, so every bunterm session
|
|
112
|
+
shares the same clipboard as `xclip`. A query xclip cannot answer is replied
|
|
113
|
+
to with empty contents. `--no-clipboard` turns this off, so a program can
|
|
114
|
+
neither set nor read the clipboard through the terminal.
|
|
115
|
+
|
|
104
116
|
## Limits
|
|
105
117
|
|
|
106
118
|
- Needs a framebuffer: `linux-lts` has one built in, while the default
|
package/package.json
CHANGED
|
@@ -27,6 +27,29 @@ cp -a --reflink=auto "$native_dir/." "$staging/"
|
|
|
27
27
|
cp README.md "$staging/usr/share/doc/buninu-linux/README.md"
|
|
28
28
|
cp -a LICENSE NOTICE.md LICENSES "$staging/usr/share/licenses/"
|
|
29
29
|
|
|
30
|
+
# os-release(5): the canonical file lives in /usr/lib and /etc/os-release links
|
|
31
|
+
# to it. build-uki.sh embeds the same file as the UKI's .osrel section.
|
|
32
|
+
version="$(sed -n 's/^ *"version": *"\([^"]*\)".*/\1/p' package.json | head -n 1)"
|
|
33
|
+
test -n "$version" || { echo "error: no version in package.json" >&2; exit 1; }
|
|
34
|
+
printf '%s\n' \
|
|
35
|
+
'NAME="Buninu Linux"' \
|
|
36
|
+
'ID=buninu-linux' \
|
|
37
|
+
"VERSION=\"$version\"" \
|
|
38
|
+
"VERSION_ID=$version" \
|
|
39
|
+
"PRETTY_NAME=\"Buninu Linux $version\"" \
|
|
40
|
+
'HOME_URL="https://buninu.org"' \
|
|
41
|
+
'BUG_REPORT_URL="https://github.com/jjtseng93/buninu-linux/issues"' \
|
|
42
|
+
'LOGO=buninu-linux' \
|
|
43
|
+
'DEFAULT_HOSTNAME=buninu' > build/os-release
|
|
44
|
+
mkdir -p "$staging/usr/lib" "$staging/etc"
|
|
45
|
+
cp build/os-release "$staging/usr/lib/os-release"
|
|
46
|
+
ln -sfn ../usr/lib/os-release "$staging/etc/os-release"
|
|
47
|
+
# LOGO names an icon-theme icon; point the standard lookup paths at the Buninu
|
|
48
|
+
# icon that /buninu already ships instead of packing a second copy.
|
|
49
|
+
mkdir -p "$staging/usr/share/icons/hicolor/512x512/apps" "$staging/usr/share/pixmaps"
|
|
50
|
+
ln -sfn ../../../../../../buninu/icon.png "$staging/usr/share/icons/hicolor/512x512/apps/buninu-linux.png"
|
|
51
|
+
ln -sfn ../../../buninu/icon.png "$staging/usr/share/pixmaps/buninu-linux.png"
|
|
52
|
+
|
|
30
53
|
# fakeroot lets cpio record the character devices without real root. Nothing
|
|
31
54
|
# has mounted devtmpfs when the kernel execs Bun as PID 1, so every device
|
|
32
55
|
# Bun's startup needs has to be in the archive itself:
|