diff --git a/README.md b/README.md index 2f49819..a8e92ae 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,18 @@ Following the [Buildroot customization docs](https://buildroot.org/downloads/man we create a folder `buildroot-v86/` with all the necessary config files, filesystem overlay, and scripts necessary to build our distribution. -## Running via Docker +## Running ISO via qemu + +``` +qemu-system-i386 -cdrom dist/v86-linux.iso +``` + +or with nix: +``` +nix-shell -p qemu --run 'qemu-system-i386 -cdrom dist/v86-linux.iso' +``` + +## Building via Docker To build the Docker image use the `build.sh` script, or: diff --git a/buildroot-v86/board/v86/rootfs_overlay/bin/js b/buildroot-v86/board/v86/rootfs_overlay/bin/js new file mode 100755 index 0000000..03589b5 --- /dev/null +++ b/buildroot-v86/board/v86/rootfs_overlay/bin/js @@ -0,0 +1,33 @@ +#!/bin/sh +PID=$$ +test -z "$1" && { echo "Usage: js 'somefunction(1)'"; exit 0; } + +source /etc/profile.sh + +test -n "$BROWSER" || { alert warning "/dev/browser not active (are you running outside of v86?)"; } +javascript="$*" + +# if we are run as shebang, use the file as input +test -f "$1" && { + javascript="args = String('$*').split(' '); $(cat $1 | tail +2)" +} + +# below is not ideal +# first I tried /dev/ttyS* https://github.com/copy/v86/issues/530 +# and differentiate processes by prefixing output by PID's +# to parse it later with AWK, but it was very hairy + +OUTPUT=/mnt/$PID +echo -n "PID=$PID; $javascript" > /dev/browser/js +sleep 0.1 +test -f $OUTPUT && { + cat $OUTPUT + rm $OUTPUT +} + + +# should we use flock, an awesome way to make processes read/write the same file +# while preventing 1001 concurrency issues? +# attempt: +# +# flock /dev/browser/js -c "echo \"$javascript\" > /dev/browser/js" diff --git a/buildroot-v86/board/v86/rootfs_overlay/bin/jsh b/buildroot-v86/board/v86/rootfs_overlay/bin/jsh new file mode 100755 index 0000000..03bb3f9 --- /dev/null +++ b/buildroot-v86/board/v86/rootfs_overlay/bin/jsh @@ -0,0 +1,45 @@ +#!/bin/sh +# usage: jsh [arg1] [arg2] ... +# +# 'jsh prompt question answer' executes: js prompt('question','answer') ) + +source /etc/profile.sh + +to_js(){ + printf "%s(" "$1" + shift + for arg in "$@"; do + case "$arg" in + (*[\.0-9]*) + printf '%s,' "$arg" + ;; + (*) + printf '"%s",' "$arg" + ;; + esac + done + printf ")\n" +} + +# run argument as js +test -z "$1" || { + func=$(to_js "$@") + func=${func/,)/)} + js "return $func" + hook "$@" + exit 0 +} + +# otherwise start repl +echo "jsh> JavaScript [browser] runtime" +echo "jsh> type 'exit' or CTRL-C to quit" +echo "jsh> HINT: to run alert('foo') outside this REPL, run 'jsh alert foo'" +echo "jsh>" +while true; do + echo -n -e "\n$(printf "\033[0m")jsh> $(printf "\033[0m")" + read line + test "$line" = exit && exit + js "$line" +done + + diff --git a/buildroot-v86/board/v86/rootfs_overlay/bin/v86pipe b/buildroot-v86/board/v86/rootfs_overlay/bin/v86pipe new file mode 100755 index 0000000..c3983d2 --- /dev/null +++ b/buildroot-v86/board/v86/rootfs_overlay/bin/v86pipe @@ -0,0 +1,30 @@ +#!/bin/sh +# +# this daemon allows 'tail -f' on v86 files (which don't persist inode when updated +# via javascript) +# more info see: https://github.com/copy/v86/issues/1140 +# +# Hopefully as V86 (or my understanding of it) matures, this will be no longer needed + +test -z $2 && { echo "usage: v86pipe "; exit 0; } + +# Start reading from the last line in the log file +last_size=0 +LOG_FILE=$1 +LOG_PIPE=$2 + +test -f $LOG_FILE || touch $LOG_FILE +test -p $LOG_PIPE || mkfifo $LOG_PIPE + +while true; do + # Get the current size of the file using wc -c (count bytes) + current_size=$(wc -c < $LOG_FILE) + test $current_size = $last_size || { + cat $LOG_FILE > $LOG_PIPE + truncate -s 0 $LOG_FILE + } + last_size=$current_size + + # Sleep for a moment to avoid excessive CPU usage + sleep 0.2 +done diff --git a/buildroot-v86/board/v86/rootfs_overlay/etc/profile b/buildroot-v86/board/v86/rootfs_overlay/etc/profile index e5f5acb..64a8340 100644 --- a/buildroot-v86/board/v86/rootfs_overlay/etc/profile +++ b/buildroot-v86/board/v86/rootfs_overlay/etc/profile @@ -1,5 +1,8 @@ +export HOME=/root +export PATH=$PATH:/etc:~/bin + # source URL data from v86 (file created by v86 during boot) -test -f /etc/profile.browser && source /etc/profile.browser +test -f /mnt/profile.browser && source /mnt/profile.browser # source xrsh env source /etc/profile.xrsh @@ -8,7 +11,7 @@ source /etc/profile.xrsh source /etc/profile.sh # source js functions -./.profile.js +./.profile.js | grep -v undefined ## forward not-found commands to javascript (via jsh) command_not_found_handle(){ @@ -25,7 +28,7 @@ help(){ echo 'js console.log: ' "type 'console document.baseURI" echo 'js function as cmd: ' "type 'alias $1=\"jsh $1\"' to run '$1 yo' as $1('yo')" echo 'js inspect: ' "type 'js \"return document.baseURI\"'" - echo 'js console disable: ' "type 'echo 0 > /dev/browser/console.tty' to enable" + echo 'js console mute: ' "type 'echo 0 > /dev/browser/tty' to disable" echo 'js capture console: ' "type 'tail -f /dev/browser/console'" echo 'jsh<->sh hooks: ' "type 'chmod +x ~/hook.d/*/* && alert helloworld'" echo 'include file into page' "type 'require '" @@ -35,11 +38,14 @@ help(){ ONBOARDING=1 } -resize -test $HOSTNAME = localhost || clear -cat /etc/motd -export PATH=$PATH:/etc:~/bin export TERM=xterm-256color export PS1="\n\[\033[38;5;57m\]x\[\033[38;5;93m\]r\[\033[38;5;129m\]s\[\033[38;5;165m\]h \[\033[38;5;201m\]# \[\033[0m\]" -pidof screen || screen -T screen-256color -c /root/.screenrc +# interactive login +[[ -t 0 ]] && { + cat /etc/motd + test -n "$STY" || { + screen -R -T screen-256color -c /root/.screenrc + } +} + diff --git a/buildroot-v86/board/v86/rootfs_overlay/etc/profile.xrsh b/buildroot-v86/board/v86/rootfs_overlay/etc/profile.xrsh index 2115b3f..ee03543 100644 --- a/buildroot-v86/board/v86/rootfs_overlay/etc/profile.xrsh +++ b/buildroot-v86/board/v86/rootfs_overlay/etc/profile.xrsh @@ -2,49 +2,24 @@ test -d /dev/browser || { - setup_binaries(){ - for bin in /mnt/js* /mnt/v86pipe /mnt/xrsh; do - chmod +x $bin - ln -s $bin /bin/. - done - } - setup_links(){ - ln -s /mnt/profile ~/.profile - ln -s /mnt/profile.js ~/.profile.js - ln -s /mnt/profile.browser ~/.profile.browser - ln -s /mnt/profile.sh ~/.profile.sh - ln -s /mnt/motd ~/.motd - ln -s ~/.profile.js ~/index.js + ln -fs /etc/profile ~/.profile + ln -fs /etc/profile.js ~/.profile.js + ln -fs /etc/profile.sh ~/.profile.sh + ln -fs /etc/motd ~/.motd + ln -fs /mnt/profile.browser ~/.profile.browser + ln -fs ~/.profile.js ~/index.js + ln -fs /dev/browser/index.html ~/index.html chmod +x ~/.profile.js } setup_browser_dev(){ - mkdir -p /mnt/dev/browser - touch /mnt/dev/browser/js - touch /mnt/console.tty - ln -s /mnt/dev/browser /dev/browser - # emulator.write_file() only writes to /mnt/. :( - # should be in /proc, but v86 gives 'no such file or dir' when creating it there - ln -s /mnt/console.tty /dev/browser/console.tty - echo 1 > /dev/browser/console.tty - touch /mnt/console && ln -s /mnt/console /dev/browser/console - touch /mnt/index.html && ln -s /mnt/index.html /dev/browser/index.html - ln -s /dev/browser/index.html ~/index.html - - test -f /etc/profile && rm /etc/profile - ln -s /mnt/profile /etc/profile - } - - setup_hook_dirs(){ # see /mnt/hook for usage - mkdir ~/bin - mkdir -p ~/hook.d/alert - echo -e "#!/bin/sh\necho hook.d/alert/yo: yo \$*" > ~/hook.d/alert/yo - echo -e "#!/bin/js\nstr = \"hook.d/alert/yo.js yo \"+args.slice(1).join(' ')\nalert(str)\nreturn str" > ~/hook.d/alert/yo.js - echo -e "#!/usr/bin/env lua\nprint(\"hook.d/alert/yo.lua: yo \" .. arg[1])" > ~/hook.d/alert/yo.lua - echo -e "#!/usr/bin/awk -f\nBEGIN{\n\tprint \"hook.d/alert/yo.awk: yo \" ARGV[1]\n}" > ~/hook.d/alert/yo.awk - echo -e "#!/bin/sh\necho hello \$*" > ~/bin/hello - chmod +x ~/bin/hello + mkdir -p /dev/browser + echo 1 > /mnt/console.tty + ln -s /mnt/console.tty /dev/browser/tty + ln -fs /mnt/js /dev/browser/js + touch /dev/browser/console + touch /dev/browser/index.html } setup_network(){ @@ -54,10 +29,13 @@ test -d /dev/browser || { echo 0 > /proc/sys/kernel/printk } - setup_binaries + setup_overlayfs(){ + test -f /mnt/overlayfs.zip && unzip /mnt/overlayfs.zip -d / + } + setup_browser_dev - setup_hook_dirs setup_links setup_network + setup_overlayfs } diff --git a/buildroot-v86/board/v86/rootfs_overlay/root/.screenrc b/buildroot-v86/board/v86/rootfs_overlay/root/.screenrc index 7783caa..ff4b233 100644 --- a/buildroot-v86/board/v86/rootfs_overlay/root/.screenrc +++ b/buildroot-v86/board/v86/rootfs_overlay/root/.screenrc @@ -1,14 +1,11 @@ # look and feel -#caption always "%{i0}^{=}" #"%{= bb}%n%{+b w}%t %{= db} ${USER}@xrsh.iso" -#hardstatus alwayslastline "%-Lw%{= BW} %{=B}%t%{-B} %{-}%+Lw%<" -#caption always "%{= bb}%{+b w}%n %t %h %=%l %H %c" -hardstatus alwayslastline "%{= Bb}%-Lw%{= BW}%50> %t %{-}<" +caption always "%{= kw}%-w%{= BW} %t %{-}%+w %-= $HOSTNAME" # skip the startup message startup_message off # go to home dir -chdir +chdir /root # Automatically detach on hangup. autodetach on @@ -37,7 +34,8 @@ defbce on # use current bg color for erased chars # setup windows screen -t jsconsole 0 tail -f /dev/browser/console -screen -t xrsh 1 -If you want it to start with a particular window active, you can add a line like the following: +screen -t jsh 1 jsh +screen -t xrsh 2 -select 1 +##If you want it to start with a particular window active, you can add a line like the following: +#select 1 diff --git a/buildroot-v86/board/v86/rootfs_overlay/root/bin/helloworld b/buildroot-v86/board/v86/rootfs_overlay/root/bin/helloworld new file mode 100755 index 0000000..3a22932 --- /dev/null +++ b/buildroot-v86/board/v86/rootfs_overlay/root/bin/helloworld @@ -0,0 +1,3 @@ +#!/bin/js +alert("~/bin/helloworld") +return done: ~/bin/helloworld diff --git a/buildroot-v86/board/v86/rootfs_overlay/root/hook.d/alert/yo b/buildroot-v86/board/v86/rootfs_overlay/root/hook.d/alert/yo new file mode 100644 index 0000000..10546c2 --- /dev/null +++ b/buildroot-v86/board/v86/rootfs_overlay/root/hook.d/alert/yo @@ -0,0 +1,2 @@ +#!/bin/sh +echo hook.d/alert/yo: yo $* diff --git a/buildroot-v86/board/v86/rootfs_overlay/root/hook.d/alert/yo.awk b/buildroot-v86/board/v86/rootfs_overlay/root/hook.d/alert/yo.awk new file mode 100644 index 0000000..b12e508 --- /dev/null +++ b/buildroot-v86/board/v86/rootfs_overlay/root/hook.d/alert/yo.awk @@ -0,0 +1,4 @@ +#!/usr/bin/awk -f +BEGIN{ + print "hook.d/alert/yo.awk: yo " ARGV[1] +} diff --git a/buildroot-v86/board/v86/rootfs_overlay/root/hook.d/alert/yo.js b/buildroot-v86/board/v86/rootfs_overlay/root/hook.d/alert/yo.js new file mode 100644 index 0000000..4b0c500 --- /dev/null +++ b/buildroot-v86/board/v86/rootfs_overlay/root/hook.d/alert/yo.js @@ -0,0 +1,3 @@ +#!/bin/js +str = "hook.d/alert/yo.js yo"+args.slice(1).join(' ') +alert(str) diff --git a/buildroot-v86/board/v86/rootfs_overlay/root/hook.d/alert/yo.lua b/buildroot-v86/board/v86/rootfs_overlay/root/hook.d/alert/yo.lua new file mode 100644 index 0000000..f1ffb8e --- /dev/null +++ b/buildroot-v86/board/v86/rootfs_overlay/root/hook.d/alert/yo.lua @@ -0,0 +1,2 @@ +#!/usr/bin/env lua +print("hook.d/alert/yo.lua: yo " .. args[1]) diff --git a/buildroot-v86/board/v86/rootfs_overlay/root/hook.d/alert/yo.py b/buildroot-v86/board/v86/rootfs_overlay/root/hook.d/alert/yo.py new file mode 100644 index 0000000..d713075 --- /dev/null +++ b/buildroot-v86/board/v86/rootfs_overlay/root/hook.d/alert/yo.py @@ -0,0 +1,3 @@ +#!/usr/bin/env micropython +import sys +print("hook.d/alert/yo.py: "+sys.argv[1]) diff --git a/dist/v86-linux.iso b/dist/v86-linux.iso new file mode 100644 index 0000000..7625306 Binary files /dev/null and b/dist/v86-linux.iso differ diff --git a/xrsh.iso b/xrsh.iso new file mode 120000 index 0000000..011758b --- /dev/null +++ b/xrsh.iso @@ -0,0 +1 @@ +dist/v86-linux.iso \ No newline at end of file