From 8a2fb2d6d0d35965b545f410b4e07637a85b676e Mon Sep 17 00:00:00 2001 From: Sunrisepeak Date: Sun, 15 Nov 2026 19:10:50 +0900 Subject: [PATCH 1/2] 0.6.4: okrun folds an absolute image name; releases carry their binaries, FreeBSD included An absolute image name was matched against the supplied directories as it stood, so a name with an empty component (`/a//b.oke', as a build system's joined paths carry it) or `.' was refused. Every name is now folded lexically before it is matched --- empty components and `.' dropped, `..' removing the component before it, a symlink left to the file system --- an absolute one from its root, a relative one beneath the first directory's name as before. The release workflow starts when a release is published, so a release carries its binaries without a separate dispatch (0.6.3 was published without them). It adds FreeBSD x86_64 and aarch64: static programs of the platform's hosted musl identity, built on Linux and run from their packages in a FreeBSD machine before they are attached. Every member is 0.6.4. --- .github/workflows/ci.yml | 9 +++ .github/workflows/release-binaries.yml | 42 +++++++++++- README.md | 9 +++ bind/mcpp.toml | 2 +- ld/mcpp.toml | 2 +- run/mcpp.toml | 2 +- run/src/full/run.cpp | 88 ++++++++++++++++---------- tools/mcpp.toml | 2 +- 8 files changed, 117 insertions(+), 39 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 62527da..d5d5235 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -310,6 +310,15 @@ jobs: | grep -q "argc as kal_env_arg_count = 2") \ || { echo "::error::a relative image name with .. was not opened"; exit 1; } echo " ok a relative name that climbs opens the image" + # A NAME WITH EMPTY COMPONENTS (0.6.4): `//' and `/./' in an absolute + # name, as a build system's joined paths carry them, fold lexically. + abs="$PWD"; [ "$RUNNER_OS" = Windows ] && abs=$(cygpath -m "$PWD") + "$OKRUN" "$abs//out/./$a//hello.oke" one | tr -d '\r' | grep -q "argc as kal_env_arg_count = 2" \ + || { echo "::error::an absolute image name with // was not opened"; exit 1; } + (cd rel/below && "$OKRUN" "..//..//out/$a/hello.oke" one | tr -d '\r' \ + | grep -q "argc as kal_env_arg_count = 2") \ + || { echo "::error::a relative image name with // was not opened"; exit 1; } + echo " ok a name with empty components opens the image" n=$("$OKRUN" "out/$a/needed.oke" | tr -d '\r') echo "$n" grep -q "twice(21) = 42, next_value() = 41" <<<"$n" || { echo "::error::an image another needs"; exit 1; } diff --git a/.github/workflows/release-binaries.yml b/.github/workflows/release-binaries.yml index bb0b383..294d7b6 100644 --- a/.github/workflows/release-binaries.yml +++ b/.github/workflows/release-binaries.yml @@ -2,12 +2,16 @@ name: release binaries # okrun and okld as programs of each system and architecture, attached to a # release: what a machine without mcpp installs to run ok images (the -# xim-pkgindex `okrun` package). Dispatched with the release's tag; each archive +# xim-pkgindex `okrun` package). A published release starts it (0.6.4: 0.6.3 was +# published without binaries because the dispatch was a separate step); a +# dispatch with a tag rebuilds an earlier release under a new asset revision. Each archive # is `mcpp pack` of the tool, a static program on Linux, and carries its # mcpp-package.json, from which `mcpp emit xpkg --package` writes the index # entry. on: + release: + types: [published] workflow_dispatch: inputs: tag: @@ -30,7 +34,7 @@ permissions: contents: write env: - RELEASE_TAG: ${{ github.event.inputs.tag }} + RELEASE_TAG: ${{ github.event.inputs.tag || github.event.release.tag_name }} ASSET_REVISION: ${{ github.event.inputs.asset_revision || '' }} MCPP_SOURCE_REF: ${{ github.event.inputs.mcpp_ref || vars.MCPP_SOURCE_REF || '' }} # 2026.11.10.1: openkal-run binds the interfaces its implementation provides. @@ -41,7 +45,9 @@ env: # platform is the one whose version group holds them (0.1.4: 0.18.0; 0.1.5: # 0.19.0, openkal-linux 0.19.0; 0.1.6: 0.19.1; 0.1.7: 0.19.2; 0.1.8: 0.20.0; 0.1.9: 0.20.1; # 0.3.0: 0.21.0; 0.3.1: 0.21.1; 0.4.2: 0.23.1; 0.4.3 and 0.4.4: 0.23.3). - PLATFORM_VERSION: ${{ github.event.inputs.platform }} + # A published release builds over the platform named here, which a release + # that changes the pinned implementations updates in the same commit. + PLATFORM_VERSION: ${{ github.event.inputs.platform || '0.28.0' }} XLINGS_VERSION: v2026.10.26.1 XLINGS_NON_INTERACTIVE: '1' @@ -63,6 +69,12 @@ jobs: - { os: ubuntu-24.04-arm, id: linux-aarch64, pack: '--target aarch64-linux-musl --mode static' } - { os: macos-15, id: macos-aarch64, pack: '--target aarch64-macos' } - { os: windows-2022, id: windows-x86_64, pack: '--target x86_64-windows-gnu' } + # FreeBSD (0.6.4): the musl identity of the platform's hosted + # arrangement, built on Linux (the runner's `built-as`), one static + # program, and run in a FreeBSD machine before it is attached. These + # are the programs a runner delivers into a FreeBSD guest. + - { os: ubuntu-24.04, id: freebsd-x86_64, pack: '--target x86_64-freebsd-musl --mode static', vm: x86_64 } + - { os: ubuntu-24.04, id: freebsd-aarch64, pack: '--target aarch64-freebsd-musl --mode static', vm: aarch64 } defaults: run: shell: bash @@ -152,6 +164,7 @@ jobs: ls -l ../out - name: Each program runs here, from its package alone + if: ${{ !matrix.vm }} run: | python=python3; [ "$RUNNER_OS" = Windows ] && python=python tag="$RELEASE_TAG" @@ -182,6 +195,29 @@ jobs: grep -q "usage: $tool" "$tool.out" || { echo "::error::$tool did not run here"; exit 1; } done + - name: Unpacked for the FreeBSD machine + if: ${{ matrix.vm }} + run: | + mkdir -p vm + for tool in okrun okld okprof; do + unzip -q -o "out/$tool-$RELEASE_TAG$ASSET_SUFFIX-${{ matrix.id }}.zip" -d vm + done + ls vm + - name: Each program runs in FreeBSD, from its package alone + if: ${{ matrix.vm }} + uses: vmactions/freebsd-vm@v1 + with: + arch: ${{ matrix.vm }} + usesh: true + run: | + uname -a + for pkg in vm/*/; do + tool=$(basename "$pkg" | cut -d- -f1) + "$pkg/$tool" > "$tool.out" 2>&1 || true + cat "$tool.out" + grep -q "usage: $tool" "$tool.out" || { echo "$tool did not run here"; exit 1; } + done + - name: Debug the just-unpacked Linux runner if: matrix.id == 'linux-x86_64' run: | diff --git a/README.md b/README.md index efe2d67..f0d35a9 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,15 @@ of the row `i686-openkal`, built through openkal-platform 0.28.0 (C++23 with `i686-linux-musl` on an x86-64 Linux, and gdb stops at a line of it and unwinds into the runner, as for an x86-64 image (measured). +Version 0.6.4 folds every image name lexically before it is matched, an +absolute one as well as a relative one: an empty component (`//`, as a build +system's joined paths carry it) and `.` are dropped, and `..` removes the +component before it. An absolute name was matched as it stood, so `/a//b.oke` +was refused. The release workflow starts when a release is published, so every +release carries its binaries (0.6.3 was published without them), and it adds +FreeBSD x86_64 and aarch64: static programs of the platform's hosted musl +identity, built on Linux and run in a FreeBSD machine before they are attached. + ## An image ```sh diff --git a/bind/mcpp.toml b/bind/mcpp.toml index 5634b77..7e72126 100644 --- a/bind/mcpp.toml +++ b/bind/mcpp.toml @@ -1,7 +1,7 @@ [package] namespace = "mcpplibs" name = "openkal-bind" -version = "0.6.2" +version = "0.6.4" # `mcpp::xpkg_request', `mcpp::decision' (protocol 15). mcpp = ">=2026.10.1.3" description = "A build plugin: a library published as an ok image (.okso) and a C header is called from a program of any system, through a binding generated from the header and libokrun." diff --git a/ld/mcpp.toml b/ld/mcpp.toml index 7d80af8..3e7ab94 100644 --- a/ld/mcpp.toml +++ b/ld/mcpp.toml @@ -1,7 +1,7 @@ [package] namespace = "mcpplibs" name = "openkal-ld" -version = "0.6.3" +version = "0.6.4" description = "libokld: the ok format (openkal image format) --- its definition, a reader of bytes, a checker, a signer, and a loader. Freestanding: no C library, no exceptions." license = "Apache-2.0" authors = ["mcpplibs"] diff --git a/run/mcpp.toml b/run/mcpp.toml index 30ce355..c959a6e 100644 --- a/run/mcpp.toml +++ b/run/mcpp.toml @@ -1,7 +1,7 @@ [package] namespace = "mcpplibs" name = "openkal-run" -version = "0.6.3" +version = "0.6.4" description = "libokrun: the runner's core --- an ok image's names bound to this process's one openkal implementation, in the image's calling convention, and its entry entered." license = "Apache-2.0" authors = ["mcpplibs"] diff --git a/run/src/full/run.cpp b/run/src/full/run.cpp index 41347cf..6074c03 100644 --- a/run/src/full/run.cpp +++ b/run/src/full/run.cpp @@ -68,47 +68,71 @@ void* allocate(okld_size n, void*) { return kal_alloc(n, 16); } void deallocate(void* p, okld_size n, void*) { kal_free(p, n, 16); } // A name as openkal names things: the supplied directory that is the longest -// prefix of it, and the rest. A relative name is folded against the first -// directory's name --- `..' and `.' lexically, a symlink not resolved --- into -// the absolute one beneath it and matched as that. It folds into `g_folded', -// which outlives the call: the rest points into it. +// prefix of it, and the rest. Every name is folded lexically before it is +// matched --- empty components (`//'), `.' and `..' --- and a symlink is not +// resolved. A relative name is first placed beneath the first directory's name. +// It folds into `g_folded', which outlives the call: the rest points into it. bool separator(char c) { return c == '/' || c == '\\'; } char lower(char c) { return (c >= 'A' && c <= 'Z') ? static_cast(c - 'A' + 'a') : c; } char g_folded[1024]; -bool locate(const char* path, kal_dir& dir, const char*& rest) { - const char* name = path; - if (!(separator(path[0]) || (path[0] && path[1] == ':'))) { +// The root of an absolute name: `/', or a drive's `X:/'. Zero: not absolute. +unsigned long root_length(const char* p) { + if (separator(p[0])) return 1; + if (p[0] && p[1] == ':' && separator(p[2])) return 3; + return 0; +} + +bool fold(const char* path) { + unsigned long at = 0, floor = 0; + const char* rest = path; + if (const unsigned long r = root_length(path)) { + for (unsigned long i = 0; i < r; ++i) g_folded[at++] = separator(path[i]) ? '/' : path[i]; + rest = path + r; + floor = r; + } else { + kal_dir first{}; char base[1024]; kal_uintptr blen = 0; - if (kal_fs_preopen(0, &dir, base, sizeof base, &blen) != kal_ok + if (kal_fs_preopen(0, &first, base, sizeof base, &blen) != kal_ok || blen == 0 || blen >= sizeof g_folded) return false; - unsigned long at = 0; - while (at < blen) { g_folded[at] = base[at]; ++at; } - if (!separator(g_folded[at - 1])) g_folded[at++] = '/'; - // `..' may climb out of the first directory, to the root of what it - // then names: the whole tree, or a drive's. No higher. - unsigned long floor = at; - if (blen > 1 && separator(g_folded[0])) floor = 1; - else if (blen > 3 && g_folded[1] == ':' && separator(g_folded[2])) floor = 3; - for (const char* p = path; *p;) { - const char* s = p; - while (*p && !separator(*p)) ++p; - const unsigned long n = static_cast(p - s); - while (separator(*p)) ++p; - if (n == 0 || (n == 1 && s[0] == '.')) continue; - if (n == 2 && s[0] == '.' && s[1] == '.') { - if (at <= floor) return false; - do --at; while (at > floor && !separator(g_folded[at - 1])); - continue; - } - if (at && !separator(g_folded[at - 1])) g_folded[at++] = '/'; - if (at + n >= sizeof g_folded) return false; - for (unsigned long i = 0; i < n; ++i) g_folded[at++] = s[i]; + base[blen] = 0; + if (root_length(base)) { + // The first directory's own name is folded too, then the relative + // name beneath it; `..' may climb to the root of what it names. + if (!fold(base)) return false; + while (g_folded[at]) ++at; + floor = root_length(g_folded); + } else { + // A first directory with no root: `..' may not climb out of it. + while (at < blen) { g_folded[at] = base[at]; ++at; } + if (!separator(g_folded[at - 1])) g_folded[at++] = '/'; + floor = at; } - g_folded[at] = 0; - name = g_folded; } + for (const char* p = rest; *p;) { + const char* s = p; + while (*p && !separator(*p)) ++p; + const unsigned long n = static_cast(p - s); + while (separator(*p)) ++p; + if (n == 0 || (n == 1 && s[0] == '.')) continue; + if (n == 2 && s[0] == '.' && s[1] == '.') { + if (at <= floor) return false; + do --at; while (at > floor && !separator(g_folded[at - 1])); + continue; + } + if (at > floor && !separator(g_folded[at - 1])) g_folded[at++] = '/'; + if (at + n + 1 >= sizeof g_folded) return false; + for (unsigned long i = 0; i < n; ++i) g_folded[at++] = s[i]; + } + if (at > floor && separator(g_folded[at - 1])) --at; + g_folded[at] = 0; + return true; +} + +bool locate(const char* path, kal_dir& dir, const char*& rest) { + if (!fold(path)) return false; + const char* name = g_folded; unsigned long best = 0; bool found = false; for (kal_uintptr i = 0; i < kal_fs_preopen_count(); ++i) { diff --git a/tools/mcpp.toml b/tools/mcpp.toml index 1130906..e93a0cc 100644 --- a/tools/mcpp.toml +++ b/tools/mcpp.toml @@ -1,7 +1,7 @@ [package] namespace = "mcpplibs" name = "openkal-tools" -version = "0.6.3" +version = "0.6.4" description = "okrun, which runs an ok image on this system, and okld, the format's tool on a build machine (check, note, sign, inspect)." license = "Apache-2.0" authors = ["mcpplibs"] From 3901b2eca88993282967448d96d571073d304552 Mon Sep 17 00:00:00 2001 From: Sunrisepeak Date: Sun, 15 Nov 2026 19:13:57 +0900 Subject: [PATCH 2/2] release binaries: mcpp 2026.11.15.1, which openkal-platform 0.28.0 requires --- .github/workflows/release-binaries.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release-binaries.yml b/.github/workflows/release-binaries.yml index 294d7b6..2698d3f 100644 --- a/.github/workflows/release-binaries.yml +++ b/.github/workflows/release-binaries.yml @@ -39,7 +39,9 @@ env: MCPP_SOURCE_REF: ${{ github.event.inputs.mcpp_ref || vars.MCPP_SOURCE_REF || '' }} # 2026.11.10.1: openkal-run binds the interfaces its implementation provides. # mcpp_ref supplies the candidate until this release is installable. - MCPP_VERSION: 2026.11.13.1 + # 2026.11.15.1: openkal-platform 0.28.0, the default platform below, requires + # 2026.11.14.1 or later. + MCPP_VERSION: 2026.11.15.1 # The platform whose hosted arrangement the programs are built over, named by # the dispatch beside the tag: a tag's tools pin exact implementations, and the # platform is the one whose version group holds them (0.1.4: 0.18.0; 0.1.5: